From 08d4dcbf482de3ded8ab2db870607a2d84951b8e Mon Sep 17 00:00:00 2001 From: Josh Wright Date: Sat, 31 Aug 2013 16:42:58 -0400 Subject: [PATCH 1/2] rplit the netloc to better handle ipv6 addresses --- raven/transport/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raven/transport/base.py b/raven/transport/base.py index 9b11d3391..257198af1 100644 --- a/raven/transport/base.py +++ b/raven/transport/base.py @@ -121,7 +121,7 @@ def send(self, data, headers): # silently ignore attempts to send messages without an auth header return - host, port = self._parsed_url.netloc.split(':') + host, port = self._parsed_url.netloc.rsplit(':') self._send_data(auth_header + '\n\n' + data, (host, int(port))) def compute_scope(self, url, scope): From b1a9c618584b793d1e48fde135e9fb9b83a90398 Mon Sep 17 00:00:00 2001 From: Josh Wright Date: Sun, 1 Sep 2013 09:00:49 -0400 Subject: [PATCH 2/2] Add IPv6 support for UDP transports (IPv4 is preferred) --- raven/transport/base.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/raven/transport/base.py b/raven/transport/base.py index 257198af1..12fa88fdc 100644 --- a/raven/transport/base.py +++ b/raven/transport/base.py @@ -14,7 +14,7 @@ try: # Google App Engine blacklists parts of the socket module, this will prevent # it from blowing up. - from socket import socket, AF_INET, SOCK_DGRAM, error as socket_error + from socket import socket, AF_INET, AF_INET6, SOCK_DGRAM, has_ipv6, getaddrinfo, error as socket_error has_socket = True except: has_socket = False @@ -114,6 +114,21 @@ def __init__(self, parsed_url): self.check_scheme(parsed_url) self._parsed_url = parsed_url + def _get_addr_info(self, host, port): + """ + Selects the address to connect to, based on the supplied host/port + information. This method prefers v4 addresses, and will only return + a v6 address if it's the only option. + """ + addresses = getaddrinfo(host, port) + if has_ipv6: + v6_addresses = [info for info in addresses if info[0] == AF_INET6] + v4_addresses = [info for info in addresses if info[0] == AF_INET] + if v6_addresses and not v4_addresses: + # The only time we return a v6 address is if it's the only option + return v6_addresses[0] + return addresses[0] + def send(self, data, headers): auth_header = headers.get('X-Sentry-Auth') @@ -122,7 +137,8 @@ def send(self, data, headers): return host, port = self._parsed_url.netloc.rsplit(':') - self._send_data(auth_header + '\n\n' + data, (host, int(port))) + addr_info = self._get_addr_info(host, int(port)) + self._send_data(auth_header + '\n\n' + data, addr_info) def compute_scope(self, url, scope): path_bits = url.path.rsplit('/', 1) @@ -157,10 +173,12 @@ def __init__(self, parsed_url): if not has_socket: raise ImportError('UDPTransport requires the socket module') - def _send_data(self, data, addr): + def _send_data(self, data, addr_info): udp_socket = None + af = addr_info[0] + addr = addr_info[4] try: - udp_socket = socket(AF_INET, SOCK_DGRAM) + udp_socket = socket(af, SOCK_DGRAM) udp_socket.setblocking(False) udp_socket.sendto(data, addr) except socket_error: