forked from lvfrazao/dhcppython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
122 lines (97 loc) · 3.62 KB
/
Copy pathutils.py
File metadata and controls
122 lines (97 loc) · 3.62 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import random
import string
import datetime
import socket
import unicodedata
from typing import Dict
import importlib.resources
from . import runtime_assets
VALID_HEX = list(set(string.hexdigits.upper()))
def cur_datetime(us_precision: bool = False) -> str:
fmt = "%Y-%m-%dT%H:%M:%S" + (".%f" if us_precision else "") + "Z"
return datetime.datetime.now(datetime.timezone.utc).strftime(fmt)
def cur_timestamp() -> int:
return int(datetime.datetime.utcnow().timestamp() * 10 ** 9)
def visual_length(text: str) -> int:
"""
Given a string it returns the visual length of the string as opposed to the
len function which returns the number of printable characters.
"""
# See https://www.unicode.org/reports/tr11/ for how this dict in constructed
visual_len = {
"F": 1,
"H": 1,
"Na": 1,
"N": 1,
"W": 2,
"A": 2,
}
return sum([visual_len[unicodedata.east_asian_width(char)] for char in text]) + 1
def random_mac(num_bytes: int = 6, delimiter: str = ":") -> str:
"""
Generates an 6 byte long MAC address.
>>> random_mac()
'CC:AC:3C:85:A4:EF'
"""
return delimiter.join(
["".join(random.choices(VALID_HEX, k=2)) for i in range(num_bytes)]
)
def random_mac_prefix(num_bytes: int = 6, delimiter: str = ":", prefix: str = "") -> str:
"""
Generates an 6 byte long MAC address with predefined prefix
>>> random_mac_prefix(prefix="00:0A:A0")
'00:0A:A0:85:A4:EF'
"""
if not prefix:
return random_mac(num_bytes=num_bytes, delimiter=delimiter)
else:
prefix = prefix.upper()
prefix = prefix.replace(":","").replace("-","").replace(".","")
if not set(prefix).issubset(set(VALID_HEX)):
raise TypeError(f"Wrong characters in MAC prefix: {prefix}")
if len(prefix)%2 != 0:
raise ValueError(f"Even number of HEX characters expected: {prefix}")
prefix_list = [ prefix[i]+prefix[i+1] for i in range(0, len(prefix), 2)]
return delimiter.join(prefix_list+
["".join(random.choices(VALID_HEX, k=2)) for i in range(num_bytes-len(prefix)//2)]
)
def is_mac_addr(mac_addr: str) -> bool:
"""
Returns True if the string is a valid MAC address.
Accepts ":" or "-" as valid MAC address delimiters.
"""
mac_addr = mac_addr.upper()
delimiter = ":" if ":" in mac_addr else "-"
if len(mac_addr.split(delimiter)) != 6 or len(mac_addr) != 17:
return False
if any([b not in VALID_HEX for b in "".join(mac_addr.split(delimiter))]):
return False
return True
mac_vendor_map: Dict[str, str] = {
line.split("\t\t")[0].split(" ")[0]: line.split("\t\t")[1]
for line in [
line.strip()
for line in importlib.resources.read_text(runtime_assets, "oui.txt").split("\n")
if "(base 16)" in line
]
}
def mac2vendor(mac_addr: str) -> str:
if is_mac_addr(mac_addr):
return mac_vendor_map.get(
mac_addr.replace(":", "").replace("-", "")[:6].upper(),
"Unknown Manufacturer",
)
else:
raise ValueError(f"{mac_addr} is not a valid MAC address")
def get_ip_by_iface(iface: str) -> str:
rand_port = 61224
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, 25, iface.encode())
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.connect(("255.255.255.255", rand_port))
return s.getsockname()[0]
def get_ip_by_server(server: str) -> str:
rand_port = 61222
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((server, rand_port))
return s.getsockname()[0]