-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathubiquity_doc.py
275 lines (231 loc) · 9.86 KB
/
ubiquity_doc.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
'''
Command:
ubnt-device-info summary
Sample output:
Device information summary:
Subsystem ID: ea15
Family: UniFi Dream Machine (UDM)
Model: UniFi Dream Machine Pro (UDM-Pro)
Default MAC address: e4:38:83:41:34:45
Default IPv4 address: 127.0.0.1
Firmware: 4.0.21 (4.0.21)
Command:
ip route
Sample output:
68.189.66.0/23 dev eth8 proto kernel scope link src 68.189.67.145
100.64.0.0/10 dev eth7 proto kernel scope link src 100.84.23.68
192.168.2.0/24 dev br0 proto kernel scope link src 192.168.2.1
192.168.3.1 dev tlprt0 scope link
192.168.4.0/24 dev br5 proto kernel scope link src 192.168.4.1
Command:
iptables -L -n
Sample Output:
Chain INPUT (policy ACCEPT)
target prot opt source destination
ALIEN all -- 0.0.0.0/0 0.0.0.0/0
UBIOS_INPUT_JUMP all -- 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ALIEN all -- 0.0.0.0/0 0.0.0.0/0
UBIOS_FORWARD_JUMP all -- 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
UBIOS_OUTPUT_JUMP all -- 0.0.0.0/0 0.0.0.0/0
Chain ALIEN (2 references)
target prot opt source destination
ALIENLOGNDROP all -- 0.0.0.0/0 0.0.0.0/0 match-set ALIEN src
Chain ALIENLOGNDROP (1 references)
target prot opt source destination
LOG all -- 0.0.0.0/0 0.0.0.0/0 limit: avg 1/min burst 5 LOG flags 0 level 4 prefix "ALIEN BLOCK: "
DROP all -- 0.0.0.0/0 0.0.0.0/0
Command:
ubnt-tools ubnt-discover
Sample output:
ERROR: (tlprt0) sendto returned: -1 - Required key not available
Hardware Address IP address Name
AC:8B:A9:D4:ED:51 192.168.2.98 UFP-UAP-B 'U6MeshBedroom'
E4:38:83:41:34:45 192.168.2.1 UDMPRO 'DreamMachinePro'
AC:8B:A9:D4:DC:DD 192.168.2.75 UFP-UAP-B 'U6MeshLivingRoom'
Command:
cat /data/udapi-config/dnsmasq.lease
Sample output:
1739993343 40:0e:85:1f:5c:97 192.168.2.49 * 01:40:0e:85:1f:5c:97
1739991547 4c:fc:aa:98:d2:67 192.168.2.33 Tesla_Model_S 01:4c:fc:aa:98:d2:67
1739973985 48:e7:29:1b:08:34 192.168.2.96 espressif *
1739934978 a4:90:05:69:53:c5 192.168.2.194 * 01:a4:90:05:69:53:c5
1739910595 34:19:4d:50:de:18 192.168.2.231 LGwebOSIT *
Command:
cat /data/udapi-config/udapi-net-cfg.json
Sample output:
json file with all the network config
'''
import paramiko
import json
import re
import requests
import os
import time
def ssh_command(hostname, username, password, command):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
client.connect(hostname, username=username, password=password)
stdin, stdout, stderr = client.exec_command(command)
return stdout.read().decode('utf-8').strip()
except Exception as e:
print(f"SSH connection failed: {e}")
return None
finally:
client.close()
def parse_device_info(output):
info = {}
for line in output.split('\n'):
if ':' in line:
key, value = line.split(':', 1)
info[key.strip()] = value.strip()
return info
def parse_ip_route(output):
routes = []
for line in output.split('\n'):
if line:
parts = line.split()
routes.append({
'destination': parts[0],
'device': parts[2],
'src': parts[-1] if len(parts) > 4 else None
})
return routes
def parse_iptables(output):
chains = {}
current_chain = None
for line in output.split('\n'):
if line.startswith('Chain'):
current_chain = line.split()[1]
chains[current_chain] = []
elif line.strip():
chains[current_chain].append(line.strip())
return chains
def parse_ubnt_discover(output):
devices = []
for line in output.split('\n'):
if 'Hardware Address' not in line:
parts = line.split()
if len(parts) >= 3:
mac = parts[0]
device = {
'mac': mac,
'ip': parts[1],
'name': ' '.join(parts[2:-1]) if len(parts) > 3 else parts[2],
'model': parts[-1].strip("'")
}
manufacturer = get_manufacturer(mac)
if manufacturer != "Unknown":
device['manufacturer'] = manufacturer
devices.append(device)
return devices
def parse_dnsmasq_lease(output):
leases = []
for line in output.split('\n'):
if line:
parts = line.split()
lease = {
'expiry': parts[0],
'mac': parts[1],
'ip': parts[2],
'hostname': parts[3],
'client_id': parts[4]
}
manufacturer = get_manufacturer(parts[1])
if manufacturer != "Unknown":
lease['manufacturer'] = manufacturer
leases.append(lease)
return leases
def parse_udapi_net_cfg(output):
return json.loads(output)
# Cache for OUI list
OUI_LIST_CACHE = None
def fetch_or_load_oui_list():
global OUI_LIST_CACHE
if OUI_LIST_CACHE is None:
cache_file = 'oui_list_cache.txt'
if os.path.exists(cache_file):
with open(cache_file, 'r') as f:
OUI_LIST_CACHE = f.read()
else:
max_retries = 3
for attempt in range(max_retries):
try:
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
response = requests.get('https://standards-oui.ieee.org/oui/oui.txt', headers=headers, timeout=10)
response.raise_for_status() # Will raise an exception for bad status codes
OUI_LIST_CACHE = response.text
with open(cache_file, 'w') as f:
f.write(OUI_LIST_CACHE)
break # Success, exit the loop
except requests.RequestException as e:
print(f"Attempt {attempt + 1}/{max_retries} failed with error: {e}")
if attempt < max_retries - 1: # If not the last attempt, wait and retry
time.sleep(5) # Wait for 5 seconds before next attempt
else:
print("No cached OUI list available.")
OUI_LIST_CACHE = "" # Empty string to avoid repeated attempts
return OUI_LIST_CACHE
def get_manufacturer(mac):
oui_list = fetch_or_load_oui_list()
oui = mac[:8].replace(':', '').upper() # Convert to format in the IEEE OUI file (first 6 characters, uppercase)
for line in oui_list.split('\n'):
if line.startswith(oui):
parts = line.split('(base 16)', 1)
if len(parts) > 1:
return parts[1].strip()
return "Unknown"
def main():
hostname = "192.168.1.1" # Replace with your UDM Pro's IP address
username = "root" # Default SSH username for UDM Pro
password = "Your_SSH_Password" # Replace with your actual password
data = {}
# Device Info
device_info = ssh_command(hostname, username, password, "ubnt-device-info summary")
data['device_info'] = parse_device_info(device_info)
# IP Route
ip_route = ssh_command(hostname, username, password, "ip route")
data['ip_routes'] = parse_ip_route(ip_route)
# IPTables
iptables = ssh_command(hostname, username, password, "iptables -L -n")
data['iptables'] = parse_iptables(iptables)
# Ubnt Discover - Changed to Network Infrastructure
ubnt_discover = ssh_command(hostname, username, password, "ubnt-tools ubnt-discover")
data['Network Infrastructure'] = parse_ubnt_discover(ubnt_discover)
# DNSMasq Lease - Changed to Network Clients
dnsmasq_lease = ssh_command(hostname, username, password, "cat /data/udapi-config/dnsmasq.lease")
data['Network Clients'] = parse_dnsmasq_lease(dnsmasq_lease)
# Udapi Net Config
udapi_net_cfg = ssh_command(hostname, username, password, "cat /data/udapi-config/udapi-net-cfg.json")
data['udapi_net_config'] = parse_udapi_net_cfg(udapi_net_cfg)
# Save to JSON
with open('udm_pro_config.json', 'w') as f:
json.dump(data, f, indent=2)
# Create Human Readable HTML
html_content = '<html><head><title>UDM Pro Configuration</title><style>body { font-family: Arial, sans-serif; } h2 { color: #333; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } tr:nth-child(even){background-color: #f2f2f2} th { background-color: #4CAF50; color: white; }</style></head><body>'
for key, value in data.items():
html_content += f'<h2>{key.replace("_", " ").title()}</h2>'
if isinstance(value, dict):
html_content += '<table><tr><th>Key</th><th>Value</th></tr>'
for k, v in value.items():
if isinstance(v, (dict, list)):
html_content += f'<tr><td>{k}</td><td><pre>{json.dumps(v, indent=2)}</pre></td></tr>'
else:
html_content += f'<tr><td>{k}</td><td>{v}</td></tr>'
html_content += '</table>'
elif isinstance(value, list):
html_content += '<table><tr><th>Item</th></tr>'
for item in value:
html_content += f'<tr><td><pre>{json.dumps(item, indent=2)}</pre></td></tr>'
html_content += '</table>'
else:
html_content += f'<p>{value}</p>'
html_content += '</body></html>'
with open('udm_pro_config.html', 'w') as f:
f.write(html_content)
if __name__ == "__main__":
main()