1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-10-08 19:34:11 +03:00
Files
openuds/server/src/uds/core/util/net.py
2018-01-18 08:32:16 +01:00

182 lines
6.2 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import re
# Test patters for networks
reCIDR = re.compile(r'^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})$')
reMask = re.compile(r'^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})netmask([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$')
re1Asterisk = re.compile(r'^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.\*$')
re2Asterisk = re.compile(r'^([0-9]{1,3})\.([0-9]{1,3})\.\*\.?\*?$')
re3Asterisk = re.compile(r'^([0-9]{1,3})\.\*\.?\*?\.?\*?$')
reRange = re.compile(r'^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})-([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$')
reHost = re.compile(r'^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$')
def ipToLong(ip):
'''
convert decimal dotted quad string to long integer
'''
try:
hexn = ''.join(["%02X" % long(i) for i in ip.split('.')])
return long(hexn, 16)
except:
return 0 # Invalid values will map to "0.0.0.0" --> 0
def longToIp(n):
'''
convert long int to dotted quad string
'''
try:
d = 1 << 24
q = []
while d > 0:
m, n = divmod(n, d)
q.append(str(m)) # As m is an integer, this works on py2 and p3 correctly
d >>= 8
return '.'.join(q)
except:
return '0.0.0.0' # Invalid values will map to "0.0.0.0"
def networksFromString(strNets, allowMultipleNetworks=True):
'''
Parses the network from strings in this forms:
- A.* (or A.*.* or A.*.*.*)
- A.B.* (or A.B.*.* )
- A.B.C.* (i.e. 192.168.0.*)
- A.B.C.D/N (i.e. 192.168.0.0/24)
- A.B.C.D netmask X.X.X.X (i.e. 192.168.0.0 netmask 255.255.255.0)
- A.B.C.D - E.F.G.D (i.e. 192-168.0.0-192.168.0.255)
- A.B.C.D
If allowMultipleNetworks is True, it allows ',' and ';' separators (and, ofc, more than 1 network)
Returns a list of networks tuples in the form [(start1, end1), (start2, end2) ...]
'''
inputString = strNets
def check(*args):
for n in args:
if int(n) < 0 or int(n) > 255:
raise Exception()
def toNum(*args):
start = 256 * 256 * 256
val = 0
for n in args:
val += start * int(n)
start >>= 8
return val
def maskFromBits(nBits):
v = 0
for n in range(nBits):
v |= 1 << (31 - n)
return v
if allowMultipleNetworks is True:
res = []
for strNet in re.split('[;,]', strNets):
if strNet != '':
res.append(networksFromString(strNet, False))
return res
strNets = strNets.replace(' ', '')
if strNets == '*':
return (0, 4294967295)
try:
# Test patterns
m = reCIDR.match(strNets)
if m is not None:
check(*m.groups())
bits = int(m.group(5))
if bits < 0 | bits > 32:
raise Exception()
val = toNum(*m.groups())
bits = maskFromBits(bits)
noBits = ~bits & 0xffffffff
return (val & bits, val | noBits)
m = reMask.match(strNets)
if m is not None:
check(*m.groups())
val = toNum(*(m.groups()[0:4]))
bits = toNum(*(m.groups()[4:8]))
noBits = ~bits & 0xffffffff
return (val & bits, val | noBits)
m = reRange.match(strNets)
if m is not None:
check(*m.groups())
val = toNum(*(m.groups()[0:4]))
val2 = toNum(*(m.groups()[4:8]))
if val2 < val:
raise Exception()
return (val, val2)
m = reHost.match(strNets)
if m is not None:
check(*m.groups())
val = toNum(*m.groups())
return (val, val)
for v in ((re1Asterisk, 3), (re2Asterisk, 2), (re3Asterisk, 1)):
m = v[0].match(strNets)
if m is not None:
check(*m.groups())
val = toNum(*(m.groups()[0:v[1] + 1]))
bits = maskFromBits(v[1] * 8)
noBits = ~bits & 0xffffffff
return (val & bits, val | noBits)
# No pattern recognized, invalid network
raise Exception()
except:
raise ValueError(inputString)
def ipInNetwork(ip, network):
if isinstance(ip, unicode) or isinstance(ip, str):
ip = ipToLong(ip)
if isinstance(network, unicode) or isinstance(network, str):
network = networksFromString(network)
for net in network:
if ip >= net[0] and ip <= net[1]:
return True
return False