"Fossies" - the Fresh Open Source Software Archive

Member "zorp-7.0.4/pylib/Zorp/Subnet.py" (28 Oct 2019, 13520 Bytes) of package /linux/privat/zorp-7.0.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "Subnet.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 7.0.1_vs_7.0.2.

    1 ############################################################################
    2 ##
    3 ## Copyright (c) 2000-2015 BalaBit IT Ltd, Budapest, Hungary
    4 ## Copyright (c) 2015-2018 BalaSys IT Ltd, Budapest, Hungary
    5 ##
    6 ##
    7 ## This program is free software; you can redistribute it and/or modify
    8 ## it under the terms of the GNU General Public License as published by
    9 ## the Free Software Foundation; either version 2 of the License, or
   10 ## (at your option) any later version.
   11 ##
   12 ## This program is distributed in the hope that it will be useful,
   13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
   14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15 ## GNU General Public License for more details.
   16 ##
   17 ## You should have received a copy of the GNU General Public License along
   18 ## with this program; if not, write to the Free Software Foundation, Inc.,
   19 ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20 ##
   21 ############################################################################
   22 
   23 """
   24 <module maturity="stable">
   25   <summary>
   26     Module defining interface to address domains.
   27   </summary>
   28   <description>
   29     <para>
   30       This module implements the Subnet classes, which encapsulate a set of physical addresses.
   31     </para>
   32   </description>
   33 </module>
   34 """
   35 
   36 from Zorp import *
   37 from string import split, atoi
   38 from socket import htonl, ntohl, inet_ntoa, inet_aton, inet_pton, inet_ntop, ntohs
   39 import socket
   40 import struct
   41 from netaddr import IPNetwork, IPRange
   42 
   43 def packed_1operand(a, f):
   44     """<function internal="yes">apply second argument to each character of the packed string 'a', converted to int</function>"""
   45     return map(lambda x: chr(f(ord(x)) & 0xff), a)
   46 
   47 def packed_2operand(a, b, f):
   48     """<function internal="yes">apply the third argument to each character in both first and second arguments</function>"""
   49     return "".join(map(lambda t: chr(f(ord(t[0]), ord(t[1]))), zip(a, b)))
   50 
   51 def packed_mask(addr, mask):
   52     """
   53     <function internal="yes"/>
   54     """
   55     return packed_2operand(addr, mask, lambda a, b: a & b)
   56 
   57 class Subnet(object):
   58     """
   59     <class internal="yes"/>
   60     """
   61     def __init__(self):
   62         """
   63         <method internal="yes"/>
   64         """
   65         pass
   66 
   67     @staticmethod
   68     def create(addr):
   69         """
   70         <method internal="yes">
   71         Factory function for InetSubnet and Inet6Subnet instances -- guess
   72         based on the string whether or not the subnet is IPv6 or IPv4.
   73         </method>
   74         """
   75         if ':' in addr:
   76             return Inet6Subnet(addr)
   77         elif '.' in addr:
   78             return InetSubnet(addr)
   79 
   80 class InetSubnet(Subnet):
   81     """
   82           <class>
   83             <summary>Class representing IPv4 address ranges.</summary>
   84           </class>
   85     """
   86     def __init__(self, addr):
   87         """
   88                <method>
   89                  <summary>Constructor to initialize an InetSubnet instance</summary>
   90                  <description>
   91                    <para>
   92                      A class representing Internet (IPv4) addresses, and IP segments.
   93                      The address is represented in the <parameter>XXX.XXX.XXX.XXX/M</parameter> format, where <parameter>XXX.XXX.XXX.XXX</parameter>
   94                      is the network address, and <parameter>M</parameter> specifies the number of ones (1) in the netmask.
   95                    </para>
   96                  </description>
   97                  <metainfo>
   98                    <arguments>
   99                      <argument maturity="stable">
  100                        <name>addr</name>
  101                        <type> <string/> </type>
  102                        <description>
  103                          The string representation of an address, optionally with a subnet prefix length.
  104                        </description>
  105                      </argument>
  106                    </arguments>
  107                  </metainfo>
  108                </method>
  109         """
  110         super(InetSubnet, self).__init__()
  111         ip_network = IPNetwork(addr)
  112         self.ip_range = IPRange(ip_network[0], ip_network[-1])
  113         parts = split(addr,'/')
  114         try:
  115             self.mask_bits = atoi(parts[1])
  116         except IndexError:
  117             self.mask_bits = 32
  118         self.mask = struct.pack(">I", ((1 << self.mask_bits) - 1) << (32 - self.mask_bits))
  119         self.ip = inet_aton(parts[0])
  120 
  121     def __str__(self):
  122         """
  123         <method internal="yes">
  124           <summary>Function returning the string representation of this instance.</summary>
  125         </method>
  126         """
  127         return "%s/%u" % (inet_ntoa(self.ip), self.mask_bits)
  128 
  129     def contains(self, other):
  130         """
  131         <method internal="yes">
  132           <summary>Checks if an address or subnet is contained within the subnet</summary>
  133           <description><parameter>other</parameter> may be an InetSubnet or a SockAddrInet.</description>
  134         </method>
  135         """
  136         if isinstance(other, InetSubnet):
  137             return (other.mask_bits >= self.mask_bits) and (packed_mask(other.addr_packed(), self.netmask_packed()) == self.addr_packed())
  138         else:
  139             try:
  140                 return ((other.ip & self.netmask_int()) == self.addr_int())
  141             except:
  142                 return False
  143 
  144     def getHostAddr(self, addr):
  145         """
  146         <method internal="yes">
  147           <summary>Masks out the subnet part of <parameter>addr</parameter>.</summary>
  148         </method>
  149         """
  150         return addr.ip & ~self.netmask_int()
  151 
  152     def mapHostAddr(self, addr):
  153         """
  154         <method internal="yes">
  155           <summary>Maps an <parameter>address</parameter> to the subnet.</summary>
  156           <description><parameter>address</parameter> is a 'host address', containing only the host specific part of the address, without the subnet part. This address will be mapped to this InetSubnet.</description>
  157         </method>
  158         """
  159         return self.addr_int() | (addr & ~self.netmask_int())
  160 
  161     def addr_packed(self):
  162         """
  163         <method internal="yes">
  164           <summary>Function returning the address packed into a string of 4 characters.</summary>
  165           <description> Uses the same representation as Python's socket.inet_pton. </description>
  166         </method>
  167         """
  168         return self.ip
  169 
  170     def addr_str(self):
  171         """
  172         <method internal="yes">
  173           <summary>Function returning the address as a string.</summary>
  174           <description> Uses the same family specific representation as Python's socket.inet_ntop. </description>
  175         </method>
  176         """
  177         return inet_ntop(socket.AF_INET, self.ip)
  178 
  179     def addr_int(self):
  180         """
  181         <method internal="yes">
  182           <summary>Function returning the address as a 32-bit integer.</summary>
  183         </method>
  184         """
  185         return struct.unpack("I", self.ip)[0]
  186 
  187     def broadcast(self):
  188         """
  189         <method internal="yes"/>
  190         """
  191         if self.mask_bits == 0:
  192             return self.addr_int()
  193 
  194         return htonl(ntohl(self.addr_int()) | (0x7fffffff >> (self.mask_bits - 1)))
  195 
  196     def network(self):
  197         """
  198         <method internal="yes"/>
  199         """
  200         return self.addr_int() & self.netmask_int()
  201 
  202     def netmask_int(self):
  203         """
  204         <method internal="yes"/>
  205         """
  206         return struct.unpack("I", self.mask)[0]
  207 
  208     def netmask_bits(self):
  209         """
  210         <method internal="yes"/>
  211         """
  212         return self.mask_bits
  213 
  214     def netmask_packed(self):
  215         """
  216         <method internal="yes">
  217           <summary>Function returning the netmask packed into a string of 4 characters.</summary>
  218           <description> Uses the same representation as Python's socket.inet_pton. </description>
  219         </method>
  220         """
  221         return self.mask
  222 
  223     def get_family(self):
  224         """
  225         <method internal="yes"/>
  226         """
  227         return socket.AF_INET
  228 
  229 class Inet6Subnet(Subnet):
  230     """
  231           <class>
  232             <summary>Class representing IPv6 address ranges.</summary>
  233           </class>
  234     """
  235     def __init__(self, addr):
  236         """
  237                 <method>
  238                   <summary>Constructor to initialize an InetSubnet instance</summary>
  239                   <description>
  240                     <para>
  241                       A class representing Internet (IPv4) addresses, and IP segments.
  242                       The address is represented in the <parameter>XXX.XXX.XXX.XXX/M</parameter> format, where <parameter>XXX.XXX.XXX.XXX</parameter>
  243                       is the network address, and <parameter>M</parameter> specifies the number of ones (1) in the netmask.
  244                     </para>
  245                   </description>
  246                   <metainfo>
  247                     <arguments>
  248                       <argument maturity="stable">
  249                         <name>addr</name>
  250                         <type> <string/> </type>
  251                         <description>
  252                           The string representation of an address, optionally with a subnet prefix length.
  253                         </description>
  254                       </argument>
  255                     </arguments>
  256                   </metainfo>
  257                 </method>
  258         """
  259         def calculate_mask(bits):
  260             ret = ""
  261             while bits > 0:
  262                 n = min(bits, 8)
  263                 v = chr(((1 << n) - 1) << (8 - n))
  264                 ret += v
  265                 bits = bits - n
  266 
  267             return ret.ljust(16, chr(0))
  268 
  269         super(Inet6Subnet, self).__init__()
  270         ip_network = IPNetwork(addr)
  271         self.ip_range = IPRange(ip_network[0], ip_network[-1])
  272 
  273         parts = split(addr, '/')
  274 
  275         if len(parts) == 2:
  276             self.mask_bits = atoi(parts[1])
  277         else:
  278             self.mask_bits = 128
  279 
  280         self.mask = calculate_mask(self.mask_bits)
  281         self.ip = packed_mask(inet_pton(socket.AF_INET6, parts[0]), self.mask)
  282 
  283     def __str__(self):
  284         """
  285         <method internal="yes">
  286           <summary>Function returning the string representation of this instance.</summary>
  287         </method>
  288         """
  289         return "%s/%u" % (inet_ntop(socket.AF_INET6, self.ip), self.mask_bits)
  290 
  291     def getHostAddr(self, addr):
  292         """
  293         <method internal="yes">
  294           <summary>Masks out the subnet part of <parameter>addr</parameter>.</summary>
  295         </method>
  296         """
  297         return packed_mask(addr.pack(), packed_1operand(self.netmask_packed(), lambda x: ~x))
  298 
  299     def mapHostAddr(self, addr):
  300         """
  301         <method internal="yes">
  302           <summary>Maps an <parameter>address</parameter> to the subnet.</summary>
  303           <description><parameter>address</parameter> is a 'host address', containing only the host specific part of the address, without the subnet part. This address will be mapped to this Inet6Subnet.</description>
  304         </method>
  305         """
  306         return struct.unpack("8H", packed_2operand(self.addr_packed(), packed_2operand(addr, packed_1operand(self.netmask_packed(), lambda x: ~x), lambda a, b: a & b), lambda a, b: a | b))
  307 
  308     def addr_int(self):
  309         """
  310         <method internal="yes">
  311           <summary>Function returning the address as a tuple of 8 16-bit integers.</summary>
  312         </method>
  313         """
  314         return struct.unpack("8H", self.ip)
  315 
  316     def addr_str(self):
  317         """
  318         <method internal="yes">
  319           <summary>Function returning the address as a string.</summary>
  320           <description> Uses the same family specific representation as Python's socket.inet_ntop. </description>
  321         </method>
  322         """
  323         return inet_ntop(socket.AF_INET6, self.ip)
  324 
  325     def addr_packed(self):
  326         """
  327         <method internal="yes">
  328           <summary>Function returning the address packed into a string of 16 characters.</summary>
  329           <description> Uses the same representation as Python's socket.inet_pton. </description>
  330         </method>
  331         """
  332         return self.ip
  333 
  334     def netmask_packed(self):
  335         """
  336         <method internal="yes">
  337           <summary>Function returning the netmask packed into a string of 16 characters.</summary>
  338           <description> Uses the same representation as Python's socket.inet_pton. </description>
  339         </method>
  340         """
  341         return self.mask
  342 
  343     def netmask_bits(self):
  344         """
  345         <method internal="yes">
  346           <summary>Return the subnet prefix length in bits.</summary>
  347           <description>Equals to the number of 1s in the base-2 representation of the netmask.</description>
  348         </method>
  349         """
  350         return self.mask_bits
  351 
  352     def netmask_int(self):
  353         """
  354         <method internal="yes">
  355           <summary>Function returning the netmask as a tuple of 8 16-bit integers.</summary>
  356         </method>
  357         """
  358         return struct.unpack("8H", self.mask)
  359 
  360     def contains(self, other):
  361         """
  362         <method internal="yes">
  363           <summary>Checks if an address or subnet is contained within the subnet</summary>
  364           <description><parameter>other</parameter> may be an Inet6Subnet or a SockAddrInet6.</description>
  365         </method>
  366         """
  367         if isinstance(other, Inet6Subnet):
  368             return ((other.mask_bits >= self.mask_bits) & (packed_mask(other.ip, self.mask_bits) == self.ip))
  369         else:
  370             try:
  371                 return (packed_mask(other.pack(), self.netmask_packed()) == self.ip)
  372             except:
  373                 return False
  374 
  375     def get_family(self):
  376         """
  377         <method internal="yes"/>
  378         """
  379         return socket.AF_INET6