5

In my Python application I have an array of IP address strings which looks something like this:

[
    "50.28.85.81-140", // Matches any IP address that matches the first 3 octets, and has its final octet somewhere between 81 and 140
    "26.83.152.12-194" // Same idea: 26.83.152.12 would match, 26.83.152.120 would match, 26.83.152.195 would not match
]

I installed netaddr and although the documentation seems great, I can't wrap my head around it. This must be really simple - how do I check if a given IP address matches one of these ranges? Don't need to use netaddr in particular - any simple Python solution will do.

smci
  • 32,567
  • 20
  • 113
  • 146
tylerl
  • 1,160
  • 1
  • 19
  • 41

2 Answers2

6

The idea is to split the IP and check every component separately.

mask = "26.83.152.12-192"
IP = "26.83.152.19"
def match(mask, IP):
   splitted_IP = IP.split('.')
   for index, current_range in enumerate(mask.split('.')):
      if '-' in current_range:
         mini, maxi = map(int,current_range.split('-'))
      else:
         mini = maxi = int(current_range)
      if not (mini <= int(splitted_IP[index]) <= maxi):
         return False
   return True
Faibbus
  • 1,115
  • 10
  • 18
  • 1
    no hacks version: `if IPv4Address('192.0.2.6') in IPv4Network('192.0.2.0/28'):` - using built in https://docs.python.org/3/library/ipaddress.html – benzkji May 12 '22 at 12:34
  • @benzkji `ipaddress` is definitely worth mentioning, though the OP case cannot be translated to a slash notation. – Faibbus May 13 '22 at 15:37
  • true. Though, there even is `ipaddress.summarize_address_range`, so you would just need to interate over all networks in the returned list of networks. https://docs.python.org/3/library/ipaddress.html#ipaddress.summarize_address_range – benzkji May 13 '22 at 18:56
3

Not sure this is the most optimal, but this is base python, no need for extra packages.

  • parse the ip_range, creating a list with 1 element if simple value, and a range if range. So it creates a list of 4 int/range objects.
  • then zip it with a split version of your address and test each value in range of the other

Note: Using range ensures super-fast in test (in Python 3) (Why is "1000000000000000 in range(1000000000000001)" so fast in Python 3?)

ip_range = "50.28.85.81-140"

toks = [[int(d)] if d.isdigit() else range(int(d.split("-")[0]),int(d.split("-")[1]+1)) for d in ip_range.split(".")]

print(toks) # debug

for test_ip in ("50.28.85.86","50.284.85.200","1.2.3.4"):
    print (all(int(a) in b for a,b in zip(test_ip.split("."),toks)))

result (as expected):

[[50], [28], [85], range(81, 140)]
True
False
False
Community
  • 1
  • 1
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219