-
Notifications
You must be signed in to change notification settings - Fork 29
/
ipaddr.py
103 lines (71 loc) · 2.56 KB
/
ipaddr.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Copyright (c) 2009 Liraz Siri <[email protected]> - all rights reserved
import struct
import socket
import math
from typing import Type, Union
def is_legal_ip(ip: str) -> bool:
try:
if len([octet for octet in ip.split(".")
if 255 >= int(octet) >= 0]) != 4:
return False
except ValueError:
return False
try:
packed = socket.inet_aton(ip)
except socket.error:
return False
return True
AnyIP = Union[int, str, 'IP']
def _str2int(ip: str) -> int:
bytes = list(map(int, ip.split('.')))
out: int = struct.unpack("!L", struct.pack("BBBB", *bytes))[0]
return out
def _int2str(num: int) -> str:
bytes = struct.unpack("BBBB", struct.pack("!L", num))
return '.'.join(list(map(str, bytes)))
class Error(Exception):
pass
class IP(int):
def __new__(cls: Type['IP'], arg: AnyIP) -> 'IP':
if isinstance(arg, IP):
return int.__new__(cls, int(arg))
elif isinstance(arg, int):
return int.__new__(cls, arg)
else:
if not is_legal_ip(arg):
raise Error(f"illegal ip ({arg})")
return int.__new__(cls, _str2int(arg))
def __str__(self) -> str:
return _int2str(self)
def __repr__(self) -> str:
return f"IP({str(self)})"
def __add__(self, other: int) -> 'IP':
return IP(int.__add__(self, other))
def __sub__(self, other: int) -> 'IP':
return IP(int.__sub__(self, other))
def __and__(self, other: int) -> 'IP':
return IP(int.__and__(self, other))
def __or__(self, other: int) -> 'IP':
return IP(int.__or__(self, other))
def __xor__(self, other: int) -> 'IP':
return IP(int.__xor__(self, other))
class IPRange:
@classmethod
def from_cidr(cls: Type['IPRange'], arg: str) -> 'IPRange':
address, cidr = arg.split('/')
netmask = 2 ** 32 - (2 ** (32 - int(cidr)))
return cls(address, netmask)
def __init__(self, ip: AnyIP, netmask: AnyIP):
self.ip = IP(ip)
self.netmask = IP(netmask)
self.network = self.ip & self.netmask
self.broadcast = self.network + 2 ** 32 - self.netmask - 1
self.cidr = int(32 - math.log(2 ** 32 - self.netmask, 2))
def __contains__(self, ip: AnyIP) -> bool:
return self.network < IP(ip) < self.broadcast
def __repr__(self) -> str:
return f"IPRange('{self.ip}', '{self.netmask}')"
def fmt_cidr(self) -> str:
return f"{self.ip}/{self.cidr}"
def __str__(self) -> str:
return self.fmt_cidr()