def is_local_device(my_ips, my_port, dev_ip, dev_port): """ Return True if the provided dev_ip and dev_port are among the IP addresses specified in my_ips and my_port respectively. To support accurate locality determination in the server-per-port deployment, when my_port is None, only IP addresses are used for determining locality (dev_port is ignored). If dev_ip is a hostname then it is first translated to an IP address before checking it against my_ips. """ candidate_ips = [] if not is_valid_ip(dev_ip) and is_valid_hostname(dev_ip): try: # get the ip for this host; use getaddrinfo so that # it works for both ipv4 and ipv6 addresses addrinfo = socket.getaddrinfo(dev_ip, dev_port) for addr in addrinfo: family = addr[0] dev_ip = addr[4][0] # get the ip-address if family == socket.AF_INET6: dev_ip = expand_ipv6(dev_ip) candidate_ips.append(dev_ip) except socket.gaierror: return False else: if is_valid_ipv6(dev_ip): dev_ip = expand_ipv6(dev_ip) candidate_ips = [dev_ip] for dev_ip in candidate_ips: if dev_ip in my_ips and (my_port is None or dev_port == my_port): return True return False
def validate_and_normalize_ip(ip): """ Return normalized ip if the ip is a valid ip. Otherwise raise ValueError Exception. The hostname is normalized to all lower case. IPv6-addresses are converted to lowercase and fully expanded. """ # first convert to lower case new_ip = ip.lower() if is_valid_ipv4(new_ip): return new_ip elif is_valid_ipv6(new_ip): return expand_ipv6(new_ip) else: raise ValueError('Invalid ip %s' % ip)
def validate_and_normalize_address(address): """ Return normalized address if the address is a valid ip or hostname. Otherwise raise ValueError Exception. The hostname is normalized to all lower case. IPv6-addresses are converted to lowercase and fully expanded. RFC1123 2.1 Host Names and Nubmers DISCUSSION This last requirement is not intended to specify the complete syntactic form for entering a dotted-decimal host number; that is considered to be a user-interface issue. For example, a dotted-decimal number must be enclosed within "[ ]" brackets for SMTP mail (see Section 5.2.17). This notation could be made universal within a host system, simplifying the syntactic checking for a dotted-decimal number. If a dotted-decimal number can be entered without such identifying delimiters, then a full syntactic check must be made, because a segment of a host domain name is now allowed to begin with a digit and could legally be entirely numeric (see Section 6.1.2.4). However, a valid host name can never have the dotted-decimal form #.#.#.#, since at least the highest-level component label will be alphabetic. """ new_address = address.lstrip('[').rstrip(']') if address.startswith('[') and address.endswith(']'): return validate_and_normalize_ip(new_address) new_address = new_address.lower() if is_valid_ipv4(new_address): return new_address elif is_valid_ipv6(new_address): return expand_ipv6(new_address) elif is_valid_hostname(new_address): return new_address else: raise ValueError('Invalid address %s' % address)
def is_local_device(my_ips, my_port, dev_ip, dev_port): """ Return True if the provided dev_ip and dev_port are among the IP addresses specified in my_ips and my_port respectively. If dev_ip is a hostname then it is first translated to an IP address before checking it against my_ips. """ if not is_valid_ip(dev_ip) and is_valid_hostname(dev_ip): try: # get the ip for this host; use getaddrinfo so that # it works for both ipv4 and ipv6 addresses addrinfo = socket.getaddrinfo(dev_ip, dev_port) for addr in addrinfo: family = addr[0] dev_ip = addr[4][0] # get the ip-address if family == socket.AF_INET6: dev_ip = expand_ipv6(dev_ip) if dev_ip in my_ips and dev_port == my_port: return True return False except socket.gaierror: return False return dev_ip in my_ips and dev_port == my_port