From 9bfd610230b027c1f8700e2650dba9c9c26fa57c Mon Sep 17 00:00:00 2001 From: Ebben Aries Date: Mon, 22 Feb 2016 17:45:18 -0700 Subject: [PATCH] change hard coding of AF_UNSPEC to user-defined address-families per repository Some environments that return AAAA records for their IMAP servers can pose problems for clients that do not have end-to-end IPv6 connectivity for a number of reasons (e.g. policy, lack of full routing, security, etc..) Even with a fallback mechanism in place, you can still arrive at IMAP implementations that could prevent authentication from unknown IPv6 space. This in itself is not enough to fallback to IPv4 since there is an actual connection on that socket. This change is for introducing a user-defined value: [Repository imap-remote] ipv6 = no to create a preference per repository on which AF to connect to the remote server on ipv6 = yes (AF_INET6) ipv6 = no (AF_INET) unspecified = default Signed-off-by: Ebben Aries Signed-off-by: Nicolas Sebrecht --- offlineimap/imaplibutil.py | 8 +++++++- offlineimap/imapserver.py | 10 ++++++++++ offlineimap/repository/IMAP.py | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/offlineimap/imaplibutil.py b/offlineimap/imaplibutil.py index 952404a..9b1095b 100644 --- a/offlineimap/imaplibutil.py +++ b/offlineimap/imaplibutil.py @@ -74,7 +74,7 @@ class UsefulIMAPMixIn(object): """open_socket() Open socket choosing first address family available.""" msg = (-1, 'could not open socket') - for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM): + for res in socket.getaddrinfo(self.host, self.port, self.af, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res try: # use socket of our own, possiblly socksified socket. @@ -175,6 +175,9 @@ class WrappedIMAP4_SSL(UsefulIMAPMixIn, IMAP4_SSL): """Improved version of imaplib.IMAP4_SSL overriding select().""" def __init__(self, *args, **kwargs): + if "af" in kwargs: + self.af = kwargs['af'] + del kwargs['af'] if "use_socket" in kwargs: self.socket = kwargs['use_socket'] del kwargs['use_socket'] @@ -209,6 +212,9 @@ class WrappedIMAP4(UsefulIMAPMixIn, IMAP4): """Improved version of imaplib.IMAP4 overriding select().""" def __init__(self, *args, **kwargs): + if "af" in kwargs: + self.af = kwargs['af'] + del kwargs['af'] if "use_socket" in kwargs: self.socket = kwargs['use_socket'] del kwargs['use_socket'] diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py index cbe8d23..a604993 100644 --- a/offlineimap/imapserver.py +++ b/offlineimap/imapserver.py @@ -23,6 +23,7 @@ import base64 import json import urllib +import socket import time import errno from sys import exc_info @@ -80,6 +81,13 @@ class IMAPServer: self.goodpassword = None self.usessl = repos.getssl() + self.useipv6 = repos.getipv6() + if self.useipv6 == True: + self.af = socket.AF_INET6 + elif self.useipv6 == False: + self.af = socket.AF_INET + else: + self.af = socket.AF_UNSPEC self.hostname = \ None if self.preauth_tunnel else repos.gethost() self.port = repos.getport() @@ -487,6 +495,7 @@ class IMAPServer: fingerprint=self.fingerprint, use_socket=self.proxied_socket, tls_level=self.tlslevel, + af=self.af, ) else: self.ui.connecting(self.hostname, self.port) @@ -494,6 +503,7 @@ class IMAPServer: self.hostname, self.port, timeout=socket.getdefaulttimeout(), use_socket=self.proxied_socket, + af=self.af, ) if not self.preauth_tunnel: diff --git a/offlineimap/repository/IMAP.py b/offlineimap/repository/IMAP.py index 7a2a98c..60d5a08 100644 --- a/offlineimap/repository/IMAP.py +++ b/offlineimap/repository/IMAP.py @@ -194,6 +194,9 @@ class IMAPRepository(BaseRepository): return self.getconfint('remoteport', None) + def getipv6(self): + return self.getconfboolean('ipv6', None) + def getssl(self): return self.getconfboolean('ssl', 1)