def parse_subnetport(s): if s.count(':') > 1: rx = r'(?:\[?([\w\:]+)(?:/(\d+))?]?)(?::(\d+)(?:-(\d+))?)?$' else: rx = r'([\w\.\-]+)(?:/(\d+))?(?::(\d+)(?:-(\d+))?)?$' m = re.match(rx, s) if not m: raise Fatal('%r is not a valid address/mask:port format' % s) # Ports range from fport to lport. If only one port is specified, # fport is defined and lport is None. # # cidr is the mask defined with the slash notation host, cidr, fport, lport = m.groups() try: addrinfo = socket.getaddrinfo(host, 0, 0, socket.SOCK_STREAM) except socket.gaierror: raise Fatal('Unable to resolve address: %s' % host) # If the address is a domain with multiple IPs and a mask is also # provided, proceed cautiously: if cidr is not None: addr_v6 = [a for a in addrinfo if a[0] == socket.AF_INET6] addr_v4 = [a for a in addrinfo if a[0] == socket.AF_INET] # Refuse to proceed if IPv4 and IPv6 addresses are present: if len(addr_v6) > 0 and len(addr_v4) > 0: raise Fatal("%s has IPv4 and IPv6 addresses, so the mask " "of /%s is not supported. Specify the IP " "addresses directly if you wish to specify " "a mask." % (host, cidr)) # Warn if a domain has multiple IPs of the same type (IPv4 vs # IPv6) and the mask is applied to all of the IPs. if len(addr_v4) > 1 or len(addr_v6) > 1: print("WARNING: %s has multiple IP addresses. The " "mask of /%s is applied to all of the addresses." % (host, cidr)) rv = [] for a in addrinfo: family, _, _, _, addr = a # Largest possible slash value we can use with this IP: max_cidr = 32 if family == socket.AF_INET else 128 if cidr is None: # if no mask, use largest mask cidr_to_use = max_cidr else: # verify user-provided mask is appropriate cidr_to_use = int(cidr) if not 0 <= cidr_to_use <= max_cidr: raise Fatal('Slash in CIDR notation (/%d) is ' 'not between 0 and %d' % (cidr_to_use, max_cidr)) rv.append((family, addr[0], cidr_to_use, int(fport or 0), int(lport or fport or 0))) return rv
def parse_ipport(s): s = str(s) if s.isdigit(): rx = r'()(\d+)$' elif ']' in s: rx = r'(?:\[([^]]+)])(?::(\d+))?$' else: rx = r'([\w\.\-]+)(?::(\d+))?$' m = re.match(rx, s) if not m: raise Fatal('%r is not a valid IP:port format' % s) host, port = m.groups() host = host or '0.0.0.0' port = int(port or 0) try: addrinfo = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) except socket.gaierror: raise Fatal('Unable to resolve address: %s' % host) if len(addrinfo) > 1: print( "WARNING: Host %s has more than one IP, only using one of them." % host) family, _, _, _, addr = min(addrinfo) # Note: addr contains (ip, port) return (family, ) + addr[:2]
def parse_subnet6(s): m = re.match(r'(?:([a-fA-F\d:]+))?(?:/(\d+))?$', s) if not m: raise Fatal('%r is not a valid IP subnet format' % s) (net, width) = m.groups() if width is None: width = 128 else: width = int(width) if width > 128: raise Fatal('*/%d is greater than the maximum of 128' % width) return (socket.AF_INET6, net, width)
def parse_subnet4(s): m = re.match(r'(\d+)(?:\.(\d+)\.(\d+)\.(\d+))?(?:/(\d+))?$', s) if not m: raise Fatal('%r is not a valid IP subnet format' % s) (a, b, c, d, width) = m.groups() (a, b, c, d) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0)) if width is None: width = 32 else: width = int(width) if a > 255 or b > 255 or c > 255 or d > 255: raise Fatal('%d.%d.%d.%d has numbers > 255' % (a, b, c, d)) if width > 32: raise Fatal('*/%d is greater than the maximum of 32' % width) return (socket.AF_INET, '%d.%d.%d.%d' % (a, b, c, d), width)
def parse_ipport4(s): s = str(s) m = re.match(r'(?:(\d+)\.(\d+)\.(\d+)\.(\d+))?(?::)?(?:(\d+))?$', s) if not m: raise Fatal('%r is not a valid IP:port format' % s) (a, b, c, d, port) = m.groups() (a, b, c, d, port) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0), int(port or 0)) if a > 255 or b > 255 or c > 255 or d > 255: raise Fatal('%d.%d.%d.%d has numbers > 255' % (a, b, c, d)) if port > 65535: raise Fatal('*:%d is greater than the maximum of 65535' % port) if a is None: a = b = c = d = 0 return ('%d.%d.%d.%d' % (a, b, c, d), port)
def parse_ipport6(s): s = str(s) m = re.match(r'(?:\[([^]]*)])?(?::)?(?:(\d+))?$', s) if not m: raise Fatal('%s is not a valid IP:port format' % s) (ip, port) = m.groups() (ip, port) = (ip or '::', int(port or 0)) return (ip, port)
def parse_subnetport(s): if s.count(':') > 1: rx = r'(?:\[?([\w\:]+)(?:/(\d+))?]?)(?::(\d+)(?:-(\d+))?)?$' else: rx = r'([\w\.\-]+)(?:/(\d+))?(?::(\d+)(?:-(\d+))?)?$' m = re.match(rx, s) if not m: raise Fatal('%r is not a valid address/mask:port format' % s) addr, width, fport, lport = m.groups() try: addrinfo = socket.getaddrinfo(addr, 0, 0, socket.SOCK_STREAM) except socket.gaierror: raise Fatal('Unable to resolve address: %s' % addr) family, _, _, _, addr = min(addrinfo) max_width = 32 if family == socket.AF_INET else 128 width = int(width or max_width) if not 0 <= width <= max_width: raise Fatal('width %d is not between 0 and %d' % (width, max_width)) return (family, addr[0], width, int(fport or 0), int(lport or fport or 0))
def parse_ipport(s): s = str(s) if s.isdigit(): rx = r'()(\d+)$' elif ']' in s: rx = r'(?:\[([^]]+)])(?::(\d+))?$' else: rx = r'([\w\.\-]+)(?::(\d+))?$' m = re.match(rx, s) if not m: raise Fatal('%r is not a valid IP:port format' % s) ip, port = m.groups() ip = ip or '0.0.0.0' port = int(port or 0) try: addrinfo = socket.getaddrinfo(ip, port, 0, socket.SOCK_STREAM) except socket.gaierror: raise Fatal('%r is not a valid IP:port format' % s) family, _, _, _, addr = min(addrinfo) return (family,) + addr[:2]
def parse_subnet_file(s): try: handle = open(s, 'r') except OSError: raise Fatal('Unable to open subnet file: %s' % s) raw_config_lines = handle.readlines() subnets = [] for line_no, line in enumerate(raw_config_lines): line = line.strip() if len(line) == 0: continue if line[0] == '#': continue subnets.append(parse_subnet(line)) return subnets