Skip to content

Instantly share code, notes, and snippets.

@dhke
Created March 13, 2017 16:02
Show Gist options
  • Save dhke/442a2eebe34cc152247da588920b1385 to your computer and use it in GitHub Desktop.
Save dhke/442a2eebe34cc152247da588920b1385 to your computer and use it in GitHub Desktop.
little script to test getaddrinfo resolver
#! /usr/bin/env python
from __future__ import print_function
import argparse
import socket
import six
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
'-6', '--ipv6', dest='ipv6', default=None, action='store_true', help='enable IPv6-only lookups (default=both)',
)
parser.add_argument(
'--no-ipv6', dest='ipv6', action='store_false', help='disable IPv6 lookups',
)
parser.add_argument(
'-4', '--ipv4', dest='ipv4', default=None, action='store_true', help='enable IPv4-only lookups (default=both)',
)
parser.add_argument(
'--no-ipv4', dest='ipv4', action='store_false', help='disable IPv4 lookups',
)
parser.add_argument(
'-s', '--socktype', dest='socktype', nargs=1, type=six.text_type, help='socket type (stream, dgram, ...)',
)
parser.add_argument(
'-p', '--proto', '--protocol', nargs=1, dest='proto', type=six.text_type, help='protocol (udp, tcp, ...)',
)
parser.add_argument('host', type=str, help='hostname to resolve')
parser.add_argument('port', nargs='?', type=str, help='port to resolve')
args = parser.parse_args()
return args
def resolve_socktype(socktype_arg):
sock = getattr(socket, 'SOCK_' + proto.upper(), None)
if not sock:
raise AttributeError('Unknown socket type: {}'.format(socktype_arg))
return sock
def print_sockaddr(sockaddr, numeric=False):
print("ip_addr= {}".format(sockaddr[0]))
if numeric:
print("port= {}".format(sockaddr[1]))
else:
try:
serv = socket.getservbyport(sockaddr[1])
print("serv= {} ({})".format(serv, sockaddr[1]))
except socket.error:
print("port= {}".format(sockaddr[1]))
if len(sockaddr) > 2:
print("scope= {}".format(sockaddr[2]))
def get_family_by_id(family):
for key in socket.__all__:
if key.startswith('AF_') and getattr(socket, key) == family:
return key
return family
def get_socktype_by_id(socktype):
for key in socket.__all__:
if key.startswith('SOCK_') and getattr(socket, key) == socktype:
return key
return socktype
def print_addr(addr, numeric=False):
family, socktype, proto, canonname, sockaddr = addr
if numeric:
print("family= {}".format(family))
print("socktype= {}".format(socktype))
else:
print("family= {} ({})".format(get_family_by_id(family), family))
print("socktype= {} ({})".format(get_socktype_by_id(socktype), socktype))
if canonname:
print("canonname= {}".format(canonname))
print_sockaddr(sockaddr)
def print_addrs(addrs):
for i, addr in enumerate(addrs):
if i:
print('')
print_addr(addr)
def main():
args = parse_args()
ipv4 = getattr(args, 'ipv4', None)
ipv6 = getattr(args, 'ipv6', None)
host = args.host
port = args.port
# defaults are a little weird:
# - when nothing is specified, you get v4 and v6
# - when one of either ipv4 or ipv6 is specified, you only get addresses of that type
# - when both are specified, you get addresses of both types
# POLA violation:
# - when you disable both v4 and v6, you (again) get all addresses
#
# Command line switches are evaluated in order, so --ipv6 --no-ipv6 gives you ipv4 addreses only.
if (ipv4 or ipv4 is None) and not ipv6:
family = socket.AF_INET
elif (ipv6 or ipv6 is None) and not ipv4:
family = socket.AF_INET6
else:
family = socket.AF_UNSPEC
if getattr(args, 'socktype', None):
socktype = resolve_socktype(args.socktype[0])
else:
socktype = 0
if getattr(args, 'proto', None):
proto = socket.getprotobyname(args.proto[0])
else:
proto = 0
addrs = socket.getaddrinfo(host, port, family, socktype, proto)
print_addrs(addrs)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment