GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Support CIDR no_proxy entries · python/cpython@a6e2fa6

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • Doc/library
    • urllib.request.rst
  • Lib
    • test
      • test_urllib.py
    • urllib
      • request.py
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎Doc/library/urllib.request.rst‎

Copy file name to clipboardExpand all lines: Doc/library/urllib.request.rst
+3-2Lines changed: 3 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,9 @@ The following classes are provided:
360360

361361
The :envvar:`no_proxy` environment variable can be used to specify hosts
362362
which shouldn't be reached via proxy; if set, it should be a comma-separated
363-
list of hostname suffixes, optionally with ``:port`` appended, for example
364-
``cern.ch,ncsa.uiuc.edu,some.host:8080``.
363+
list of hostname suffixes, optionally with ``:port`` appended, and IP
364+
address CIDR ranges, for example
365+
``cern.ch,ncsa.uiuc.edu,some.host:8080,192.168.0.0/16``.
365366

366367
.. note::
367368

Collapse file

‎Lib/test/test_urllib.py‎

Copy file name to clipboardExpand all lines: Lib/test/test_urllib.py
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,28 @@ def test_proxy_bypass_environment_host_match(self):
245245
self.assertFalse(bypass('newdomain.com')) # no port
246246
self.assertFalse(bypass('newdomain.com:1235')) # wrong port
247247

248+
def test_proxy_bypass_environment_cidr_match(self):
249+
bypass = urllib.request.proxy_bypass_environment
250+
self.env.set('NO_PROXY',
251+
'192.168.0.0/16, 2001:db8::/32, 172.16.1.1/24')
252+
self.assertTrue(bypass('192.168.1.1'))
253+
self.assertTrue(bypass('192.168.1.1:1234'))
254+
self.assertTrue(bypass('2001:db8::1'))
255+
self.assertTrue(bypass('[2001:db8::1]:1234'))
256+
self.assertTrue(bypass('172.16.1.255'))
257+
self.assertFalse(bypass('192.169.1.1'))
258+
self.assertFalse(bypass('2001:db9::1'))
259+
self.assertFalse(bypass('172.16.2.1'))
260+
self.assertFalse(bypass('python.org'))
261+
262+
def test_proxy_bypass_environment_invalid_cidr(self):
263+
bypass = urllib.request.proxy_bypass_environment
264+
self.env.set('NO_PROXY',
265+
'192.168.0.0/33, 2001:db8::/129, anotherdomain.com')
266+
self.assertFalse(bypass('192.168.1.1'))
267+
self.assertFalse(bypass('2001:db8::1'))
268+
self.assertTrue(bypass('anotherdomain.com'))
269+
248270
def test_proxy_bypass_environment_always_match(self):
249271
bypass = urllib.request.proxy_bypass_environment
250272
self.env.set('NO_PROXY', '*')
Collapse file

‎Lib/urllib/request.py‎

Copy file name to clipboardExpand all lines: Lib/urllib/request.py
+29-2Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,7 +1912,8 @@ def proxy_bypass_environment(host, proxies=None):
19121912
"""Test if proxies should not be used for a particular host.
19131913
19141914
Checks the proxy dict for the value of no_proxy, which should
1915-
be a list of comma separated DNS suffixes, or '*' for all hosts.
1915+
be a list of comma separated DNS suffixes, IP address CIDR ranges,
1916+
or '*' for all hosts.
19161917
19171918
"""
19181919
if proxies is None:
@@ -1928,14 +1929,40 @@ def proxy_bypass_environment(host, proxies=None):
19281929
host = host.lower()
19291930
# strip port off host
19301931
hostonly, port = _splitport(host)
1931-
# check if the host ends with any of the DNS suffixes
1932+
host_ip = None
1933+
checked_host_ip = False
1934+
# for every entry in no_proxy...
19321935
for name in no_proxy.split(','):
19331936
name = name.strip()
19341937
if name:
19351938
name = name.lstrip('.') # ignore leading dots
19361939
name = name.lower()
1940+
1941+
# check for exact match
19371942
if hostonly == name or host == name:
19381943
return True
1944+
1945+
# check if the IP is within CIDR range
1946+
if '/' in name:
1947+
if not checked_host_ip:
1948+
from ipaddress import ip_address
1949+
for candidate in (hostonly, host):
1950+
candidate = candidate.strip('[]')
1951+
try:
1952+
host_ip = ip_address(candidate)
1953+
break
1954+
except ValueError:
1955+
pass
1956+
checked_host_ip = True
1957+
if host_ip is not None:
1958+
from ipaddress import ip_network
1959+
try:
1960+
if host_ip in ip_network(name, strict=False):
1961+
return True
1962+
except ValueError:
1963+
pass
1964+
1965+
# check if the host ends with any of the DNS suffixes
19391966
name = '.' + name
19401967
if hostonly.endswith(name) or host.endswith(name):
19411968
return True

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.