Opened 17 years ago

Closed 4 years ago

Last modified 4 years ago

#3237 closed enhancement (wontfix)

[patch] CIDR in INTERNAL_IPS

Reported by: Jeremy Dunck <jdunck@…> Owned by: nobody
Component: Core (Other) Version:
Severity: normal Keywords: CIDR INTERNAL_IPS
Cc: Triage Stage: Design decision needed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

It'd be nice if INTERNAL_IPS could support CIDR expressions:

class CIDR_LIST(list):

def init(self, cidrs):

self.cidrs = []
try:

#http://cheeseshop.python.org/pypi/IPv4_Utils/0.35
import ipv4
for cidr in cidrs:

self.cidrs.append(ipv4.CIDR(cidr))

except ImportError:

pass

def contains(self, ip):

import ipv4
try:

for cidr in self.cidrs:

if ipv4.CIDR(ip) in cidr:

return True

except:

pass

return False


INTERNAL_IPS = CIDR_LIST([

'127.0.0.1',
'10.0.0.0/24'
])

Change History (13)

comment:1 by Jeremy Dunck <jdunck@…>, 17 years ago

code, un-hosed:

class CIDR_LIST(list):
    def __init__(self, cidrs):
        self.cidrs = []
        try:
            #http://cheeseshop.python.org/pypi/IPv4_Utils/0.35
            import ipv4
            for cidr in cidrs:
                self.cidrs.append(ipv4.CIDR(cidr))
        except ImportError:
            pass
    def __contains__(self, ip):
        import ipv4
        try:
            for cidr in self.cidrs:
                if ipv4.CIDR(ip) in cidr:
                    return True
        except:
            pass
        return False
    
INTERNAL_IPS = CIDR_LIST([
    '127.0.0.1',
    '10.0.0.0/24'
    ])

comment:2 by Simon G. <dev@…>, 17 years ago

Has patch: set
Keywords: CIDR INTERNAL_IPS added
Triage Stage: UnreviewedDesign decision needed

comment:3 by Simon G. <dev@…>, 17 years ago

Summary: CIDR in INTERNAL_IPS[patch] CIDR in INTERNAL_IPS

comment:4 by Jacob, 16 years ago

Resolution: wontfix
Status: newclosed

I don't think this is something that should be added to django proper, but you can bet your butt I'll use this code myself!

comment:5 by Kenneth Arnold, 15 years ago

Has patch: unset
Resolution: wontfix
Status: closedreopened

A simpler version (see http://www.djangosnippets.org/snippets/1380/)

from fnmatch import fnmatch
class glob_list(list):
    def __contains__(self, key):
        for elt in self:
            if fnmatch(key, elt): return True
        return False

INTERNAL_IPS = glob_list([
    '127.0.0.1',
    '18.85.*.*'
    ])

This is simple and useful enough that I'll entertain the thought of putting something like it in Django proper.

comment:6 by George Vilches, 15 years ago

If the first one didn't belong in Django (which uses standard CIDR syntax accepted by sysadmins everywhere), this one definitely shouldn't be part of Django, with non-standard and very inflexible syntax that only supports a tiny subset of what CIDR is used for. Nominating for closure.

comment:7 by Kenneth Arnold, 15 years ago

gav's right about my solution being very limited. If something is going to go in Django, it should be reasonably general.

Here's an adaptation to use ipaddr-py, which has been added to the Python standard library in 3.1 (so eventually it wouldn't be a separate dependency):

from ipaddr import IP
class IpList(object):
    def __init__(self, addresses):
        self.addresses = [IP(address) for address in addresses]
    def __contains__(self, ip):
        ip = IP(ip)
        for address in self.addresses:
            if ip in address:
                return True
        return False
    
INTERNAL_IPS = IpList([
    '127.0.0.1',
    '10.0.0.0/24'
    ])

(I don't subclass list because we don't intend to support the full list interface.)

btw, "I don't think this is something that should be added to django proper, but you can bet your butt I'll use this code myself!" -- isn't that what "contrib" is usually for?

comment:8 by James Bennett, 15 years ago

The ipaddr module was actually yanked out of 3.1 prior to final release, due to some controversy over whether it was really a good API for this. So I'd be somewhat wary of depending on it; whatever ends up in later 3.x Pythons may not resemble it at all.

comment:9 by Jeremy Dunck, 14 years ago

Resolution: wontfix
Status: reopenedclosed

I made this a snippet:
http://www.djangosnippets.org/snippets/1862/

Closing.

comment:10 by Fabian Köster, 4 years ago

Easy pickings: unset
Resolution: wontfix
Status: closednew
UI/UX: unset

I would like to reopen this issue because it was closed already 10 years ago and I think it should be reevaluated for the following reasons:

  1. It is much more likely to run into this problem nowadays because when Django is executed using container virtualization (like Docker), the ip address of the container is often selected "randomly" and not known in advance. In this case setting INTERNAL_IPS to the the entire network from which Docker chooses from is the preferred solution.
  2. The implementation works with only builtin modules beginning with the introduction of the ipaddress module in Python 3.3. So all versions of Python supported by Django >= 2.2 support this feature.

This is the implementation I currently use:

import ipaddress


class CIDRList(list):
    def __init__(self, addresses):
        """Create a new ip_network object for each address range provided."""
        self.networks = [ipaddress.ip_network(address) for address in addresses]

    def __contains__(self, address):
        """Check if the given address is contained in any of the networks."""
        return any([ipaddress.ip_address(address) in network for network in self.networks])

I can then use for instance:

INTERNAL_IPS = CIDRList([
    '127.0.0.1',
    '172.0.0.0/255.0.0.0'  # Docker containers
])

comment:11 by Mariusz Felisiak, 4 years ago

Resolution: wontfix
Status: newclosed

in reply to:  10 ; comment:12 by Nick Pope, 4 years ago

Replying to Fabian Köster:

Why overcomplicate things? You can do the following without any custom classes:

import ipaddress

INTERNAL_IPS = ['127.0.0.1', *map(str, ipaddress.ip_network('172.0.0.0/24'))]

Granted for 172.0.0.0/8 this is a bad idea, but then you should probably constrain your range of addresses!

in reply to:  12 comment:13 by Fabian Köster, 4 years ago

Right, your solution is much easier. Thanks!

Replying to Nick Pope:

Replying to Fabian Köster:

Why overcomplicate things? You can do the following without any custom classes:

import ipaddress

INTERNAL_IPS = ['127.0.0.1', *map(str, ipaddress.ip_network('172.0.0.0/24'))]

Granted for 172.0.0.0/8 this is a bad idea, but then you should probably constrain your range of addresses!

Note: See TracTickets for help on using tickets.
Back to Top