Last active
June 2, 2021 17:18
-
-
Save nil0x42/943c2691e2130252091224e3dda059db to your computer and use it in GitHub Desktop.
Quickly check if an IPv4 is contained in a list of subnets.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import struct | |
import socket | |
class SubnetList: | |
"""Quickly check if an IPv4 is contained in a list of subnets. | |
- by @nil0x42 | |
- inspired by @nigel222's solution: https://stackoverflow.com/a/44264136 | |
>>> cloudflare_ips = SubnetList("/wordlists/cloudflare-ips.txt") | |
>>> "103.31.4.12" in cloudflare_ips | |
True | |
>>> "127.0.0.1" in cloudflare_ips | |
False | |
""" | |
def __init__(self, subnets_path=None): | |
self.subnets = [set() for x in range(32+1)] | |
if subnets_path: | |
for line in open(subnets_path): | |
line = line.strip() | |
if not line or line.startswith("#"): | |
continue | |
self.add(line) | |
def __contains__(self, ip): | |
ip = self._ip2int(ip) | |
for N in range(32, 7, -1): # check N from 32 to 8 | |
mask = 0xffffffff >> 32-N << 32-N | |
if ip & mask in self.subnets[N]: | |
return True | |
return False | |
def add(self, subnet): | |
if "/" in subnet: | |
network, N = subnet.split('/') | |
N = int(N) | |
assert 8 <= N <= 32, "invalid subnet mask in %r" % subnet | |
else: | |
network, N = subnet, 32 | |
network = self._ip2int(network) | |
self.subnets[N].add(network >> 32-N << 32-N) | |
def _ip2int(self, ip): | |
return struct.unpack("!I", socket.inet_aton(ip))[0] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment