Download - Socket Programmierung mit IPv6
Socket-Programmierung mit IPv6
Christian Kauhaus
gocept gmbh & co. kg
PyCon DE Leipzig, 7. Oktober 2011
Socket-Programmierung mit IPv6 · Christian Kauhaus · 1
Übersicht
..1 Einleitung
..2 Aktive Socketverbindungen (Clients)
..3 Passive Socketverbindungen (Server)
..4 IP-Adressen
..5 Zusammenfassung
Socket-Programmierung mit IPv6 · Christian Kauhaus · 2
EinleitungAnti-Motivation
Brauche ich IPv6-Socketprogrammierung?In der Regel nicht.
IPv6-Support umsonst durch:• Bibliotheken (urllib etc.)• Frameworks (Twisted etc.)• vorgelagerter Server (nginx etc.)
Aber wenn ich es doch mal brauche..?
Socket-Programmierung mit IPv6 · Christian Kauhaus · 3
Durchgehendes BeispielChristians DATE-Protokoll
Simples Protokoll, um das aktuelle Datum abzufragen• Client sagt: DATE• Server sagt: DATE YYYY-MM-DD
class DateHandler(socketserver.BaseRequestHandler):
def handle(self):if self.request.recv(1024).strip() == 'DATE':
self.request.send('DATE %s\r\n' %datetime.date.today())
else:self.request.send('ERROR\r\n')
class DateSocketServer(socketserver.ThreadingMixIn,socketserver.TCPServer):
allow_reuse_address = True
Socket-Programmierung mit IPv6 · Christian Kauhaus · 4
Aktive SocketverbindungenDate-Client nur mit IPv4
»Old school« Implementierung
class DateClient(object):
def __init__(self, hostname, port=9000, timeout=15):address = socket.gethostbyname(hostname)self.socket = socket.socket(socket.AF_INET,
socket.SOCK_STREAM, 0)self.socket.settimeout(timeout)self.socket.connect((address, port))
def query(self):self.socket.send('DATE\r\n')response = self.socket.recv(1024)print 'C: response is %s' % response.strip()
Socket-Programmierung mit IPv6 · Christian Kauhaus · 5
Verhalten des Single-Stack-ClientsIgnoriert IPv6-Adressen komplett
Shell-Demo:• test.local löst zu IPv4- und IPv6-Adressen auf• server6 test.local lauscht auf allen Adressen• client4 test.local verbindet sich über IPv4
Socket-Programmierung mit IPv6 · Christian Kauhaus · 6
Programmiertip 1: getaddrinfo()Schnittstelle zwischen Sockets und Außenwelt
getaddrinfo() nutzen. Immer!
• Namensauflösung• Validierung der Eingabe• Filtern nach Socket-Typen• address family, socket type, IP protocol
Anti-Patternaddress = socket.gethostbyname(host)
.
.
.
GAI
Socket-Programmierung mit IPv6 · Christian Kauhaus · 7
Programmiertip 1: getaddrinfo()Schnittstelle zwischen Sockets und Außenwelt
Beispiel:>>> socket.getaddrinfo('www.python.org', 80, socket.AF_UNSPEC)[(10, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0)),(10, 2, 17, '', ('2001:888:2000:d::a2', 80, 0, 0)),(10, 3, 0, '', ('2001:888:2000:d::a2', 80, 0, 0)),(2, 1, 6, '', ('82.94.164.162', 80)),(2, 2, 17, '', ('82.94.164.162', 80)),(2, 3, 0, '', ('82.94.164.162', 80))]
• address family, z. B. 10 = AF_INET6• socket type, z. B. 1 = SOCK_STREAM• IP protocol, z. B. 6 = SOL_TCP• socket address: host, port, flow id, scope
Socket-Programmierung mit IPv6 · Christian Kauhaus · 8
Programmiertip 2: 1:n-AuflösungEin Host, mehrere Adressen
Einem Hostnamen sind mehrere Adressen zugeordnet.
• IPv4- und IPv6-Adresse• mehrere IPv6-Adressen für Multi-Homed Hosts• getaddrinfo() gibt eine Liste zurück• Reihenfolge nach absteigender Priorität
Anti-Patternres = socket.getaddrinfo(...)sock.connect(res[0][4])
.
.
.
1:n
Socket-Programmierung mit IPv6 · Christian Kauhaus · 9
Programmiertip 3: Connect-LoopAlle Adressen durchprobieren
Abbruch nur, wenn keine Adresse erreichbar ist.
• Verbindung kommt zustande: fertig• Fehler, aber noch Adressen übrig: weitermachen• Fehler bei letzter Adresse: letzten Fehler eskalieren
Anti-Patterntry:
sock.connect(sockaddr)except socket.error as e:
sys.exit(1)
.
.
.
Loop
Socket-Programmierung mit IPv6 · Christian Kauhaus · 10
Dual-Stack-CodeDate-Client mit IPv4 und IPv6
class DateClient(object):
def __init__(self, hostname, port=9000, timeout=15):self.socket = Noneself.connect(hostname, port, timeout)
def query(self):self.socket.send(b'DATE\r\n')response = self.socket.recv(1024).decode()print('C: response is {}'.format(response.strip()))
Socket-Programmierung mit IPv6 · Christian Kauhaus · 11
Dual-Stack-CodeDate-Client mit IPv4 und IPv6 (Fortsetzung)
def connect(self, host, port, timeout):exception = Nonefor (af, socktype, proto, cname, sockaddr
) in socket.getaddrinfo(host, port, socket.AF_UNSPEC,socket.SOCK_STREAM, 0):
try:self.socket = socket.socket(af, socktype, proto)self.socket.settimeout(timeout)self.socket.connect(sockaddr)return
except socket.error as e:exception = e
raise exception
.
.
.
GAI
.
.
1:n
.
.
Loop
Socket-Programmierung mit IPv6 · Christian Kauhaus · 12
Verhalten des Dual-Stack-ClientsVerbindung mit IPv6
Shell-Demo:• test.local löst zu IPv4- und IPv6-Adressen auf• server6 test.local lauscht auf allen Adressen• client6 test.local verbindet sich über IPv6• server4 test.local lauscht nur auf IPv4-Adresse• client6 test.local probiert IPv6 und verbindet sich dann
über IPv4
Socket-Programmierung mit IPv6 · Christian Kauhaus · 13
Passive SocketverbindungenDate-Server mit IPv4
class DateServer(object):
def __init__(self, listen_addresses, port):self.listen_addresses = listen_addressesself.port = portself.threads = list(self.create_threads())
def create_threads(self):for host_or_address in self.listen_addresses:
address = socket.gethostbyname(host_or_address)server = DateSocketServer((address, self.port),
DateHandler)yield threading.Thread(target=server.serve_forever)
def run(self):for thread in self.threads:
thread.start()for thread in self.threads:
thread.join()
Socket-Programmierung mit IPv6 · Christian Kauhaus · 14
Verhalten des Single-Stack-ServersVerbindung mit IPv4
Shell-Demo:• test.local löst zu IPv4- und IPv6-Adressen auf• server4 test.local lauscht nur auf IPv4-Adresse• client6 test.local verbindet sich über IPv4
Socket-Programmierung mit IPv6 · Christian Kauhaus · 15
Dual-Stack-CodeDate-Server mit IPv4 und IPv6
create_threads() muss mehrere Server pro Listen-Itemerzeugen:
class DateServer(object):
def __init__(self, listen_addresses, port):self.listen_addresses = listen_addressesself.port = portself.threads = list(self.create_threads())
def create_threads(self):servers = []for host_or_address in self.listen_addresses:
servers += self.connect_servers(host_or_address)for server in servers:
yield threading.Thread(target=server.serve_forever)
Socket-Programmierung mit IPv6 · Christian Kauhaus · 16
Dual-Stack-CodeDate-Server mit IPv4 und IPv6 (Fortsetzung)
def connect_servers(self, host_or_address):servers = []exception = Nonefor (af, socktype, proto, cname, sockaddr
) in socket.getaddrinfo(host_or_address, self.port, socket.AF_UNSPEC,socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
try:servers.append(DateSocketServer(
sockaddr[0:2], DateHandler, True, af))except socket.error as e:
exception = econtinue
if not servers:raise exception
return servers
.
.
.
GAI
.
.
1:n
.
.
Loop
Socket-Programmierung mit IPv6 · Christian Kauhaus · 17
Dual-Stack-CodeDate-Server mit IPv4 und IPv6 (Fortsetzung)
TCPServer erweitern, um address_family im Konstruktorfallweise zu setzen:
class DateSocketServer(socketserver.ThreadingMixIn,socketserver.TCPServer):
allow_reuse_address = True
def __init__(self, server_address, RequestHandlerClass,bind_and_activate=True,address_family=socket.AF_INET):
self.address_family = address_familysuper().__init__(server_address, RequestHandlerClass,
bind_and_activate)
Socket-Programmierung mit IPv6 · Christian Kauhaus · 18
Verhalten des Dual-Stack-ServersVerbindung mit IPv6 und IPv4
Shell-Demo:• test.local löst zu IPv4- und IPv6-Adressen auf• server6 test.local lauscht auf allen Adressen• client6 test.local verbindet sich über IPv6• client4 test.local verbindet sich über IPv4
Socket-Programmierung mit IPv6 · Christian Kauhaus · 19
IP-AdressenGar nicht so simpel
IP-Adressen als Stringsentweder:
• unbehandelt durchreichen(z. B. getaddrinfo(), Datenbanken, Logging)
oder:• »richtig« parsen und manipulieren (z. B. netaddr, IPy)
Anti-Patternre.match(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', ipaddress)
Socket-Programmierung mit IPv6 · Christian Kauhaus · 20
ZusammenfassungSocket-Programmierung mit IPv6
• Sockets richtig erzeugen• getaddrinfo()• 1:n Adressauflösung• Connect-Loop
• Externe Repräsentation von IP-Adressen mit Respektbehandeln
• Dual-Stack Code schreiben! :-)
Socket-Programmierung mit IPv6 · Christian Kauhaus · 21
Vielen Dank!Fragen?
E-Mail [email protected] [email protected]
Hosting http://gocept.net/auf Jobsuche? http://gocept.com/das-unternehmen/karriere
API definition RFC 3493IPv6 porting http://owend.corp.he.net/ipv6/
Socket-Programmierung mit IPv6 · Christian Kauhaus · 22