Commit e72e1618 authored by Ronald Oussoren's avatar Ronald Oussoren

Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified IP...

Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified IP addresses in the proxy exception list

Patch by Scott Wilson.
parent 94eceeb8
...@@ -6,7 +6,9 @@ import io ...@@ -6,7 +6,9 @@ import io
import socket import socket
import urllib.request import urllib.request
from urllib.request import Request, OpenerDirector # The proxy bypass method imported below has logic specific to the OSX
# proxy config data structure but is testable on all platforms.
from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
# XXX # XXX
# Request # Request
...@@ -1030,6 +1032,17 @@ class HandlerTests(unittest.TestCase): ...@@ -1030,6 +1032,17 @@ class HandlerTests(unittest.TestCase):
self.assertEqual(req.get_host(), "www.python.org") self.assertEqual(req.get_host(), "www.python.org")
del os.environ['no_proxy'] del os.environ['no_proxy']
def test_proxy_no_proxy_all(self):
os.environ['no_proxy'] = '*'
o = OpenerDirector()
ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
o.add_handler(ph)
req = Request("http://www.python.org")
self.assertEqual(req.get_host(), "www.python.org")
r = o.open(req)
self.assertEqual(req.get_host(), "www.python.org")
del os.environ['no_proxy']
def test_proxy_https(self): def test_proxy_https(self):
o = OpenerDirector() o = OpenerDirector()
...@@ -1070,6 +1083,26 @@ class HandlerTests(unittest.TestCase): ...@@ -1070,6 +1083,26 @@ class HandlerTests(unittest.TestCase):
self.assertEqual(req.get_host(), "proxy.example.com:3128") self.assertEqual(req.get_host(), "proxy.example.com:3128")
self.assertEqual(req.get_header("Proxy-authorization"),"FooBar") self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
def test_osx_proxy_bypass(self):
bypass = {
'exclude_simple': False,
'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
'10.0/16']
}
# Check hosts that should trigger the proxy bypass
for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
'10.0.0.1'):
self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
'expected bypass of %s to be True' % host)
# Check hosts that should not trigger the proxy bypass
for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
'expected bypass of %s to be False' % host)
# Check the exclude_simple flag
bypass = {'exclude_simple': True, 'exceptions': []}
self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
def test_basic_auth(self, quote_char='"'): def test_basic_auth(self, quote_char='"'):
opener = OpenerDirector() opener = OpenerDirector()
password_manager = MockPasswordManager() password_manager = MockPasswordManager()
......
...@@ -2175,68 +2175,76 @@ def proxy_bypass_environment(host): ...@@ -2175,68 +2175,76 @@ def proxy_bypass_environment(host):
return 0 return 0
if sys.platform == 'darwin': # This code tests an OSX specific data structure but is testable on all
from _scproxy import _get_proxy_settings, _get_proxies # platforms
def _proxy_bypass_macosx_sysconf(host, proxy_settings):
def proxy_bypass_macosx_sysconf(host): """
""" Return True iff this host shouldn't be accessed using a proxy
Return True iff this host shouldn't be accessed using a proxy
This function uses the MacOSX framework SystemConfiguration This function uses the MacOSX framework SystemConfiguration
to fetch the proxy information. to fetch the proxy information.
"""
import re
import socket
from fnmatch import fnmatch
hostonly, port = splitport(host) proxy_settings come from _scproxy._get_proxy_settings or get mocked ie:
{ 'exclude_simple': bool,
'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16']
}
"""
import re
import socket
from fnmatch import fnmatch
def ip2num(ipAddr): hostonly, port = splitport(host)
parts = ipAddr.split('.')
parts = list(map(int, parts))
if len(parts) != 4:
parts = (parts + [0, 0, 0, 0])[:4]
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
proxy_settings = _get_proxy_settings() def ip2num(ipAddr):
parts = ipAddr.split('.')
parts = list(map(int, parts))
if len(parts) != 4:
parts = (parts + [0, 0, 0, 0])[:4]
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
# Check for simple host names: # Check for simple host names:
if '.' not in host: if '.' not in host:
if proxy_settings['exclude_simple']: if proxy_settings['exclude_simple']:
return True return True
hostIP = None hostIP = None
for value in proxy_settings.get('exceptions', ()): for value in proxy_settings.get('exceptions', ()):
# Items in the list are strings like these: *.local, 169.254/16 # Items in the list are strings like these: *.local, 169.254/16
if not value: continue if not value: continue
m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value) m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
if m is not None: if m is not None:
if hostIP is None: if hostIP is None:
try: try:
hostIP = socket.gethostbyname(hostonly) hostIP = socket.gethostbyname(hostonly)
hostIP = ip2num(hostIP) hostIP = ip2num(hostIP)
except socket.error: except socket.error:
continue continue
base = ip2num(m.group(1))
mask = m.group(2)
if mask is None:
mask = 8 * (m.group(1).count('.') + 1)
else:
mask = int(mask[1:])
mask = 32 - mask
base = ip2num(m.group(1)) if (hostIP >> mask) == (base >> mask):
mask = m.group(2) return True
if mask is None:
mask = 8 * (m.group(1).count('.') + 1)
else: elif fnmatch(host, value):
mask = int(mask[1:]) return True
mask = 32 - mask
if (hostIP >> mask) == (base >> mask): return False
return True
elif fnmatch(host, value):
return True
return False if sys.platform == 'darwin':
from _scproxy import _get_proxy_settings, _get_proxies
def proxy_bypass_macosx_sysconf(host):
proxy_settings = _get_proxy_settings()
return _proxy_bypass_macosx_sysconf(host, proxy_settings)
def getproxies_macosx_sysconf(): def getproxies_macosx_sysconf():
"""Return a dictionary of scheme -> proxy server URL mappings. """Return a dictionary of scheme -> proxy server URL mappings.
......
...@@ -197,6 +197,9 @@ Library ...@@ -197,6 +197,9 @@ Library
OSError exception when The OS had been told to ignore SIGCLD in our process OSError exception when The OS had been told to ignore SIGCLD in our process
or otherwise not wait for exiting child processes. or otherwise not wait for exiting child processes.
- Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified
IP addresses in the proxy exception list.
Extensions Extensions
---------- ----------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment