├── .gitignore ├── README.md ├── conf └── unifi-gateway.conf ├── daemon.py ├── poc ├── adopt.sh.py ├── inform.py ├── inform_sniffer.py ├── pool.py ├── real_inform_payload_exemple.json ├── sniffer.py ├── src │ ├── Sniffer.java │ ├── Test.java │ ├── TlvBox.java │ └── codec │ │ └── UnifiTlv.java ├── ssh_server.py └── unifi_inform_protocol.py ├── requirements.txt ├── tlv.py ├── tools.py ├── unifi_gateway.py └── unifi_protocol.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | *.pyc 4 | venv 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WORK IN PROGRESS, NOT WORKING !! 2 | 3 | # pfSense Unifi gateway plugin 4 | 5 | I don't know about you guys, but I'm very upset each time I log in the unifi controller. It looks like a conspiracy by Ubiquiti to not show all green circles because you don't buy all the ubuiquiti stuff. 6 | 7 | The goal of this plugin is to simulate a UGW router to the Unifi controller. 8 | 9 | Things to do: 10 | - [x] reverse engineering the unifi protocol 11 | - [ ] create a nice python code 12 | - [ ] create a plugin for pfSense 13 | - [ ] add dpi compatibility ? 14 | 15 | ## Reverse engineering / Proof of concept 16 | 17 | You will find in "poc" directory all the necessary to simulate a UGW gateway. It's a **poc**, so please wait the final version if you don't know what you do. 18 | 19 | ## Things to install manualy on pfSense router for now on: 20 | 21 | - pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/py27-setuptools-36.5.0.txz 22 | - pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/py27-uptime-3.0.1.txz 23 | 24 | ## How it works now 25 | 26 | Without the definitive pfSense plugin, we have to manualy launch the daemon: 27 | 28 | ```bash 29 | python unifi_gateway.py start 30 | ``` 31 | 32 | ## Documentation 33 | - https://github.com/jk-5/unifi-inform-protocol 34 | - https://github.com/fxkr/unifi-protocol-reverse-engineering 35 | -------------------------------------------------------------------------------- /conf/unifi-gateway.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | pid_file = unifi-gateway.pid 3 | 4 | [gateway] 5 | is_adopted = no 6 | lan_ip = 192.168.0.1 7 | lan_mac = 0a:0a:0a:0a:0a:0a 8 | firmware = 4.3.49.5001150 9 | device = UGW3 10 | url = http://toto 11 | key = oeruchoreuch 12 | 13 | -------------------------------------------------------------------------------- /daemon.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # From "A simple unix/linux daemon in Python" by Sander Marechal 3 | # See http://stackoverflow.com/a/473702/1422096 4 | # 5 | # Modified to add quit() that allows to run some code before closing the daemon 6 | # See http://stackoverflow.com/a/40423758/1422096 7 | # 8 | # Joseph Ernest, 2016/11/12 9 | 10 | import sys, os, time, atexit 11 | from signal import signal, SIGTERM 12 | 13 | 14 | class Daemon: 15 | """ 16 | A generic daemon class. 17 | 18 | Usage: subclass the Daemon class and override the run() method 19 | """ 20 | def __init__(self, pidfile='_.pid', stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): 21 | self.stdin = stdin 22 | self.stdout = stdout 23 | self.stderr = stderr 24 | self.pidfile = pidfile 25 | 26 | def daemonize(self): 27 | """ 28 | do the UNIX double-fork magic, see Stevens' "Advanced 29 | Programming in the UNIX Environment" for details (ISBN 0201563177) 30 | http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 31 | """ 32 | try: 33 | pid = os.fork() 34 | if pid > 0: 35 | # exit first parent 36 | sys.exit(0) 37 | except OSError, e: 38 | sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) 39 | sys.exit(1) 40 | 41 | # decouple from parent environment 42 | os.setsid() 43 | os.umask(0) 44 | 45 | # do second fork 46 | try: 47 | pid = os.fork() 48 | if pid > 0: 49 | # exit from second parent 50 | sys.exit(0) 51 | except OSError, e: 52 | sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) 53 | sys.exit(1) 54 | 55 | # redirect standard file descriptors 56 | sys.stdout.flush() 57 | sys.stderr.flush() 58 | si = file(self.stdin, 'r') 59 | so = file(self.stdout, 'a+') 60 | se = file(self.stderr, 'a+', 0) 61 | os.dup2(si.fileno(), sys.stdin.fileno()) 62 | os.dup2(so.fileno(), sys.stdout.fileno()) 63 | os.dup2(se.fileno(), sys.stderr.fileno()) 64 | 65 | atexit.register(self.onstop) 66 | signal(SIGTERM, lambda signum, stack_frame: exit()) 67 | 68 | # write pidfile 69 | pid = str(os.getpid()) 70 | file(self.pidfile, 'w+').write("%s\n" % pid) 71 | 72 | def onstop(self): 73 | self.quit() 74 | os.remove(self.pidfile) 75 | 76 | def start(self): 77 | """ 78 | Start the daemon 79 | """ 80 | # Check for a pidfile to see if the daemon already runs 81 | try: 82 | pf = file(self.pidfile, 'r') 83 | pid = int(pf.read().strip()) 84 | pf.close() 85 | except IOError: 86 | pid = None 87 | 88 | if pid: 89 | message = "pidfile %s already exist. Daemon already running?\n" 90 | sys.stderr.write(message % self.pidfile) 91 | sys.exit(1) 92 | 93 | # Start the daemon 94 | self.daemonize() 95 | self.run() 96 | 97 | def stop(self): 98 | """ 99 | Stop the daemon 100 | """ 101 | # Get the pid from the pidfile 102 | try: 103 | pf = file(self.pidfile, 'r') 104 | pid = int(pf.read().strip()) 105 | pf.close() 106 | except IOError: 107 | pid = None 108 | 109 | if not pid: 110 | message = "pidfile %s does not exist. Daemon not running?\n" 111 | sys.stderr.write(message % self.pidfile) 112 | return # not an error in a restart 113 | 114 | # Try killing the daemon process 115 | try: 116 | while 1: 117 | os.kill(pid, SIGTERM) 118 | time.sleep(0.1) 119 | except OSError, err: 120 | err = str(err) 121 | if err.find("No such process") > 0: 122 | if os.path.exists(self.pidfile): 123 | os.remove(self.pidfile) 124 | else: 125 | print str(err) 126 | sys.exit(1) 127 | 128 | def restart(self): 129 | """ 130 | Restart the daemon 131 | """ 132 | self.stop() 133 | self.start() 134 | 135 | def run(self): 136 | """ 137 | You should override this method when you subclass Daemon. It will be called after the process has been 138 | daemonized by start() or restart(). 139 | """ 140 | 141 | def quit(self): 142 | """ 143 | You should override this method when you subclass Daemon. It will be called before the process is stopped. 144 | """ 145 | -------------------------------------------------------------------------------- /poc/adopt.sh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys 3 | 4 | from inform import send_inform 5 | 6 | with open('/tmp/cfg/log', 'w') as f: 7 | f.write('url=%s\nkey=%s\n' % (sys.argv[1], sys.argv[2])) 8 | 9 | send_inform(sys.argv[1], sys.argv[2]) 10 | -------------------------------------------------------------------------------- /poc/inform.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import urllib2 4 | import sys 5 | import uuid 6 | 7 | from struct import pack, unpack 8 | 9 | import zlib 10 | 11 | import os 12 | 13 | import time 14 | 15 | import binascii 16 | 17 | import psutil 18 | from Crypto import Random 19 | from Crypto.Cipher import AES 20 | from binascii import a2b_hex 21 | 22 | from random import randint 23 | 24 | from uptime import uptime 25 | 26 | 27 | def packet_encode(key, json): 28 | iv = Random.new().read(16) 29 | 30 | # zlib compression 31 | payload = zlib.compress(json) 32 | # padding - http://stackoverflow.com/a/14205319 33 | pad_len = AES.block_size - (len(payload) % AES.block_size) 34 | payload += chr(pad_len) * pad_len 35 | # encryption 36 | payload = AES.new(key, AES.MODE_CBC, iv).encrypt(payload) 37 | 38 | # encode packet 39 | data = 'TNBU' # magic 40 | data += pack('>I', 1) # packet version 41 | data += pack('BBBBBB', *(0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)) # mac address 42 | data += pack('>H', 3) # flags 43 | data += iv # encryption iv 44 | data += pack('>I', 1) # payload version 45 | data += pack('>I', len(payload)) # payload length 46 | data += payload 47 | 48 | return data 49 | 50 | 51 | def inform(url, key, json): 52 | headers = { 53 | 'Content-Type': 'application/x-binary', 54 | 'User-Agent': 'AirControl Agent v1.0' 55 | } 56 | data = packet_encode(key, json) 57 | req = urllib2.Request(url, data, headers) 58 | print('send %s' % json) 59 | try: 60 | res = urllib2.urlopen(req) 61 | return packet_decode(key, res.read()) 62 | except Exception as a: 63 | print a 64 | 65 | 66 | def mac2a(mac): 67 | return ':'.join(map(lambda i: '%02x' %i, mac)) 68 | 69 | 70 | def mac2serial(mac): 71 | return ''.join(map(lambda i: '%02x'%i, mac)) 72 | 73 | 74 | def ip2a(ip): 75 | return '.'.join(map(str, ip)) 76 | 77 | 78 | def packet_decode(key, data, iv=None): 79 | magic = data[0:4] 80 | if magic != 'TNBU': 81 | raise Exception("Missing magic in response: '%s' instead of 'TNBU'" %(magic)) 82 | mac = unpack('BBBBBB', data[8:14]) 83 | # if mac != (0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9): 84 | # raise Exception('Mac address changed in response: %s -> %s'%(mac2a((0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)), mac2a(mac))) 85 | 86 | flags = unpack('>H', data[14:16])[0] 87 | iv = data[16:32] if not iv else iv 88 | version = unpack('>I', data[32:36])[0] 89 | payload_len = unpack('>I', data[36:40])[0] 90 | payload = data[40:(40+payload_len)] 91 | 92 | print(binascii.hexlify(iv)) 93 | 94 | # decrypt if required 95 | if flags & 0x01: 96 | payload = AES.new(key, AES.MODE_CBC, iv).decrypt(payload) 97 | # unpad - https://gist.github.com/marcoslin/8026990#file-server-py-L43 98 | pad_size = ord(payload[-1]) 99 | if pad_size > AES.block_size: 100 | raise Exception('Response not padded or padding is corrupt') 101 | payload = payload[:(len(payload) - pad_size)] 102 | # uncompress if required 103 | if flags & 0x02: 104 | payload = zlib.decompress(payload) 105 | 106 | return payload 107 | 108 | 109 | def cfg_replace(fn, contents): 110 | '''replace configuration file''' 111 | fp = os.path.join('/tmp/cfg', fn) 112 | try: 113 | os.mkdir('/tmp/cfg') 114 | except OSError: 115 | pass 116 | with open(fp, 'w') as f: 117 | f.write(contents) 118 | 119 | 120 | def cfg(fn, key): 121 | '''read key from configuration file''' 122 | fp = os.path.join('/tmp/cfg', fn) 123 | try: 124 | with open(fp) as f: 125 | for line in f: 126 | if line.startswith(key + '='): 127 | return line.split('=', 1)[1].rstrip() 128 | except IOError: 129 | pass 130 | 131 | def create_complete_inform(): 132 | load_average = open('/proc/loadavg').readline().split(' ') 133 | gateway_wan_ip = ip2a((82, 238, 9, 250)) 134 | gateway_wan_mac = mac2a((0x80, 0x2a, 0xa8, 0xcd, 0xa9, 0x52)) 135 | gateway_lan_ip = ip2a((10, 0, 8, 2)) 136 | gateway_lan_mac = mac2a((0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)) 137 | 138 | return json.dumps({ 139 | "bootrom_version": "unknown", 140 | "cfgversion": cfg('_cfg', 'cfgversion'), 141 | "config_network_wan": { 142 | "type": "dhcp", 143 | }, 144 | "config_port_table": [ 145 | { 146 | "ifname": "eth0", 147 | "name": "wan" 148 | }, 149 | { 150 | "ifname": "eth1", 151 | "name": "lan" 152 | }, 153 | { 154 | "ifname": "eth2", 155 | "name": "lan" 156 | } 157 | ], 158 | "connect_request_ip": gateway_lan_ip, 159 | "connect_request_port": "36424", 160 | "default": False, 161 | "discovery_response": False, 162 | "fw_caps": 3, 163 | "guest_token": "4C1D46707239C6EB5A2366F505A44A91", 164 | "has_default_route_distance": True, 165 | "has_dnsmasq_hostfile_update": False, 166 | "has_dpi": True, 167 | "dpi-clients": [ 168 | "80:2a:a8:f0:ef:78" 169 | ], 170 | "dpi-stats": [ 171 | { 172 | "initialized": "94107792805", 173 | "mac": "80:2a:a8:f0:ef:78", 174 | "stats": [ 175 | { 176 | "app": 5, 177 | "cat": 3, 178 | "rx_bytes": 82297468, 179 | "rx_packets": 57565, 180 | "tx_bytes": 1710174, 181 | "tx_packets": 25324 182 | }, 183 | { 184 | "app": 94, 185 | "cat": 19, 186 | "rx_bytes": 1593846895, 187 | "rx_packets": 1738901, 188 | "tx_bytes": 348738675, 189 | "tx_packets": 2004045 190 | }, 191 | { 192 | "app": 133, 193 | "cat": 3, 194 | "rx_bytes": 531190, 195 | "rx_packets": 2465, 196 | "tx_bytes": 676859, 197 | "tx_packets": 2760 198 | }, 199 | { 200 | "app": 222, 201 | "cat": 13, 202 | "rx_bytes": 3441437, 203 | "rx_packets": 3033, 204 | "tx_bytes": 203173, 205 | "tx_packets": 1468 206 | }, 207 | { 208 | "app": 23, 209 | "cat": 0, 210 | "rx_bytes": 0, 211 | "rx_packets": 0, 212 | "tx_bytes": 145, 213 | "tx_packets": 2 214 | }, 215 | { 216 | "app": 7, 217 | "cat": 0, 218 | "rx_bytes": 0, 219 | "rx_packets": 0, 220 | "tx_bytes": 145, 221 | "tx_packets": 2 222 | }, 223 | { 224 | "app": 7, 225 | "cat": 13, 226 | "rx_bytes": 24417806554, 227 | "rx_packets": 18415873, 228 | "tx_bytes": 2817966897, 229 | "tx_packets": 9910192 230 | }, 231 | { 232 | "app": 185, 233 | "cat": 20, 234 | "rx_bytes": 28812050, 235 | "rx_packets": 208945, 236 | "tx_bytes": 160819147, 237 | "tx_packets": 1228992 238 | }, 239 | { 240 | "app": 65535, 241 | "cat": 255, 242 | "rx_bytes": 182029551, 243 | "rx_packets": 1796815, 244 | "tx_bytes": 435732626, 245 | "tx_packets": 1933469 246 | }, 247 | { 248 | "app": 4, 249 | "cat": 10, 250 | "rx_bytes": 1522, 251 | "rx_packets": 20, 252 | "tx_bytes": 882, 253 | "tx_packets": 12 254 | }, 255 | { 256 | "app": 106, 257 | "cat": 18, 258 | "rx_bytes": 982710, 259 | "rx_packets": 10919, 260 | "tx_bytes": 1010970, 261 | "tx_packets": 11233 262 | }, 263 | { 264 | "app": 30, 265 | "cat": 18, 266 | "rx_bytes": 7819852, 267 | "rx_packets": 20378, 268 | "tx_bytes": 1293104, 269 | "tx_packets": 18686 270 | }, 271 | { 272 | "app": 1, 273 | "cat": 0, 274 | "rx_bytes": 0, 275 | "rx_packets": 0, 276 | "tx_bytes": 145, 277 | "tx_packets": 2 278 | }, 279 | { 280 | "app": 63, 281 | "cat": 18, 282 | "rx_bytes": 780358, 283 | "rx_packets": 3520, 284 | "tx_bytes": 545757, 285 | "tx_packets": 6545 286 | }, 287 | { 288 | "app": 8, 289 | "cat": 13, 290 | "rx_bytes": 180691586, 291 | "rx_packets": 132204, 292 | "tx_bytes": 5970383, 293 | "tx_packets": 74482 294 | }, 295 | { 296 | "app": 21, 297 | "cat": 10, 298 | "rx_bytes": 5521547718, 299 | "rx_packets": 73080390, 300 | "tx_bytes": 179999309100, 301 | "tx_packets": 130627577 302 | } 303 | ] 304 | } 305 | ], 306 | "dpi-stats-table": [ 307 | { 308 | "_id": "5875d9f9e4b02fd3851c55e4", 309 | "_subid": "5875d9f5e4b02fd3851c55d8", 310 | "by_app": [ 311 | { 312 | "app": 5, 313 | "cat": 3, 314 | "rx_bytes": 2652, 315 | "rx_packets": 4, 316 | "tx_bytes": 1797, 317 | "tx_packets": 7 318 | }, 319 | { 320 | "app": 94, 321 | "cat": 19, 322 | "rx_bytes": 9010458, 323 | "rx_packets": 6977, 324 | "tx_bytes": 518163, 325 | "tx_packets": 3533 326 | }, 327 | { 328 | "app": 209, 329 | "cat": 13, 330 | "rx_bytes": 39303, 331 | "rx_packets": 90, 332 | "tx_bytes": 17744, 333 | "tx_packets": 78 334 | }, 335 | { 336 | "app": 10, 337 | "cat": 4, 338 | "rx_bytes": 15273, 339 | "rx_packets": 15, 340 | "tx_bytes": 2728, 341 | "tx_packets": 23 342 | }, 343 | { 344 | "app": 7, 345 | "cat": 13, 346 | "rx_bytes": 369394, 347 | "rx_packets": 293, 348 | "tx_bytes": 24904, 349 | "tx_packets": 244 350 | }, 351 | { 352 | "app": 185, 353 | "cat": 20, 354 | "rx_bytes": 62070, 355 | "rx_packets": 130, 356 | "tx_bytes": 27219, 357 | "tx_packets": 169 358 | }, 359 | { 360 | "app": 65535, 361 | "cat": 255, 362 | "rx_bytes": 976848, 363 | "rx_packets": 1027, 364 | "tx_bytes": 77317, 365 | "tx_packets": 695 366 | }, 367 | { 368 | "app": 12, 369 | "cat": 13, 370 | "rx_bytes": 92924774, 371 | "rx_packets": 70496, 372 | "tx_bytes": 17360339, 373 | "tx_packets": 69509 374 | }, 375 | { 376 | "app": 150, 377 | "cat": 3, 378 | "rx_bytes": 54609, 379 | "rx_packets": 71, 380 | "tx_bytes": 19749, 381 | "tx_packets": 85 382 | }, 383 | { 384 | "app": 95, 385 | "cat": 5, 386 | "rx_bytes": 9835, 387 | "rx_packets": 41, 388 | "tx_bytes": 3956, 389 | "tx_packets": 41 390 | }, 391 | { 392 | "app": 168, 393 | "cat": 20, 394 | "rx_bytes": 100049, 395 | "rx_packets": 198, 396 | "tx_bytes": 60396, 397 | "tx_packets": 275 398 | }, 399 | { 400 | "app": 3, 401 | "cat": 10, 402 | "rx_bytes": 12538, 403 | "rx_packets": 36, 404 | "tx_bytes": 10607, 405 | "tx_packets": 75 406 | }, 407 | { 408 | "app": 84, 409 | "cat": 3, 410 | "rx_bytes": 45115, 411 | "rx_packets": 135, 412 | "tx_bytes": 91866, 413 | "tx_packets": 158 414 | }, 415 | { 416 | "app": 84, 417 | "cat": 13, 418 | "rx_bytes": 42563, 419 | "rx_packets": 102, 420 | "tx_bytes": 32676, 421 | "tx_packets": 113 422 | }, 423 | { 424 | "app": 186, 425 | "cat": 20, 426 | "rx_bytes": 44618, 427 | "rx_packets": 68, 428 | "tx_bytes": 8826, 429 | "tx_packets": 86 430 | } 431 | ], 432 | "by_cat": [ 433 | { 434 | "apps": [ 435 | 5, 436 | 150, 437 | 84 438 | ], 439 | "cat": 3, 440 | "rx_bytes": 102376, 441 | "rx_packets": 210, 442 | "tx_bytes": 113412, 443 | "tx_packets": 250 444 | }, 445 | { 446 | "apps": [ 447 | 10 448 | ], 449 | "cat": 4, 450 | "rx_bytes": 15273, 451 | "rx_packets": 15, 452 | "tx_bytes": 2728, 453 | "tx_packets": 23 454 | }, 455 | { 456 | "apps": [ 457 | 95 458 | ], 459 | "cat": 5, 460 | "rx_bytes": 9835, 461 | "rx_packets": 41, 462 | "tx_bytes": 3956, 463 | "tx_packets": 41 464 | }, 465 | { 466 | "apps": [ 467 | 3 468 | ], 469 | "cat": 10, 470 | "rx_bytes": 12538, 471 | "rx_packets": 36, 472 | "tx_bytes": 10607, 473 | "tx_packets": 75 474 | }, 475 | { 476 | "apps": [ 477 | 209, 478 | 7, 479 | 12, 480 | 84 481 | ], 482 | "cat": 13, 483 | "rx_bytes": 93376034, 484 | "rx_packets": 70981, 485 | "tx_bytes": 17435663, 486 | "tx_packets": 69944 487 | }, 488 | { 489 | "apps": [ 490 | 94 491 | ], 492 | "cat": 19, 493 | "rx_bytes": 9010458, 494 | "rx_packets": 6977, 495 | "tx_bytes": 518163, 496 | "tx_packets": 3533 497 | }, 498 | { 499 | "apps": [ 500 | 185, 501 | 168, 502 | 186 503 | ], 504 | "cat": 20, 505 | "rx_bytes": 206737, 506 | "rx_packets": 396, 507 | "tx_bytes": 96441, 508 | "tx_packets": 530 509 | }, 510 | { 511 | "apps": [ 512 | 65535 513 | ], 514 | "cat": 255, 515 | "rx_bytes": 976848, 516 | "rx_packets": 1027, 517 | "tx_bytes": 77317, 518 | "tx_packets": 695 519 | } 520 | ], 521 | "initialized": "88122111307" 522 | }, 523 | { 524 | "_id": "5875d9f9e4b02fd3851c55e4", 525 | "_subid": "5875e1f8e4b0ba28be0f8335", 526 | "by_app": [ 527 | { 528 | "app": 5, 529 | "cat": 3, 530 | "clients": [ 531 | { 532 | "mac": "80:2a:a8:f0:ef:78", 533 | "rx_bytes": 82297468, 534 | "rx_packets": 57565, 535 | "tx_bytes": 1710174, 536 | "tx_packets": 25324 537 | } 538 | ], 539 | "known_clients": 1, 540 | "rx_bytes": 82300120, 541 | "rx_packets": 57569, 542 | "tx_bytes": 1711971, 543 | "tx_packets": 25331 544 | }, 545 | { 546 | "app": 94, 547 | "cat": 19, 548 | "clients": [ 549 | { 550 | "mac": "80:2a:a8:f0:ef:78", 551 | "rx_bytes": 1593846895, 552 | "rx_packets": 1738901, 553 | "tx_bytes": 348738675, 554 | "tx_packets": 2004045 555 | } 556 | ], 557 | "known_clients": 1, 558 | "rx_bytes": 1622602418, 559 | "rx_packets": 1760201, 560 | "tx_bytes": 349693010, 561 | "tx_packets": 2012708 562 | }, 563 | { 564 | "app": 209, 565 | "cat": 13, 566 | "rx_bytes": 43670, 567 | "rx_packets": 100, 568 | "tx_bytes": 20728, 569 | "tx_packets": 91 570 | }, 571 | { 572 | "app": 10, 573 | "cat": 4, 574 | "rx_bytes": 15273, 575 | "rx_packets": 15, 576 | "tx_bytes": 2728, 577 | "tx_packets": 23 578 | }, 579 | { 580 | "app": 133, 581 | "cat": 3, 582 | "clients": [ 583 | { 584 | "mac": "80:2a:a8:f0:ef:78", 585 | "rx_bytes": 531190, 586 | "rx_packets": 2465, 587 | "tx_bytes": 676859, 588 | "tx_packets": 2760 589 | } 590 | ], 591 | "known_clients": 1, 592 | "rx_bytes": 531190, 593 | "rx_packets": 2465, 594 | "tx_bytes": 676859, 595 | "tx_packets": 2760 596 | }, 597 | { 598 | "app": 222, 599 | "cat": 13, 600 | "clients": [ 601 | { 602 | "mac": "80:2a:a8:f0:ef:78", 603 | "rx_bytes": 3441437, 604 | "rx_packets": 3033, 605 | "tx_bytes": 203173, 606 | "tx_packets": 1468 607 | } 608 | ], 609 | "known_clients": 1, 610 | "rx_bytes": 3441437, 611 | "rx_packets": 3033, 612 | "tx_bytes": 203173, 613 | "tx_packets": 1468 614 | }, 615 | { 616 | "app": 23, 617 | "cat": 0, 618 | "clients": [ 619 | { 620 | "mac": "80:2a:a8:f0:ef:78", 621 | "rx_bytes": 0, 622 | "rx_packets": 0, 623 | "tx_bytes": 145, 624 | "tx_packets": 2 625 | } 626 | ], 627 | "known_clients": 1, 628 | "rx_bytes": 0, 629 | "rx_packets": 0, 630 | "tx_bytes": 145, 631 | "tx_packets": 2 632 | }, 633 | { 634 | "app": 7, 635 | "cat": 0, 636 | "clients": [ 637 | { 638 | "mac": "80:2a:a8:f0:ef:78", 639 | "rx_bytes": 0, 640 | "rx_packets": 0, 641 | "tx_bytes": 145, 642 | "tx_packets": 2 643 | } 644 | ], 645 | "known_clients": 1, 646 | "rx_bytes": 0, 647 | "rx_packets": 0, 648 | "tx_bytes": 145, 649 | "tx_packets": 2 650 | }, 651 | { 652 | "app": 7, 653 | "cat": 13, 654 | "clients": [ 655 | { 656 | "mac": "80:2a:a8:f0:ef:78", 657 | "rx_bytes": 24417806554, 658 | "rx_packets": 18415873, 659 | "tx_bytes": 2817966897, 660 | "tx_packets": 9910192 661 | } 662 | ], 663 | "known_clients": 1, 664 | "rx_bytes": 24418175948, 665 | "rx_packets": 18416166, 666 | "tx_bytes": 2817991801, 667 | "tx_packets": 9910436 668 | }, 669 | { 670 | "app": 185, 671 | "cat": 20, 672 | "clients": [ 673 | { 674 | "mac": "80:2a:a8:f0:ef:78", 675 | "rx_bytes": 28812050, 676 | "rx_packets": 208945, 677 | "tx_bytes": 160819147, 678 | "tx_packets": 1228992 679 | } 680 | ], 681 | "known_clients": 1, 682 | "rx_bytes": 28874120, 683 | "rx_packets": 209075, 684 | "tx_bytes": 160846366, 685 | "tx_packets": 1229161 686 | }, 687 | { 688 | "app": 65535, 689 | "cat": 255, 690 | "clients": [ 691 | { 692 | "mac": "80:2a:a8:f0:ef:78", 693 | "rx_bytes": 182029551, 694 | "rx_packets": 1796815, 695 | "tx_bytes": 435732626, 696 | "tx_packets": 1933469 697 | } 698 | ], 699 | "known_clients": 1, 700 | "rx_bytes": 183022079, 701 | "rx_packets": 1798016, 702 | "tx_bytes": 435832672, 703 | "tx_packets": 1934359 704 | }, 705 | { 706 | "app": 12, 707 | "cat": 13, 708 | "rx_bytes": 92925290, 709 | "rx_packets": 70498, 710 | "tx_bytes": 17360839, 711 | "tx_packets": 69512 712 | }, 713 | { 714 | "app": 4, 715 | "cat": 10, 716 | "clients": [ 717 | { 718 | "mac": "80:2a:a8:f0:ef:78", 719 | "rx_bytes": 1522, 720 | "rx_packets": 20, 721 | "tx_bytes": 882, 722 | "tx_packets": 12 723 | } 724 | ], 725 | "known_clients": 1, 726 | "rx_bytes": 1522, 727 | "rx_packets": 20, 728 | "tx_bytes": 882, 729 | "tx_packets": 12 730 | }, 731 | { 732 | "app": 106, 733 | "cat": 18, 734 | "clients": [ 735 | { 736 | "mac": "80:2a:a8:f0:ef:78", 737 | "rx_bytes": 982710, 738 | "rx_packets": 10919, 739 | "tx_bytes": 1010970, 740 | "tx_packets": 11233 741 | } 742 | ], 743 | "known_clients": 1, 744 | "rx_bytes": 982710, 745 | "rx_packets": 10919, 746 | "tx_bytes": 1010970, 747 | "tx_packets": 11233 748 | }, 749 | { 750 | "app": 30, 751 | "cat": 18, 752 | "clients": [ 753 | { 754 | "mac": "80:2a:a8:f0:ef:78", 755 | "rx_bytes": 7819852, 756 | "rx_packets": 20378, 757 | "tx_bytes": 1293104, 758 | "tx_packets": 18686 759 | } 760 | ], 761 | "known_clients": 1, 762 | "rx_bytes": 7819852, 763 | "rx_packets": 20378, 764 | "tx_bytes": 1293104, 765 | "tx_packets": 18686 766 | }, 767 | { 768 | "app": 1, 769 | "cat": 0, 770 | "clients": [ 771 | { 772 | "mac": "80:2a:a8:f0:ef:78", 773 | "rx_bytes": 0, 774 | "rx_packets": 0, 775 | "tx_bytes": 145, 776 | "tx_packets": 2 777 | } 778 | ], 779 | "known_clients": 1, 780 | "rx_bytes": 0, 781 | "rx_packets": 0, 782 | "tx_bytes": 145, 783 | "tx_packets": 2 784 | }, 785 | { 786 | "app": 150, 787 | "cat": 3, 788 | "rx_bytes": 54609, 789 | "rx_packets": 71, 790 | "tx_bytes": 19749, 791 | "tx_packets": 85 792 | }, 793 | { 794 | "app": 95, 795 | "cat": 5, 796 | "rx_bytes": 9835, 797 | "rx_packets": 41, 798 | "tx_bytes": 3956, 799 | "tx_packets": 41 800 | }, 801 | { 802 | "app": 168, 803 | "cat": 20, 804 | "rx_bytes": 100583, 805 | "rx_packets": 204, 806 | "tx_bytes": 62503, 807 | "tx_packets": 296 808 | }, 809 | { 810 | "app": 3, 811 | "cat": 10, 812 | "rx_bytes": 12916, 813 | "rx_packets": 41, 814 | "tx_bytes": 11501, 815 | "tx_packets": 86 816 | }, 817 | { 818 | "app": 84, 819 | "cat": 13, 820 | "rx_bytes": 42563, 821 | "rx_packets": 102, 822 | "tx_bytes": 32676, 823 | "tx_packets": 113 824 | }, 825 | { 826 | "app": 84, 827 | "cat": 3, 828 | "rx_bytes": 62456, 829 | "rx_packets": 166, 830 | "tx_bytes": 101105, 831 | "tx_packets": 183 832 | }, 833 | { 834 | "app": 63, 835 | "cat": 18, 836 | "clients": [ 837 | { 838 | "mac": "80:2a:a8:f0:ef:78", 839 | "rx_bytes": 780358, 840 | "rx_packets": 3520, 841 | "tx_bytes": 545757, 842 | "tx_packets": 6545 843 | } 844 | ], 845 | "known_clients": 1, 846 | "rx_bytes": 780358, 847 | "rx_packets": 3520, 848 | "tx_bytes": 545757, 849 | "tx_packets": 6545 850 | }, 851 | { 852 | "app": 8, 853 | "cat": 13, 854 | "clients": [ 855 | { 856 | "mac": "80:2a:a8:f0:ef:78", 857 | "rx_bytes": 180691586, 858 | "rx_packets": 132204, 859 | "tx_bytes": 5970383, 860 | "tx_packets": 74482 861 | } 862 | ], 863 | "known_clients": 1, 864 | "rx_bytes": 180691586, 865 | "rx_packets": 132204, 866 | "tx_bytes": 5970383, 867 | "tx_packets": 74482 868 | }, 869 | { 870 | "app": 186, 871 | "cat": 20, 872 | "rx_bytes": 44618, 873 | "rx_packets": 68, 874 | "tx_bytes": 8826, 875 | "tx_packets": 86 876 | }, 877 | { 878 | "app": 21, 879 | "cat": 10, 880 | "clients": [ 881 | { 882 | "mac": "80:2a:a8:f0:ef:78", 883 | "rx_bytes": 5521547718, 884 | "rx_packets": 73080390, 885 | "tx_bytes": 179999309100, 886 | "tx_packets": 130627577 887 | } 888 | ], 889 | "known_clients": 1, 890 | "rx_bytes": 5521547718, 891 | "rx_packets": 73080390, 892 | "tx_bytes": 179999309100, 893 | "tx_packets": 130627577 894 | } 895 | ], 896 | "by_cat": [ 897 | { 898 | "apps": [ 899 | 23, 900 | 7, 901 | 1 902 | ], 903 | "cat": 0, 904 | "rx_bytes": 0, 905 | "rx_packets": 0, 906 | "tx_bytes": 435, 907 | "tx_packets": 6 908 | }, 909 | { 910 | "apps": [ 911 | 5, 912 | 133, 913 | 150, 914 | 84 915 | ], 916 | "cat": 3, 917 | "rx_bytes": 82948375, 918 | "rx_packets": 60271, 919 | "tx_bytes": 2509684, 920 | "tx_packets": 28359 921 | }, 922 | { 923 | "apps": [ 924 | 10 925 | ], 926 | "cat": 4, 927 | "rx_bytes": 15273, 928 | "rx_packets": 15, 929 | "tx_bytes": 2728, 930 | "tx_packets": 23 931 | }, 932 | { 933 | "apps": [ 934 | 95 935 | ], 936 | "cat": 5, 937 | "rx_bytes": 9835, 938 | "rx_packets": 41, 939 | "tx_bytes": 3956, 940 | "tx_packets": 41 941 | }, 942 | { 943 | "apps": [ 944 | 4, 945 | 3, 946 | 21 947 | ], 948 | "cat": 10, 949 | "rx_bytes": 5521562156, 950 | "rx_packets": 73080451, 951 | "tx_bytes": 179999321483, 952 | "tx_packets": 130627675 953 | }, 954 | { 955 | "apps": [ 956 | 209, 957 | 222, 958 | 7, 959 | 12, 960 | 84, 961 | 8 962 | ], 963 | "cat": 13, 964 | "rx_bytes": 24695320494, 965 | "rx_packets": 18622103, 966 | "tx_bytes": 2841579600, 967 | "tx_packets": 10056102 968 | }, 969 | { 970 | "apps": [ 971 | 106, 972 | 30, 973 | 63 974 | ], 975 | "cat": 18, 976 | "rx_bytes": 9582920, 977 | "rx_packets": 34817, 978 | "tx_bytes": 2849831, 979 | "tx_packets": 36464 980 | }, 981 | { 982 | "apps": [ 983 | 94 984 | ], 985 | "cat": 19, 986 | "rx_bytes": 1622602418, 987 | "rx_packets": 1760201, 988 | "tx_bytes": 349693010, 989 | "tx_packets": 2012708 990 | }, 991 | { 992 | "apps": [ 993 | 185, 994 | 168, 995 | 186 996 | ], 997 | "cat": 20, 998 | "rx_bytes": 29019321, 999 | "rx_packets": 209347, 1000 | "tx_bytes": 160917695, 1001 | "tx_packets": 1229543 1002 | }, 1003 | { 1004 | "apps": [ 1005 | 65535 1006 | ], 1007 | "cat": 255, 1008 | "rx_bytes": 183022079, 1009 | "rx_packets": 1798016, 1010 | "tx_bytes": 435832672, 1011 | "tx_packets": 1934359 1012 | } 1013 | ], 1014 | "initialized": "88121276686", 1015 | "is_ugw": True 1016 | } 1017 | ], 1018 | "has_eth1": True, 1019 | "has_porta": True, 1020 | "has_ssh_disable": True, 1021 | "has_vti": True, 1022 | "hostname": "pfSense", 1023 | "inform_url": "http://192.168.0.7:8080/inform", 1024 | "ip": "82.238.9.250", 1025 | "isolated": False, 1026 | "locating": False, 1027 | 'mac': gateway_lan_mac, 1028 | "model": "UGW3", 1029 | "model_display": "UniFi-Gateway-3", 1030 | "netmask": "255.255.248.0", 1031 | "required_version": "4.0.0", 1032 | "selfrun_beacon": True, 1033 | 'serial': gateway_lan_mac.replace(":", ""), 1034 | "pfor-stats": [ 1035 | { 1036 | "id": "596add99e4b0a76e35003e00", 1037 | "rx_bytes": 41444574, 1038 | "rx_packets": 305634, 1039 | "tx_bytes": 88048319, 1040 | "tx_packets": 364768 1041 | } 1042 | ], 1043 | "speedtest-status": { 1044 | "latency": 9, 1045 | "rundate": int(time.time()), 1046 | "runtime": 6, 1047 | "status_download": 2, 1048 | "status_ping": 2, 1049 | "status_summary": 2, 1050 | "status_upload": 2, 1051 | "xput_download": 385.30819702148, 1052 | "xput_upload": 68.445808410645 1053 | }, 1054 | "state": 2, 1055 | "system-stats": { 1056 | "cpu": '%s' % psutil.cpu_percent(), 1057 | "mem": '%s' % (100 - psutil.virtual_memory()[2]), 1058 | "uptime": '%s' % uptime() 1059 | }, 1060 | "time": int(time.time()), 1061 | "uplink": "eth0", 1062 | "uptime": uptime(), 1063 | "routes": [ 1064 | { 1065 | "nh": [ 1066 | { 1067 | "intf": "eth0", 1068 | "metric": "1/0", 1069 | "t": "S>*", 1070 | "via": "20.1.1.1" 1071 | } 1072 | ], 1073 | "pfx": "0.0.0.0/0" 1074 | }, 1075 | { 1076 | "nh": [ 1077 | { 1078 | "intf": "eth2", 1079 | "metric": "220/0", 1080 | "t": "S ", 1081 | "via": "10.1.1.1" 1082 | } 1083 | ], 1084 | "pfx": "0.0.0.0/0" 1085 | }, 1086 | { 1087 | "nh": [ 1088 | { 1089 | "intf": "eth2", 1090 | "metric": "1/0", 1091 | "t": "S " 1092 | } 1093 | ], 1094 | "pfx": "10.1.1.0/24" 1095 | }, 1096 | { 1097 | "nh": [ 1098 | { 1099 | "intf": "eth2", 1100 | "t": "C>*" 1101 | } 1102 | ], 1103 | "pfx": "10.1.1.0/24" 1104 | }, 1105 | { 1106 | "nh": [ 1107 | { 1108 | "intf": "lo", 1109 | "t": "C>*" 1110 | } 1111 | ], 1112 | "pfx": "127.0.0.0/8" 1113 | }, 1114 | { 1115 | "nh": [ 1116 | { 1117 | "intf": "eth1", 1118 | "t": "C>*" 1119 | } 1120 | ], 1121 | "pfx": "192.168.1.0/24" 1122 | }, 1123 | { 1124 | "nh": [ 1125 | { 1126 | "intf": "eth0", 1127 | "t": "C>*" 1128 | } 1129 | ], 1130 | "pfx": "20.1.1.0/21" 1131 | } 1132 | ], 1133 | "network_table": [ 1134 | { 1135 | "address": "192.168.1.1/24", 1136 | "addresses": [ 1137 | "%s/24" % gateway_lan_ip 1138 | ], 1139 | "autoneg": "true", 1140 | "duplex": "full", 1141 | "host_table": [ 1142 | { 1143 | "age": 0, 1144 | "authorized": True, 1145 | "bc_bytes": 4814073447, 1146 | "bc_packets": 104642338, 1147 | "dev_cat": 1, 1148 | "dev_family": 4, 1149 | "dev_id": 239, 1150 | "dev_vendor": 47, 1151 | "ip": "192.168.1.8", 1152 | "mac": "80:2a:a8:f0:ef:78", 1153 | "mc_bytes": 4814073447, 1154 | "mc_packets": 104642338, 1155 | "os_class": 15, 1156 | "os_name": 19, 1157 | "rx_bytes": 802239963372, 1158 | "rx_packets": 805925675, 1159 | "tx_bytes": 35371476651, 1160 | "tx_packets": 104136843, 1161 | "uptime": 5822032 1162 | }, 1163 | { 1164 | "age": 41, 1165 | "authorized": True, 1166 | "bc_bytes": 9202676, 1167 | "bc_packets": 200043, 1168 | "hostname": "switch", 1169 | "ip": "192.168.1.10", 1170 | "mac": "f0:9f:c2:09:2b:f2", 1171 | "mc_bytes": 21366640, 1172 | "mc_packets": 406211, 1173 | "rx_bytes": 30862046, 1174 | "rx_packets": 610310, 1175 | "tx_bytes": 13628015, 1176 | "tx_packets": 204110, 1177 | "uptime": 5821979 1178 | }, 1179 | { 1180 | "age": 8, 1181 | "authorized": True, 1182 | "bc_bytes": 2000, 1183 | "bc_packets": 3000, 1184 | "mac": "f0:9f:c2:09:2b:f3", 1185 | "mc_bytes": 21232297, 1186 | "mc_packets": 206139, 1187 | "rx_bytes": 21232297, 1188 | "rx_packets": 206139, 1189 | "tx_bytes": 4000, 1190 | "tx_packets": 5000, 1191 | "uptime": 5822017 1192 | } 1193 | ], 1194 | "l1up": "true", 1195 | "mac": "80:2a:a8:cd:a9:53", 1196 | "mtu": "1500", 1197 | "name": "eth1", 1198 | "speed": "1000", 1199 | "stats": { 1200 | "multicast": "412294", 1201 | "rx_bps": "342", 1202 | "rx_bytes": 52947224765, 1203 | "rx_dropped": 2800, 1204 | "rx_errors": 0, 1205 | "rx_multicast": 412314, 1206 | "rx_packets": 341232922, 1207 | "tx_bps": "250", 1208 | "tx_bytes": 792205417381, 1209 | "tx_dropped": 0, 1210 | "tx_errors": 0, 1211 | "tx_packets": 590930778 1212 | }, 1213 | "up": "true" 1214 | }, 1215 | { 1216 | "address": "20.1.2.10/21", 1217 | "addresses": [ 1218 | "20.1.2.10/21" 1219 | ], 1220 | "autoneg": "true", 1221 | "duplex": "full", 1222 | "gateways": [ 1223 | "20.1.1.1" 1224 | ], 1225 | "l1up": "true", 1226 | "mac": gateway_wan_mac, 1227 | "mtu": "1500", 1228 | "name": "eth0", 1229 | "nameservers": [ 1230 | gateway_lan_ip, 1231 | "212.27.40.240", 1232 | "212.27.40.241" 1233 | ], 1234 | "speed": "1000", 1235 | "stats": { 1236 | "multicast": "65627", 1237 | "rx_bps": "262", 1238 | "rx_bytes": 353519562926, 1239 | "rx_dropped": 19137, 1240 | "rx_errors": 0, 1241 | "rx_multicast": 65629, 1242 | "rx_packets": 645343103, 1243 | "tx_bps": "328", 1244 | "tx_bytes": 953646055362, 1245 | "tx_dropped": 0, 1246 | "tx_errors": 0, 1247 | "tx_packets": 863173990 1248 | }, 1249 | "up": "true" 1250 | } 1251 | ], 1252 | "if_table": [ 1253 | { 1254 | "drops": 333, 1255 | "enable": True, 1256 | "full_duplex": True, 1257 | "gateways": [ 1258 | gateway_lan_ip 1259 | ], 1260 | "ip": gateway_wan_ip, 1261 | "latency": randint(0, 200), 1262 | "mac": gateway_wan_mac, 1263 | "name": "eth0", 1264 | "nameservers": [ 1265 | gateway_lan_ip, 1266 | "212.27.40.240", 1267 | "212.27.40.241" 1268 | ], 1269 | "netmask": "255.255.255.0", 1270 | "num_port": 1, 1271 | "rx_bytes": 353519562926 + randint(0, 200000), 1272 | "rx_dropped": 19137 + randint(0, 2000), 1273 | "rx_errors": 0, 1274 | "rx_multicast": 65629 + randint(0, 2000), 1275 | "rx_packets": 645343103 + randint(0, 200000), 1276 | "speed": 1000, 1277 | "speedtest_lastrun": int(time.time()), 1278 | "speedtest_ping": randint(0, 2000), 1279 | "speedtest_status": "Idle", 1280 | "tx_bytes": 953646055362 + randint(0, 200000), 1281 | "tx_dropped": 0, 1282 | "tx_errors": 0, 1283 | "tx_packets": 863173990 + randint(0, 200000), 1284 | "up": True, 1285 | "uptime": uptime(), 1286 | "xput_down": randint(0, 100), 1287 | "xput_up": randint(0, 30) 1288 | }, 1289 | { 1290 | "enable": True, 1291 | "full_duplex": True, 1292 | "ip": gateway_lan_ip, 1293 | "mac": "80:2a:a8:cd:a9:53", 1294 | "name": "eth1", 1295 | "netmask": "255.255.255.0", 1296 | "num_port": 1, 1297 | "rx_bytes": 807912794876, 1298 | "rx_dropped": 2800, 1299 | "rx_errors": 0, 1300 | "rx_multicast": 412314, 1301 | "rx_packets": 700376545, 1302 | "speed": 1000, 1303 | "tx_bytes": 58901673253, 1304 | "tx_dropped": 0, 1305 | "tx_errors": 0, 1306 | "tx_packets": 347161831, 1307 | "up": True 1308 | }, 1309 | { 1310 | "enable": False, 1311 | "full_duplex": True, 1312 | "up": False 1313 | } 1314 | ], 1315 | 'version': '4.3.49.5001150', 1316 | }) 1317 | 1318 | 1319 | def send_inform(url, key, partial=False): 1320 | if not partial: 1321 | # value = json.dumps({'mac': mac2a((0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)), 'ip': ip2a((10, 0, 8, 2)), 'model': 'UGW3', 1322 | # 'model-display': 'UniFi-Gateway-3', 'inform_as_notif': 'true', 'default': 'false', 1323 | # 'hotsname': 'pfsense', 'isolated': 'false', 'locating': 'false', 'netmask': '255.255.255.0', 1324 | # 'version': '4.3.49.5001150', 'serial': mac2serial((0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)), 1325 | # 'uptime': uptime(), 'time': int(time.time()), "has_fan": False, "has_speaker": False, 1326 | # "discovery_response": False, "fw_caps": 3589, "general_temperature": 26, 1327 | # "guest_token": "FDE5188F48A10D22E4BE82A6A128C50G", "default": False, "board_rev": 3, 1328 | # 'cfgversion': cfg('_cfg', 'cfgversion'), 'config_network_wan': {'type': 'dhcp'}, 1329 | # 'required_version': '4.0.0', 'notif_reson': 'stun', 'notif_payload': '', 1330 | # 'inform_ip': '192.168.0.7', 'inform_url': 'http://192.168.0.7:8080/inform', 1331 | # 'license_state': 'registered', 'selfrun_beacon': True, 'overheating': False, 'state': 2, 1332 | # 'adopted': True, 'stp_priority': 32768, 'stream_token': '', 1333 | # 'ssh_session_table': [{'state': 'establish', 'uuid': '%s' % uuid.uuid1()}], 1334 | # 'sys_stats': {'loadavg_1': '%s' % load_average[0], 'loadavg_15': '%s' % load_average[1], 1335 | # 'loadavg_5': '%s' % load_average[2], 'mem_buffer': 0, 1336 | # 'mem_total': psutil.virtual_memory()[0], 'mem_used': psutil.virtual_memory()[1]}, 1337 | # 'system-stats': {'cpu': '%s' % psutil.cpu_percent(), 1338 | # 'mem': '%s' % (100 - psutil.virtual_memory()[2]), 'uptime': '%s' % uptime()}, 1339 | # 'port_table': [{'port_idx': 1, 'media': 'GE', 'port_poe': False, 'poe_caps': 0}, 1340 | # {'port_idx': 2, 'media': 'GE', 'port_poe': False, 'poe_caps': 0}, 1341 | # {'port_idx': 3, 'media': 'GE', 'port_poe': False, 'poe_caps': 0}], 1342 | # 'firewall': open('/tmp/cfg/system').readline()}) 1343 | value = create_complete_inform() 1344 | else: 1345 | value = json.dumps({ 1346 | 'mac': mac2a((0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)), 1347 | 'ip': ip2a((10, 0, 8, 2)), 1348 | 'model': 'UGW3', 1349 | 'model-display': 'UniFi-Gateway-3', 1350 | 'version': '4.3.49.5001150' 1351 | }) 1352 | 1353 | response = inform(url, a2b_hex(key), value) 1354 | 1355 | if response: 1356 | response = json.loads(response) 1357 | print('receive %s' % response) 1358 | if response['_type'] == 'setparam': 1359 | othercfg = '' 1360 | for key, val in response.items(): 1361 | if key.endswith('_cfg'): 1362 | cfg_replace(key[0:(len(key)-4)], val) 1363 | elif key != '_type' and key != 'server_time_in_utc' and key != 'mgmt_cfg': 1364 | othercfg += key + '=' + val + '\n' 1365 | cfg_replace('_cfg', othercfg) 1366 | 1367 | return int(response['interval']) if 'interval' in response else 5 1368 | 1369 | return 5 1370 | -------------------------------------------------------------------------------- /poc/inform_sniffer.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import json 3 | import struct 4 | 5 | import zlib 6 | from Crypto.Cipher import AES 7 | from binascii import a2b_hex 8 | from flask import Flask, request 9 | 10 | from inform import packet_decode 11 | 12 | app = Flask(__name__) 13 | 14 | 15 | @app.route("/inform", methods=['POST']) 16 | def inform(): 17 | data = request.get_data() 18 | 19 | payload = json.loads(packet_decode(a2b_hex("a09e428c482eb53c7731c224295cd9d3"), data)) 20 | print(payload) 21 | 22 | 23 | return '' 24 | 25 | 26 | 27 | #mca-ctrl -t connect -s "http://10.0.8.2:8080/inform" -k "A09E428C482EB53C7731C224295CD9D3" 28 | 29 | 30 | 31 | def print_bytearray(value): 32 | print([b for b in value]) 33 | 34 | app.run(debug=True, port=8080, host='10.0.8.2') 35 | -------------------------------------------------------------------------------- /poc/pool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import time 3 | 4 | from inform import cfg, send_inform 5 | 6 | 7 | url = cfg('log', 'url') 8 | key = cfg('log', 'key') 9 | 10 | print(url) 11 | print(key) 12 | 13 | while(True): 14 | interval = send_inform(url, key) 15 | print('new interval %s' % interval) 16 | time.sleep(interval) 17 | -------------------------------------------------------------------------------- /poc/real_inform_payload_exemple.json: -------------------------------------------------------------------------------- 1 | { 2 | "bootrom_version": "unknown", 3 | "cfgversion": "8fad50b7136e3f76", 4 | "config_network_wan": { 5 | "type": "dhcp" 6 | }, 7 | "config_network_wan2": { 8 | "dns1": "10.1.1.1", 9 | "gateway": "10.1.1.1", 10 | "ip": "10.1.1.10", 11 | "netmask": "255.255.255.0", 12 | "type": "static" 13 | }, 14 | "config_port_table": [ 15 | { 16 | "ifname": "eth0", 17 | "name": "wan" 18 | }, 19 | { 20 | "ifname": "eth1", 21 | "name": "lan" 22 | }, 23 | { 24 | "ifname": "eth2", 25 | "name": "wan2" 26 | } 27 | ], 28 | "connect_request_ip": "192.168.1.1", 29 | "connect_request_port": "36424", 30 | "ddns-status": { 31 | "dyndns": [ 32 | { 33 | "atime": 0, 34 | "host_name": "hostname", 35 | "ip": "20.1.2.3", 36 | "mtime": 1412958, 37 | "status": "good", 38 | "warned_min_error_interval": 0, 39 | "warned_min_interval": 0, 40 | "wtime": 30 41 | } 42 | ] 43 | }, 44 | "default": false, 45 | "discovery_response": false, 46 | "dpi-clients": [ 47 | "80:2a:a8:f0:ef:78" 48 | ], 49 | "dpi-stats": [ 50 | { 51 | "initialized": "94107792805", 52 | "mac": "80:2a:a8:f0:ef:78", 53 | "stats": [ 54 | { 55 | "app": 5, 56 | "cat": 3, 57 | "rx_bytes": 82297468, 58 | "rx_packets": 57565, 59 | "tx_bytes": 1710174, 60 | "tx_packets": 25324 61 | }, 62 | { 63 | "app": 94, 64 | "cat": 19, 65 | "rx_bytes": 1593846895, 66 | "rx_packets": 1738901, 67 | "tx_bytes": 348738675, 68 | "tx_packets": 2004045 69 | }, 70 | { 71 | "app": 133, 72 | "cat": 3, 73 | "rx_bytes": 531190, 74 | "rx_packets": 2465, 75 | "tx_bytes": 676859, 76 | "tx_packets": 2760 77 | }, 78 | { 79 | "app": 222, 80 | "cat": 13, 81 | "rx_bytes": 3441437, 82 | "rx_packets": 3033, 83 | "tx_bytes": 203173, 84 | "tx_packets": 1468 85 | }, 86 | { 87 | "app": 23, 88 | "cat": 0, 89 | "rx_bytes": 0, 90 | "rx_packets": 0, 91 | "tx_bytes": 145, 92 | "tx_packets": 2 93 | }, 94 | { 95 | "app": 7, 96 | "cat": 0, 97 | "rx_bytes": 0, 98 | "rx_packets": 0, 99 | "tx_bytes": 145, 100 | "tx_packets": 2 101 | }, 102 | { 103 | "app": 7, 104 | "cat": 13, 105 | "rx_bytes": 24417806554, 106 | "rx_packets": 18415873, 107 | "tx_bytes": 2817966897, 108 | "tx_packets": 9910192 109 | }, 110 | { 111 | "app": 185, 112 | "cat": 20, 113 | "rx_bytes": 28812050, 114 | "rx_packets": 208945, 115 | "tx_bytes": 160819147, 116 | "tx_packets": 1228992 117 | }, 118 | { 119 | "app": 65535, 120 | "cat": 255, 121 | "rx_bytes": 182029551, 122 | "rx_packets": 1796815, 123 | "tx_bytes": 435732626, 124 | "tx_packets": 1933469 125 | }, 126 | { 127 | "app": 4, 128 | "cat": 10, 129 | "rx_bytes": 1522, 130 | "rx_packets": 20, 131 | "tx_bytes": 882, 132 | "tx_packets": 12 133 | }, 134 | { 135 | "app": 106, 136 | "cat": 18, 137 | "rx_bytes": 982710, 138 | "rx_packets": 10919, 139 | "tx_bytes": 1010970, 140 | "tx_packets": 11233 141 | }, 142 | { 143 | "app": 30, 144 | "cat": 18, 145 | "rx_bytes": 7819852, 146 | "rx_packets": 20378, 147 | "tx_bytes": 1293104, 148 | "tx_packets": 18686 149 | }, 150 | { 151 | "app": 1, 152 | "cat": 0, 153 | "rx_bytes": 0, 154 | "rx_packets": 0, 155 | "tx_bytes": 145, 156 | "tx_packets": 2 157 | }, 158 | { 159 | "app": 63, 160 | "cat": 18, 161 | "rx_bytes": 780358, 162 | "rx_packets": 3520, 163 | "tx_bytes": 545757, 164 | "tx_packets": 6545 165 | }, 166 | { 167 | "app": 8, 168 | "cat": 13, 169 | "rx_bytes": 180691586, 170 | "rx_packets": 132204, 171 | "tx_bytes": 5970383, 172 | "tx_packets": 74482 173 | }, 174 | { 175 | "app": 21, 176 | "cat": 10, 177 | "rx_bytes": 5521547718, 178 | "rx_packets": 73080390, 179 | "tx_bytes": 179999309100, 180 | "tx_packets": 130627577 181 | } 182 | ] 183 | } 184 | ], 185 | "dpi-stats-table": [ 186 | { 187 | "_id": "5875d9f9e4b02fd3851c55e4", 188 | "_subid": "5875d9f5e4b02fd3851c55d8", 189 | "by_app": [ 190 | { 191 | "app": 5, 192 | "cat": 3, 193 | "rx_bytes": 2652, 194 | "rx_packets": 4, 195 | "tx_bytes": 1797, 196 | "tx_packets": 7 197 | }, 198 | { 199 | "app": 94, 200 | "cat": 19, 201 | "rx_bytes": 9010458, 202 | "rx_packets": 6977, 203 | "tx_bytes": 518163, 204 | "tx_packets": 3533 205 | }, 206 | { 207 | "app": 209, 208 | "cat": 13, 209 | "rx_bytes": 39303, 210 | "rx_packets": 90, 211 | "tx_bytes": 17744, 212 | "tx_packets": 78 213 | }, 214 | { 215 | "app": 10, 216 | "cat": 4, 217 | "rx_bytes": 15273, 218 | "rx_packets": 15, 219 | "tx_bytes": 2728, 220 | "tx_packets": 23 221 | }, 222 | { 223 | "app": 7, 224 | "cat": 13, 225 | "rx_bytes": 369394, 226 | "rx_packets": 293, 227 | "tx_bytes": 24904, 228 | "tx_packets": 244 229 | }, 230 | { 231 | "app": 185, 232 | "cat": 20, 233 | "rx_bytes": 62070, 234 | "rx_packets": 130, 235 | "tx_bytes": 27219, 236 | "tx_packets": 169 237 | }, 238 | { 239 | "app": 65535, 240 | "cat": 255, 241 | "rx_bytes": 976848, 242 | "rx_packets": 1027, 243 | "tx_bytes": 77317, 244 | "tx_packets": 695 245 | }, 246 | { 247 | "app": 12, 248 | "cat": 13, 249 | "rx_bytes": 92924774, 250 | "rx_packets": 70496, 251 | "tx_bytes": 17360339, 252 | "tx_packets": 69509 253 | }, 254 | { 255 | "app": 150, 256 | "cat": 3, 257 | "rx_bytes": 54609, 258 | "rx_packets": 71, 259 | "tx_bytes": 19749, 260 | "tx_packets": 85 261 | }, 262 | { 263 | "app": 95, 264 | "cat": 5, 265 | "rx_bytes": 9835, 266 | "rx_packets": 41, 267 | "tx_bytes": 3956, 268 | "tx_packets": 41 269 | }, 270 | { 271 | "app": 168, 272 | "cat": 20, 273 | "rx_bytes": 100049, 274 | "rx_packets": 198, 275 | "tx_bytes": 60396, 276 | "tx_packets": 275 277 | }, 278 | { 279 | "app": 3, 280 | "cat": 10, 281 | "rx_bytes": 12538, 282 | "rx_packets": 36, 283 | "tx_bytes": 10607, 284 | "tx_packets": 75 285 | }, 286 | { 287 | "app": 84, 288 | "cat": 3, 289 | "rx_bytes": 45115, 290 | "rx_packets": 135, 291 | "tx_bytes": 91866, 292 | "tx_packets": 158 293 | }, 294 | { 295 | "app": 84, 296 | "cat": 13, 297 | "rx_bytes": 42563, 298 | "rx_packets": 102, 299 | "tx_bytes": 32676, 300 | "tx_packets": 113 301 | }, 302 | { 303 | "app": 186, 304 | "cat": 20, 305 | "rx_bytes": 44618, 306 | "rx_packets": 68, 307 | "tx_bytes": 8826, 308 | "tx_packets": 86 309 | } 310 | ], 311 | "by_cat": [ 312 | { 313 | "apps": [ 314 | 5, 315 | 150, 316 | 84 317 | ], 318 | "cat": 3, 319 | "rx_bytes": 102376, 320 | "rx_packets": 210, 321 | "tx_bytes": 113412, 322 | "tx_packets": 250 323 | }, 324 | { 325 | "apps": [ 326 | 10 327 | ], 328 | "cat": 4, 329 | "rx_bytes": 15273, 330 | "rx_packets": 15, 331 | "tx_bytes": 2728, 332 | "tx_packets": 23 333 | }, 334 | { 335 | "apps": [ 336 | 95 337 | ], 338 | "cat": 5, 339 | "rx_bytes": 9835, 340 | "rx_packets": 41, 341 | "tx_bytes": 3956, 342 | "tx_packets": 41 343 | }, 344 | { 345 | "apps": [ 346 | 3 347 | ], 348 | "cat": 10, 349 | "rx_bytes": 12538, 350 | "rx_packets": 36, 351 | "tx_bytes": 10607, 352 | "tx_packets": 75 353 | }, 354 | { 355 | "apps": [ 356 | 209, 357 | 7, 358 | 12, 359 | 84 360 | ], 361 | "cat": 13, 362 | "rx_bytes": 93376034, 363 | "rx_packets": 70981, 364 | "tx_bytes": 17435663, 365 | "tx_packets": 69944 366 | }, 367 | { 368 | "apps": [ 369 | 94 370 | ], 371 | "cat": 19, 372 | "rx_bytes": 9010458, 373 | "rx_packets": 6977, 374 | "tx_bytes": 518163, 375 | "tx_packets": 3533 376 | }, 377 | { 378 | "apps": [ 379 | 185, 380 | 168, 381 | 186 382 | ], 383 | "cat": 20, 384 | "rx_bytes": 206737, 385 | "rx_packets": 396, 386 | "tx_bytes": 96441, 387 | "tx_packets": 530 388 | }, 389 | { 390 | "apps": [ 391 | 65535 392 | ], 393 | "cat": 255, 394 | "rx_bytes": 976848, 395 | "rx_packets": 1027, 396 | "tx_bytes": 77317, 397 | "tx_packets": 695 398 | } 399 | ], 400 | "initialized": "88122111307" 401 | }, 402 | { 403 | "_id": "5875d9f9e4b02fd3851c55e4", 404 | "_subid": "5875e1f8e4b0ba28be0f8335", 405 | "by_app": [ 406 | { 407 | "app": 5, 408 | "cat": 3, 409 | "clients": [ 410 | { 411 | "mac": "80:2a:a8:f0:ef:78", 412 | "rx_bytes": 82297468, 413 | "rx_packets": 57565, 414 | "tx_bytes": 1710174, 415 | "tx_packets": 25324 416 | } 417 | ], 418 | "known_clients": 1, 419 | "rx_bytes": 82300120, 420 | "rx_packets": 57569, 421 | "tx_bytes": 1711971, 422 | "tx_packets": 25331 423 | }, 424 | { 425 | "app": 94, 426 | "cat": 19, 427 | "clients": [ 428 | { 429 | "mac": "80:2a:a8:f0:ef:78", 430 | "rx_bytes": 1593846895, 431 | "rx_packets": 1738901, 432 | "tx_bytes": 348738675, 433 | "tx_packets": 2004045 434 | } 435 | ], 436 | "known_clients": 1, 437 | "rx_bytes": 1622602418, 438 | "rx_packets": 1760201, 439 | "tx_bytes": 349693010, 440 | "tx_packets": 2012708 441 | }, 442 | { 443 | "app": 209, 444 | "cat": 13, 445 | "rx_bytes": 43670, 446 | "rx_packets": 100, 447 | "tx_bytes": 20728, 448 | "tx_packets": 91 449 | }, 450 | { 451 | "app": 10, 452 | "cat": 4, 453 | "rx_bytes": 15273, 454 | "rx_packets": 15, 455 | "tx_bytes": 2728, 456 | "tx_packets": 23 457 | }, 458 | { 459 | "app": 133, 460 | "cat": 3, 461 | "clients": [ 462 | { 463 | "mac": "80:2a:a8:f0:ef:78", 464 | "rx_bytes": 531190, 465 | "rx_packets": 2465, 466 | "tx_bytes": 676859, 467 | "tx_packets": 2760 468 | } 469 | ], 470 | "known_clients": 1, 471 | "rx_bytes": 531190, 472 | "rx_packets": 2465, 473 | "tx_bytes": 676859, 474 | "tx_packets": 2760 475 | }, 476 | { 477 | "app": 222, 478 | "cat": 13, 479 | "clients": [ 480 | { 481 | "mac": "80:2a:a8:f0:ef:78", 482 | "rx_bytes": 3441437, 483 | "rx_packets": 3033, 484 | "tx_bytes": 203173, 485 | "tx_packets": 1468 486 | } 487 | ], 488 | "known_clients": 1, 489 | "rx_bytes": 3441437, 490 | "rx_packets": 3033, 491 | "tx_bytes": 203173, 492 | "tx_packets": 1468 493 | }, 494 | { 495 | "app": 23, 496 | "cat": 0, 497 | "clients": [ 498 | { 499 | "mac": "80:2a:a8:f0:ef:78", 500 | "rx_bytes": 0, 501 | "rx_packets": 0, 502 | "tx_bytes": 145, 503 | "tx_packets": 2 504 | } 505 | ], 506 | "known_clients": 1, 507 | "rx_bytes": 0, 508 | "rx_packets": 0, 509 | "tx_bytes": 145, 510 | "tx_packets": 2 511 | }, 512 | { 513 | "app": 7, 514 | "cat": 0, 515 | "clients": [ 516 | { 517 | "mac": "80:2a:a8:f0:ef:78", 518 | "rx_bytes": 0, 519 | "rx_packets": 0, 520 | "tx_bytes": 145, 521 | "tx_packets": 2 522 | } 523 | ], 524 | "known_clients": 1, 525 | "rx_bytes": 0, 526 | "rx_packets": 0, 527 | "tx_bytes": 145, 528 | "tx_packets": 2 529 | }, 530 | { 531 | "app": 7, 532 | "cat": 13, 533 | "clients": [ 534 | { 535 | "mac": "80:2a:a8:f0:ef:78", 536 | "rx_bytes": 24417806554, 537 | "rx_packets": 18415873, 538 | "tx_bytes": 2817966897, 539 | "tx_packets": 9910192 540 | } 541 | ], 542 | "known_clients": 1, 543 | "rx_bytes": 24418175948, 544 | "rx_packets": 18416166, 545 | "tx_bytes": 2817991801, 546 | "tx_packets": 9910436 547 | }, 548 | { 549 | "app": 185, 550 | "cat": 20, 551 | "clients": [ 552 | { 553 | "mac": "80:2a:a8:f0:ef:78", 554 | "rx_bytes": 28812050, 555 | "rx_packets": 208945, 556 | "tx_bytes": 160819147, 557 | "tx_packets": 1228992 558 | } 559 | ], 560 | "known_clients": 1, 561 | "rx_bytes": 28874120, 562 | "rx_packets": 209075, 563 | "tx_bytes": 160846366, 564 | "tx_packets": 1229161 565 | }, 566 | { 567 | "app": 65535, 568 | "cat": 255, 569 | "clients": [ 570 | { 571 | "mac": "80:2a:a8:f0:ef:78", 572 | "rx_bytes": 182029551, 573 | "rx_packets": 1796815, 574 | "tx_bytes": 435732626, 575 | "tx_packets": 1933469 576 | } 577 | ], 578 | "known_clients": 1, 579 | "rx_bytes": 183022079, 580 | "rx_packets": 1798016, 581 | "tx_bytes": 435832672, 582 | "tx_packets": 1934359 583 | }, 584 | { 585 | "app": 12, 586 | "cat": 13, 587 | "rx_bytes": 92925290, 588 | "rx_packets": 70498, 589 | "tx_bytes": 17360839, 590 | "tx_packets": 69512 591 | }, 592 | { 593 | "app": 4, 594 | "cat": 10, 595 | "clients": [ 596 | { 597 | "mac": "80:2a:a8:f0:ef:78", 598 | "rx_bytes": 1522, 599 | "rx_packets": 20, 600 | "tx_bytes": 882, 601 | "tx_packets": 12 602 | } 603 | ], 604 | "known_clients": 1, 605 | "rx_bytes": 1522, 606 | "rx_packets": 20, 607 | "tx_bytes": 882, 608 | "tx_packets": 12 609 | }, 610 | { 611 | "app": 106, 612 | "cat": 18, 613 | "clients": [ 614 | { 615 | "mac": "80:2a:a8:f0:ef:78", 616 | "rx_bytes": 982710, 617 | "rx_packets": 10919, 618 | "tx_bytes": 1010970, 619 | "tx_packets": 11233 620 | } 621 | ], 622 | "known_clients": 1, 623 | "rx_bytes": 982710, 624 | "rx_packets": 10919, 625 | "tx_bytes": 1010970, 626 | "tx_packets": 11233 627 | }, 628 | { 629 | "app": 30, 630 | "cat": 18, 631 | "clients": [ 632 | { 633 | "mac": "80:2a:a8:f0:ef:78", 634 | "rx_bytes": 7819852, 635 | "rx_packets": 20378, 636 | "tx_bytes": 1293104, 637 | "tx_packets": 18686 638 | } 639 | ], 640 | "known_clients": 1, 641 | "rx_bytes": 7819852, 642 | "rx_packets": 20378, 643 | "tx_bytes": 1293104, 644 | "tx_packets": 18686 645 | }, 646 | { 647 | "app": 1, 648 | "cat": 0, 649 | "clients": [ 650 | { 651 | "mac": "80:2a:a8:f0:ef:78", 652 | "rx_bytes": 0, 653 | "rx_packets": 0, 654 | "tx_bytes": 145, 655 | "tx_packets": 2 656 | } 657 | ], 658 | "known_clients": 1, 659 | "rx_bytes": 0, 660 | "rx_packets": 0, 661 | "tx_bytes": 145, 662 | "tx_packets": 2 663 | }, 664 | { 665 | "app": 150, 666 | "cat": 3, 667 | "rx_bytes": 54609, 668 | "rx_packets": 71, 669 | "tx_bytes": 19749, 670 | "tx_packets": 85 671 | }, 672 | { 673 | "app": 95, 674 | "cat": 5, 675 | "rx_bytes": 9835, 676 | "rx_packets": 41, 677 | "tx_bytes": 3956, 678 | "tx_packets": 41 679 | }, 680 | { 681 | "app": 168, 682 | "cat": 20, 683 | "rx_bytes": 100583, 684 | "rx_packets": 204, 685 | "tx_bytes": 62503, 686 | "tx_packets": 296 687 | }, 688 | { 689 | "app": 3, 690 | "cat": 10, 691 | "rx_bytes": 12916, 692 | "rx_packets": 41, 693 | "tx_bytes": 11501, 694 | "tx_packets": 86 695 | }, 696 | { 697 | "app": 84, 698 | "cat": 13, 699 | "rx_bytes": 42563, 700 | "rx_packets": 102, 701 | "tx_bytes": 32676, 702 | "tx_packets": 113 703 | }, 704 | { 705 | "app": 84, 706 | "cat": 3, 707 | "rx_bytes": 62456, 708 | "rx_packets": 166, 709 | "tx_bytes": 101105, 710 | "tx_packets": 183 711 | }, 712 | { 713 | "app": 63, 714 | "cat": 18, 715 | "clients": [ 716 | { 717 | "mac": "80:2a:a8:f0:ef:78", 718 | "rx_bytes": 780358, 719 | "rx_packets": 3520, 720 | "tx_bytes": 545757, 721 | "tx_packets": 6545 722 | } 723 | ], 724 | "known_clients": 1, 725 | "rx_bytes": 780358, 726 | "rx_packets": 3520, 727 | "tx_bytes": 545757, 728 | "tx_packets": 6545 729 | }, 730 | { 731 | "app": 8, 732 | "cat": 13, 733 | "clients": [ 734 | { 735 | "mac": "80:2a:a8:f0:ef:78", 736 | "rx_bytes": 180691586, 737 | "rx_packets": 132204, 738 | "tx_bytes": 5970383, 739 | "tx_packets": 74482 740 | } 741 | ], 742 | "known_clients": 1, 743 | "rx_bytes": 180691586, 744 | "rx_packets": 132204, 745 | "tx_bytes": 5970383, 746 | "tx_packets": 74482 747 | }, 748 | { 749 | "app": 186, 750 | "cat": 20, 751 | "rx_bytes": 44618, 752 | "rx_packets": 68, 753 | "tx_bytes": 8826, 754 | "tx_packets": 86 755 | }, 756 | { 757 | "app": 21, 758 | "cat": 10, 759 | "clients": [ 760 | { 761 | "mac": "80:2a:a8:f0:ef:78", 762 | "rx_bytes": 5521547718, 763 | "rx_packets": 73080390, 764 | "tx_bytes": 179999309100, 765 | "tx_packets": 130627577 766 | } 767 | ], 768 | "known_clients": 1, 769 | "rx_bytes": 5521547718, 770 | "rx_packets": 73080390, 771 | "tx_bytes": 179999309100, 772 | "tx_packets": 130627577 773 | } 774 | ], 775 | "by_cat": [ 776 | { 777 | "apps": [ 778 | 23, 779 | 7, 780 | 1 781 | ], 782 | "cat": 0, 783 | "rx_bytes": 0, 784 | "rx_packets": 0, 785 | "tx_bytes": 435, 786 | "tx_packets": 6 787 | }, 788 | { 789 | "apps": [ 790 | 5, 791 | 133, 792 | 150, 793 | 84 794 | ], 795 | "cat": 3, 796 | "rx_bytes": 82948375, 797 | "rx_packets": 60271, 798 | "tx_bytes": 2509684, 799 | "tx_packets": 28359 800 | }, 801 | { 802 | "apps": [ 803 | 10 804 | ], 805 | "cat": 4, 806 | "rx_bytes": 15273, 807 | "rx_packets": 15, 808 | "tx_bytes": 2728, 809 | "tx_packets": 23 810 | }, 811 | { 812 | "apps": [ 813 | 95 814 | ], 815 | "cat": 5, 816 | "rx_bytes": 9835, 817 | "rx_packets": 41, 818 | "tx_bytes": 3956, 819 | "tx_packets": 41 820 | }, 821 | { 822 | "apps": [ 823 | 4, 824 | 3, 825 | 21 826 | ], 827 | "cat": 10, 828 | "rx_bytes": 5521562156, 829 | "rx_packets": 73080451, 830 | "tx_bytes": 179999321483, 831 | "tx_packets": 130627675 832 | }, 833 | { 834 | "apps": [ 835 | 209, 836 | 222, 837 | 7, 838 | 12, 839 | 84, 840 | 8 841 | ], 842 | "cat": 13, 843 | "rx_bytes": 24695320494, 844 | "rx_packets": 18622103, 845 | "tx_bytes": 2841579600, 846 | "tx_packets": 10056102 847 | }, 848 | { 849 | "apps": [ 850 | 106, 851 | 30, 852 | 63 853 | ], 854 | "cat": 18, 855 | "rx_bytes": 9582920, 856 | "rx_packets": 34817, 857 | "tx_bytes": 2849831, 858 | "tx_packets": 36464 859 | }, 860 | { 861 | "apps": [ 862 | 94 863 | ], 864 | "cat": 19, 865 | "rx_bytes": 1622602418, 866 | "rx_packets": 1760201, 867 | "tx_bytes": 349693010, 868 | "tx_packets": 2012708 869 | }, 870 | { 871 | "apps": [ 872 | 185, 873 | 168, 874 | 186 875 | ], 876 | "cat": 20, 877 | "rx_bytes": 29019321, 878 | "rx_packets": 209347, 879 | "tx_bytes": 160917695, 880 | "tx_packets": 1229543 881 | }, 882 | { 883 | "apps": [ 884 | 65535 885 | ], 886 | "cat": 255, 887 | "rx_bytes": 183022079, 888 | "rx_packets": 1798016, 889 | "tx_bytes": 435832672, 890 | "tx_packets": 1934359 891 | } 892 | ], 893 | "initialized": "88121276686", 894 | "is_ugw": true 895 | } 896 | ], 897 | "fw_caps": 3, 898 | "guest_token": "4C1D46707239C6EB5A2366F505A44A91", 899 | "has_default_route_distance": true, 900 | "has_dnsmasq_hostfile_update": true, 901 | "has_dpi": true, 902 | "has_eth1": true, 903 | "has_porta": true, 904 | "has_ssh_disable": true, 905 | "has_vti": true, 906 | "hostname": "usg", 907 | "if_table": [ 908 | { 909 | "drops": 333, 910 | "enable": true, 911 | "full_duplex": true, 912 | "gateways": [ 913 | "20.1.2.3" 914 | ], 915 | "ip": "20.1.2.40", 916 | "latency": 11, 917 | "mac": "80:2a:a8:cd:a9:52", 918 | "name": "eth0", 919 | "nameservers": [ 920 | "20.1.2.19", 921 | "20.1.3.19" 922 | ], 923 | "netmask": "255.255.248.0", 924 | "num_port": 1, 925 | "rx_bytes": 353519562926, 926 | "rx_dropped": 19137, 927 | "rx_errors": 0, 928 | "rx_multicast": 65629, 929 | "rx_packets": 645343103, 930 | "speed": 1000, 931 | "speedtest_lastrun": 1504930035, 932 | "speedtest_ping": 68, 933 | "speedtest_status": "Idle", 934 | "tx_bytes": 953646055362, 935 | "tx_dropped": 0, 936 | "tx_errors": 0, 937 | "tx_packets": 863173990, 938 | "up": true, 939 | "uptime": 37193, 940 | "xput_down": 38.161000000000001, 941 | "xput_up": 12.484999999999999 942 | }, 943 | { 944 | "enable": true, 945 | "full_duplex": true, 946 | "ip": "192.168.1.1", 947 | "mac": "80:2a:a8:cd:a9:53", 948 | "name": "eth1", 949 | "netmask": "255.255.255.0", 950 | "num_port": 1, 951 | "rx_bytes": 807912794876, 952 | "rx_dropped": 2800, 953 | "rx_errors": 0, 954 | "rx_multicast": 412314, 955 | "rx_packets": 700376545, 956 | "speed": 1000, 957 | "tx_bytes": 58901673253, 958 | "tx_dropped": 0, 959 | "tx_errors": 0, 960 | "tx_packets": 347161831, 961 | "up": true 962 | }, 963 | { 964 | "enable": true, 965 | "full_duplex": true, 966 | "gateways": [ 967 | "20.1.2.1" 968 | ], 969 | "ip": "10.1.1.10", 970 | "mac": "80:2a:a8:cd:a9:54", 971 | "name": "eth2", 972 | "nameservers": [ 973 | "20.1.2.19", 974 | "20.1.3.19" 975 | ], 976 | "netmask": "255.255.255.0", 977 | "num_port": 1, 978 | "rx_bytes": 118162997, 979 | "rx_dropped": 1, 980 | "rx_errors": 0, 981 | "rx_multicast": 65629, 982 | "rx_packets": 1126891, 983 | "speed": 1000, 984 | "tx_bytes": 77684158, 985 | "tx_dropped": 0, 986 | "tx_errors": 0, 987 | "tx_packets": 1025525, 988 | "up": true 989 | } 990 | ], 991 | "inform_url": "http://192.168.1.8:8080/inform", 992 | "ip": "20.1.2.40", 993 | "isolated": false, 994 | "locating": false, 995 | "mac": "80:2a:a8:cd:a9:52", 996 | "model": "UGW3", 997 | "model_display": "UniFi-Gateway-3", 998 | "netmask": "255.255.248.0", 999 | "network_table": [ 1000 | { 1001 | "address": "10.1.1.10/24", 1002 | "addresses": [ 1003 | "10.1.1.10/24" 1004 | ], 1005 | "autoneg": "true", 1006 | "duplex": "full", 1007 | "gateways": [ 1008 | "20.1.2.1" 1009 | ], 1010 | "l1up": "true", 1011 | "mac": "80:2a:a8:cd:a9:54", 1012 | "mtu": "1500", 1013 | "name": "eth2", 1014 | "nameservers": [ 1015 | "20.1.2.191", 1016 | "20.1.3.191" 1017 | ], 1018 | "speed": "1000", 1019 | "stats": { 1020 | "multicast": "65627", 1021 | "rx_bps": "0", 1022 | "rx_bytes": 118162997, 1023 | "rx_dropped": 1, 1024 | "rx_errors": 0, 1025 | "rx_multicast": 65629, 1026 | "rx_packets": 1126891, 1027 | "tx_bps": "0", 1028 | "tx_bytes": 77684158, 1029 | "tx_dropped": 0, 1030 | "tx_errors": 0, 1031 | "tx_packets": 1025525 1032 | }, 1033 | "up": "true" 1034 | }, 1035 | { 1036 | "address": "192.168.1.1/24", 1037 | "addresses": [ 1038 | "192.168.1.1/24" 1039 | ], 1040 | "autoneg": "true", 1041 | "duplex": "full", 1042 | "host_table": [ 1043 | { 1044 | "age": 0, 1045 | "authorized": true, 1046 | "bc_bytes": 4814073447, 1047 | "bc_packets": 104642338, 1048 | "dev_cat": 1, 1049 | "dev_family": 4, 1050 | "dev_id": 239, 1051 | "dev_vendor": 47, 1052 | "ip": "192.168.1.8", 1053 | "mac": "80:2a:a8:f0:ef:78", 1054 | "mc_bytes": 4814073447, 1055 | "mc_packets": 104642338, 1056 | "os_class": 15, 1057 | "os_name": 19, 1058 | "rx_bytes": 802239963372, 1059 | "rx_packets": 805925675, 1060 | "tx_bytes": 35371476651, 1061 | "tx_packets": 104136843, 1062 | "uptime": 5822032 1063 | }, 1064 | { 1065 | "age": 41, 1066 | "authorized": true, 1067 | "bc_bytes": 9202676, 1068 | "bc_packets": 200043, 1069 | "hostname": "switch", 1070 | "ip": "192.168.1.10", 1071 | "mac": "f0:9f:c2:09:2b:f2", 1072 | "mc_bytes": 21366640, 1073 | "mc_packets": 406211, 1074 | "rx_bytes": 30862046, 1075 | "rx_packets": 610310, 1076 | "tx_bytes": 13628015, 1077 | "tx_packets": 204110, 1078 | "uptime": 5821979 1079 | }, 1080 | { 1081 | "age": 8, 1082 | "authorized": true, 1083 | "bc_bytes": 0, 1084 | "bc_packets": 0, 1085 | "mac": "f0:9f:c2:09:2b:f3", 1086 | "mc_bytes": 21232297, 1087 | "mc_packets": 206139, 1088 | "rx_bytes": 21232297, 1089 | "rx_packets": 206139, 1090 | "tx_bytes": 0, 1091 | "tx_packets": 0, 1092 | "uptime": 5822017 1093 | } 1094 | ], 1095 | "l1up": "true", 1096 | "mac": "80:2a:a8:cd:a9:53", 1097 | "mtu": "1500", 1098 | "name": "eth1", 1099 | "speed": "1000", 1100 | "stats": { 1101 | "multicast": "412294", 1102 | "rx_bps": "342", 1103 | "rx_bytes": 52947224765, 1104 | "rx_dropped": 2800, 1105 | "rx_errors": 0, 1106 | "rx_multicast": 412314, 1107 | "rx_packets": 341232922, 1108 | "tx_bps": "250", 1109 | "tx_bytes": 792205417381, 1110 | "tx_dropped": 0, 1111 | "tx_errors": 0, 1112 | "tx_packets": 590930778 1113 | }, 1114 | "up": "true" 1115 | }, 1116 | { 1117 | "address": "20.1.2.10/21", 1118 | "addresses": [ 1119 | "20.1.2.10/21" 1120 | ], 1121 | "autoneg": "true", 1122 | "duplex": "full", 1123 | "gateways": [ 1124 | "20.1.1.1" 1125 | ], 1126 | "l1up": "true", 1127 | "mac": "80:2a:a8:cd:a9:52", 1128 | "mtu": "1500", 1129 | "name": "eth0", 1130 | "nameservers": [ 1131 | "20.1.2.1", 1132 | "20.1.2.11" 1133 | ], 1134 | "speed": "1000", 1135 | "stats": { 1136 | "multicast": "65627", 1137 | "rx_bps": "262", 1138 | "rx_bytes": 353519562926, 1139 | "rx_dropped": 19137, 1140 | "rx_errors": 0, 1141 | "rx_multicast": 65629, 1142 | "rx_packets": 645343103, 1143 | "tx_bps": "328", 1144 | "tx_bytes": 953646055362, 1145 | "tx_dropped": 0, 1146 | "tx_errors": 0, 1147 | "tx_packets": 863173990 1148 | }, 1149 | "up": "true" 1150 | } 1151 | ], 1152 | "pfor-stats": [ 1153 | { 1154 | "id": "596add99e4b0a76e35003e00", 1155 | "rx_bytes": 41444574, 1156 | "rx_packets": 305634, 1157 | "tx_bytes": 88048319, 1158 | "tx_packets": 364768 1159 | } 1160 | ], 1161 | "radius_caps": 1, 1162 | "required_version": "4.0.0", 1163 | "routes": [ 1164 | { 1165 | "nh": [ 1166 | { 1167 | "intf": "eth0", 1168 | "metric": "1/0", 1169 | "t": "S>*", 1170 | "via": "20.1.1.1" 1171 | } 1172 | ], 1173 | "pfx": "0.0.0.0/0" 1174 | }, 1175 | { 1176 | "nh": [ 1177 | { 1178 | "intf": "eth2", 1179 | "metric": "220/0", 1180 | "t": "S ", 1181 | "via": "10.1.1.1" 1182 | } 1183 | ], 1184 | "pfx": "0.0.0.0/0" 1185 | }, 1186 | { 1187 | "nh": [ 1188 | { 1189 | "intf": "eth2", 1190 | "metric": "1/0", 1191 | "t": "S " 1192 | } 1193 | ], 1194 | "pfx": "10.1.1.0/24" 1195 | }, 1196 | { 1197 | "nh": [ 1198 | { 1199 | "intf": "eth2", 1200 | "t": "C>*" 1201 | } 1202 | ], 1203 | "pfx": "10.1.1.0/24" 1204 | }, 1205 | { 1206 | "nh": [ 1207 | { 1208 | "intf": "lo", 1209 | "t": "C>*" 1210 | } 1211 | ], 1212 | "pfx": "127.0.0.0/8" 1213 | }, 1214 | { 1215 | "nh": [ 1216 | { 1217 | "intf": "eth1", 1218 | "t": "C>*" 1219 | } 1220 | ], 1221 | "pfx": "192.168.1.0/24" 1222 | }, 1223 | { 1224 | "nh": [ 1225 | { 1226 | "intf": "eth0", 1227 | "t": "C>*" 1228 | } 1229 | ], 1230 | "pfx": "20.1.1.0/21" 1231 | } 1232 | ], 1233 | "selfrun_beacon": true, 1234 | "serial": "802AA8CDA952", 1235 | "speedtest-status": { 1236 | "latency": 0, 1237 | "rundate": 0, 1238 | "runtime": 0, 1239 | "status_download": 0, 1240 | "status_ping": 1, 1241 | "status_summary": 1, 1242 | "status_upload": 0, 1243 | "xput_download": 0.0, 1244 | "xput_upload": 0.0 1245 | }, 1246 | "state": 2, 1247 | "system-stats": { 1248 | "cpu": "8", 1249 | "mem": "24", 1250 | "uptime": "6251317" 1251 | }, 1252 | "time": 1508244980, 1253 | "uplink": "eth0", 1254 | "uptime": 6251621, 1255 | "version": "4.3.49.5001150", 1256 | "vpn": { 1257 | "ipsec": { 1258 | "sa": [ 1259 | { 1260 | "active_time": 0, 1261 | "connect_id": "peer-1.2.3.4-tunnel-0", 1262 | "in_bytes": "n/a", 1263 | "lifetime": 0, 1264 | "local_id": "n/a", 1265 | "local_ip": "n/a", 1266 | "nat_t": false, 1267 | "out_bytes": "n/a", 1268 | "peer_id": "1.2.3.4", 1269 | "remote_id": "n/a", 1270 | "remote_ip": "n/a", 1271 | "state": "down" 1272 | }, 1273 | { 1274 | "active_time": 0, 1275 | "connect_id": "peer-1.2.3.4-tunnel-1", 1276 | "in_bytes": "n/a", 1277 | "lifetime": 0, 1278 | "local_id": "n/a", 1279 | "local_ip": "n/a", 1280 | "nat_t": false, 1281 | "out_bytes": "n/a", 1282 | "peer_id": "1.2.3.4", 1283 | "remote_id": "n/a", 1284 | "remote_ip": "n/a", 1285 | "state": "down" 1286 | } 1287 | ] 1288 | } 1289 | } 1290 | } 1291 | -------------------------------------------------------------------------------- /poc/sniffer.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | import time 4 | 5 | import struct 6 | 7 | from uptime import uptime 8 | 9 | mac = [0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9] 10 | ip = [192, 168, 0, 225] 11 | firmware = '4.3.49.5001150' 12 | device = 'UGW3' 13 | 14 | 15 | class TLV(object): 16 | 17 | def __init__(self): 18 | self.results = bytearray() 19 | 20 | def add(self, type, value): 21 | data = bytearray([type, ((len(value) >> 8) & 0xFF), (len(value) & 0xFF)]) 22 | data.extend(value) 23 | self.results.extend(data) 24 | 25 | def get(self, version, command): 26 | value = bytearray([version, command, 0, len(self.results)]) 27 | value.extend(self.results) 28 | 29 | return value 30 | 31 | 32 | def construct_inform_tlv(index): 33 | tlv = TLV() 34 | tlv.add(1, bytearray(mac)) 35 | tlv.add(2, bytearray(mac + ip)) 36 | tlv.add(3, bytearray('UGW4.v{}'.format(firmware))) 37 | tlv.add(10, bytearray([ord(c) for c in struct.pack("!I", uptime())])) 38 | tlv.add(11, bytearray('PFSENSE')) 39 | tlv.add(12, bytearray(device)) 40 | tlv.add(19, bytearray(mac)) 41 | tlv.add(18, bytearray([ord(c) for c in struct.pack("!I", index)])) 42 | tlv.add(21, bytearray(device)) 43 | tlv.add(27, bytearray(firmware)) 44 | tlv.add(22, bytearray(firmware)) 45 | return tlv 46 | 47 | 48 | index = 1 49 | while True: 50 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 51 | s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) 52 | s.sendto(construct_inform_tlv(index).get(version=2, command=6), ('233.89.188.1', 10001)) 53 | time.sleep(10) 54 | index += 1 55 | -------------------------------------------------------------------------------- /poc/src/Sniffer.java: -------------------------------------------------------------------------------- 1 | import codec.UnifiTlv; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.net.*; 6 | import java.nio.ByteBuffer; 7 | import java.text.MessageFormat; 8 | import java.util.Arrays; 9 | 10 | public class Sniffer { 11 | 12 | private static final byte[] supersuper = {-23, 89, -68, 1}; 13 | 14 | public static void main2(String[] args) throws IOException { 15 | InetAddress inetAddress = InetAddress.getByAddress("233.89.188.1", supersuper); 16 | MulticastSocket socket = new MulticastSocket(10001); 17 | socket.setReuseAddress(true); 18 | socket.joinGroup(inetAddress); 19 | 20 | TlvBox box = new TlvBox(); 21 | // System.out.println(box.serialize()); 22 | // box.putStringValue(0x02); 23 | 24 | Thread thread = new Thread(() -> { 25 | try { 26 | while (true) { 27 | // byte[] bytes = new byte['È']; 28 | // DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length); 29 | // socket.receive(datagramPacket); 30 | 31 | DatagramPacket datagramPacket = new DatagramPacket(box.serialize(), box.serialize().length); 32 | socket.send(datagramPacket); 33 | } 34 | } catch (Exception ex) { 35 | System.out.println(ex); 36 | } 37 | }, "discover"); 38 | thread.start(); 39 | } 40 | 41 | public static byte[] macToBytes(String mac) { 42 | String[] macAddressParts = mac.split(":"); 43 | 44 | byte[] macAddressBytes = new byte[6]; 45 | for(int i=0; i<6; i++){ 46 | Integer hex = Integer.parseInt(macAddressParts[i], 16); 47 | macAddressBytes[i] = hex.byteValue(); 48 | } 49 | 50 | return macAddressBytes; 51 | } 52 | 53 | public static void main(String[] args) throws IOException, InterruptedException { 54 | byte[] macAddress = {0x00, 0x0d, (byte) 0xb9, 0x47, 0x65, (byte) 0xf9}; 55 | byte[] ip = {0x00, 0x0d, (byte) 0xb9, 0x47, 0x65, (byte) 0xf9, (byte) 0xC0, (byte) 0xA8, 0x0, 0x1}; 56 | byte[] mac = UnifiTlv.toTlv(UnifiTlv.MAC_ADDRESS, macAddress); 57 | byte[] count = UnifiTlv.toTlv((byte)0x12, ByteBuffer.allocate(4).putInt(1).array()); 58 | byte[] anotherMac = UnifiTlv.toTlv((byte)0x13, macAddress); 59 | byte[] ipInfo = UnifiTlv.toTlv(UnifiTlv.IP_INFO, ip); 60 | byte[] username = UnifiTlv.toTlv(UnifiTlv.USERNAME, "UBN"); 61 | byte[] firmware = UnifiTlv.toTlv(UnifiTlv.FIRMWARE_VERSION, "UGW4.v4.3.49.5001150"); 62 | byte[] uptime = UnifiTlv.toTlv(UnifiTlv.UPTIME, ByteBuffer.allocate(4).putInt(458).array()); 63 | byte[] hostname = UnifiTlv.toTlv(UnifiTlv.HOSTNAME, "PFSENSE"); 64 | byte[] platform = UnifiTlv.toTlv(UnifiTlv.PLATFORM, "UGW3"); 65 | byte[] otherPlatform = UnifiTlv.toTlv((byte)0x15, "UGW3"); 66 | byte[] otherFirmware = UnifiTlv.toTlv((byte)0x1B, "4.3.49.5001150"); 67 | byte[] otherOtherFirmware = UnifiTlv.toTlv((byte)0x16, "4.3.49.5001150"); 68 | byte[] bytes = UnifiTlv.generate(2, 6, ipInfo, mac, uptime, hostname, platform, firmware, anotherMac, count, otherPlatform, otherFirmware, otherOtherFirmware); 69 | 70 | InetAddress inetAddress = InetAddress.getByAddress("233.89.188.1", supersuper); 71 | 72 | int i = bytes[0]; 73 | System.out.println("Version " + i + " packet received of " + bytes.length + " bytes"); 74 | int j = 1; 75 | byte b = bytes[j]; 76 | System.out.println("Command: " + b); 77 | j++; 78 | 79 | byte[] arrayOfByte1 = new byte[2]; 80 | System.arraycopy(bytes, j, arrayOfByte1, 0, arrayOfByte1.length); 81 | j += arrayOfByte1.length; 82 | int k = Sniffer.aaaa(arrayOfByte1); 83 | System.out.println("Data length: " + k); 84 | if (j + k > bytes.length) { 85 | throw new RuntimeException("Packet reports invalid data length, discarding..."); 86 | } 87 | int m = k + 1 + 1 + 2; 88 | 89 | byte[] arrayOfByte2 = new byte[6]; 90 | byte[] localObject3; 91 | byte[] localObject4; 92 | int i2 = -1; 93 | while (j < m) { 94 | int i3 = bytes[(j++)]; 95 | System.arraycopy(bytes, j, arrayOfByte1, 0, arrayOfByte1.length); 96 | j += arrayOfByte1.length; 97 | int i4 = Sniffer.aaaa(arrayOfByte1); 98 | if (j + i4 > m) { 99 | throw new RuntimeException("Invalid length (" + i4 + ") for item " + i3); 100 | } 101 | System.out.println("Item type: " + i3 + " length: " + i4); 102 | byte[] localObject2 = new byte[i4]; 103 | System.arraycopy(bytes, j, localObject2, 0, localObject2.length); 104 | switch (i3) { 105 | case 3: 106 | String str1 = new String(localObject2).trim(); 107 | System.out.println(" [" + str1 + "]"); 108 | break; 109 | case 1: 110 | if (localObject2.length == 6) { 111 | System.arraycopy(localObject2, 0, arrayOfByte2, 0, localObject2.length); 112 | System.out.println(" [" + Sniffer.bbbbbbb(arrayOfByte2) + "]"); 113 | } 114 | break; 115 | case 2: 116 | if (localObject2.length == 10) { 117 | localObject3 = new byte[6]; 118 | localObject4 = new byte[4]; 119 | System.arraycopy(localObject2, 0, localObject3, 0, localObject3.length); 120 | System.arraycopy(localObject2, 6, localObject4, 0, localObject4.length); 121 | InetAddress localInetAddress = null; 122 | try { 123 | localInetAddress = InetAddress.getByAddress((byte[]) localObject4); 124 | System.out.println(" [" + Sniffer.bbbbbbb(localObject3) + ", " + localInetAddress.getHostAddress() + "]"); 125 | } 126 | catch (UnknownHostException localUnknownHostException) {} 127 | } 128 | break; 129 | case 6: 130 | System.out.println(" username: '" + new String((byte[])localObject2) + "'"); 131 | break; 132 | case 10: 133 | System.out.println(" uptime: [" + Sniffer.aaaa(localObject2) + "]"); 134 | break; 135 | case 11: 136 | System.out.println(" hostname: '" + new String((byte[])localObject2) + "'"); 137 | break; 138 | 139 | default: 140 | System.out.println("\t TLV " + i3 + " data: [" + new String(localObject2).trim() + "]"); 141 | } 142 | j += i4; 143 | } 144 | 145 | if ((i == 2) && (b == 8)) { 146 | System.out.println("coucou"); 147 | } 148 | if (i == 2) { 149 | System.out.println("cicicicic"); 150 | } 151 | if ((i == 2) && (b == 11) && (i2 == -1)) { 152 | System.out.println("sdfsdfsdfsfd"); 153 | } 154 | if ((b == 6) || (b == 11) || (b == Byte.MIN_VALUE)) { 155 | System.out.println("qqqqqqqqqqqqq"); 156 | } 157 | if ((b == 2) || (b == -126)) { 158 | System.out.println("psdpsdof"); 159 | } 160 | DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, inetAddress, 10001); 161 | DatagramSocket socket = new DatagramSocket(); 162 | 163 | while (true) { 164 | socket.send(datagramPacket); 165 | System.out.println(bytes.length); 166 | Thread.sleep(10000); 167 | } 168 | } 169 | 170 | public static int aaaa(byte[] paramArrayOfByte) 171 | { 172 | int i = 0; 173 | for (int j = 0; j < paramArrayOfByte.length; j++) 174 | { 175 | int k = (paramArrayOfByte[j] & 0xFF) << (paramArrayOfByte.length - 1 - j) * 8; 176 | i += k; 177 | } 178 | return i; 179 | } 180 | 181 | public static String bbbbbbb(byte[] paramArrayOfByte) 182 | { 183 | String str1 = null; 184 | if ((paramArrayOfByte != null) && (paramArrayOfByte.length > 5)) 185 | { 186 | String[] arrayOfString = new String[paramArrayOfByte.length]; 187 | for (int i = 0; i < paramArrayOfByte.length; i++) 188 | { 189 | String str2 = Integer.toHexString(paramArrayOfByte[i] & 0xFF); 190 | if (str2.length() == 1) { 191 | str2 = "0" + str2; 192 | } 193 | arrayOfString[i] = str2.toUpperCase(); 194 | } 195 | str1 = MessageFormat.format("{0}-{1}-{2}-{3}-{4}-{5}", (Object[])arrayOfString); 196 | } 197 | return str1; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /poc/src/Test.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.net.DatagramPacket; 3 | import java.net.InetAddress; 4 | import java.net.MulticastSocket; 5 | import java.net.UnknownHostException; 6 | import java.util.Date; 7 | 8 | public class Test { 9 | 10 | private static final byte[] supersuper = {-23, 89, -68, 1}; 11 | 12 | public static void main(String[] args) throws IOException { 13 | InetAddress inetAddress = InetAddress.getByAddress("233.89.188.1", supersuper); 14 | MulticastSocket socket = new MulticastSocket(10001); 15 | socket.setReuseAddress(true); 16 | socket.joinGroup(inetAddress); 17 | 18 | // int k = 0; 19 | // byte i = 0x00; 20 | // byte j = 0x00; 21 | // while (k != 148) { 22 | // byte[] toto = {i, j}; 23 | // k = Sniffer.aaaa(toto); 24 | // 25 | // if (i % 128 == 0) { 26 | // i++; 27 | // } else { 28 | // i = 0; 29 | // j++; 30 | // } 31 | // } 32 | // 33 | // System.out.println(1); 34 | // System.out.println(-108); 35 | 36 | 37 | while (true) { 38 | byte[] bytes = new byte[1024]; 39 | DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length); 40 | socket.receive(datagramPacket); 41 | System.out.println(new Date()); 42 | 43 | int i = bytes[0]; 44 | System.out.println("Version " + i + " packet received of " + bytes.length + " bytes"); 45 | int j = 1; 46 | byte b = bytes[j]; 47 | System.out.println("Command: " + b); 48 | j++; 49 | 50 | byte[] arrayOfByte1 = new byte[2]; 51 | System.arraycopy(bytes, j, arrayOfByte1, 0, arrayOfByte1.length); 52 | j += arrayOfByte1.length; 53 | int k = Sniffer.aaaa(arrayOfByte1); 54 | System.out.println("Data length: " + k); 55 | if (j + k > bytes.length) { 56 | throw new RuntimeException("Packet reports invalid data length, discarding..."); 57 | } 58 | int m = k + 1 + 1 + 2; 59 | 60 | byte[] arrayOfByte2 = new byte[6]; 61 | byte[] localObject3; 62 | byte[] localObject4; 63 | int i1 = -1; 64 | int i2 = -1; 65 | byte[] arrayOfByte5 = new byte[6]; 66 | String str5 = ""; 67 | String str8 = null; 68 | String str9 = null; 69 | String str6 = ""; 70 | while (j < m) { 71 | int i3 = bytes[(j++)]; 72 | System.arraycopy(bytes, j, arrayOfByte1, 0, arrayOfByte1.length); 73 | j += arrayOfByte1.length; 74 | int i4 = Sniffer.aaaa(arrayOfByte1); 75 | if (j + i4 > m) { 76 | throw new RuntimeException("Invalid length (" + i4 + ") for item " + i3); 77 | } 78 | System.out.println("Item type: " + i3 + " length: " + i4); 79 | byte[] localObject2 = new byte[i4]; 80 | System.arraycopy(bytes, j, localObject2, 0, localObject2.length); 81 | switch (i3) { 82 | case 3: 83 | String str1 = new String(localObject2).trim(); 84 | System.out.println(" [" + str1 + "]"); 85 | break; 86 | case 1: 87 | if (localObject2.length == 6) { 88 | System.arraycopy(localObject2, 0, arrayOfByte2, 0, localObject2.length); 89 | System.out.println(" [" + Sniffer.bbbbbbb(arrayOfByte2) + "]"); 90 | } 91 | break; 92 | case 2: 93 | if (localObject2.length == 10) { 94 | localObject3 = new byte[6]; 95 | localObject4 = new byte[4]; 96 | System.arraycopy(localObject2, 0, localObject3, 0, localObject3.length); 97 | System.arraycopy(localObject2, 6, localObject4, 0, localObject4.length); 98 | InetAddress localInetAddress = null; 99 | try { 100 | localInetAddress = InetAddress.getByAddress((byte[]) localObject4); 101 | System.out.println(" [" + Sniffer.bbbbbbb(localObject3) + ", " + localInetAddress.getHostAddress() + "]"); 102 | } 103 | catch (UnknownHostException localUnknownHostException) {} 104 | } 105 | break; 106 | case 6: 107 | System.out.println(" username: '" + new String((byte[])localObject2) + "'"); 108 | break; 109 | case 18: 110 | i1 = Sniffer.aaaa((byte[])localObject2); 111 | break; 112 | case 19: 113 | System.arraycopy(localObject2, 0, arrayOfByte5, 0, arrayOfByte5.length); 114 | str9 = Sniffer.bbbbbbb(arrayOfByte5); 115 | break; 116 | case 21: 117 | str6 = new String((byte[])localObject2); 118 | break; 119 | case 27: 120 | str8 = new String((byte[])localObject2); 121 | break; 122 | case 22: 123 | str5 = new String((byte[])localObject2); 124 | break; 125 | default: 126 | System.out.println("\t TLV " + i3 + " data: [" + new String(localObject2).trim() + "]"); 127 | } 128 | j += i4; 129 | } 130 | } 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /poc/src/TlvBox.java: -------------------------------------------------------------------------------- 1 | import java.nio.ByteBuffer; 2 | import java.nio.ByteOrder; 3 | import java.util.HashMap; 4 | import java.util.Set; 5 | 6 | public class TlvBox { 7 | 8 | private static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; 9 | 10 | private HashMap mObjects; 11 | private int mTotalBytes = 0; 12 | 13 | public TlvBox() { 14 | mObjects = new HashMap(); 15 | } 16 | 17 | public static TlvBox parse(byte[] buffer,int offset,int length) { 18 | 19 | TlvBox box = new TlvBox(); 20 | 21 | int parsed = 0; 22 | while (parsed < length) { 23 | int type = ByteBuffer.wrap(buffer,offset+parsed,4).order(DEFAULT_BYTE_ORDER).getInt(); 24 | parsed += 4; 25 | int size = ByteBuffer.wrap(buffer,offset+parsed,4).order(DEFAULT_BYTE_ORDER).getInt(); 26 | parsed += 4; 27 | byte[] value = new byte[size]; 28 | System.arraycopy(buffer, offset+parsed, value, 0, size); 29 | box.putBytesValue(type,value); 30 | parsed += size; 31 | } 32 | return box; 33 | } 34 | 35 | public byte[] serialize() { 36 | int offset = 0; 37 | byte[] result = new byte[mTotalBytes]; 38 | Set keys = mObjects.keySet(); 39 | for (Integer key : keys) { 40 | byte[] bytes = mObjects.get(key); 41 | byte[] type = ByteBuffer.allocate(4).order(DEFAULT_BYTE_ORDER).putInt(key).array(); 42 | byte[] length = ByteBuffer.allocate(4).order(DEFAULT_BYTE_ORDER).putInt(bytes.length).array(); 43 | System.arraycopy(type, 0, result, offset, type.length); 44 | offset += 4; 45 | System.arraycopy(length, 0, result, offset, length.length); 46 | offset += 4; 47 | System.arraycopy(bytes, 0, result, offset, bytes.length); 48 | offset += bytes.length; 49 | } 50 | return result; 51 | } 52 | 53 | public void putByteValue(int type,byte value) { 54 | byte[] bytes = new byte[1]; 55 | bytes[0] = value; 56 | putBytesValue(type,bytes); 57 | } 58 | 59 | public void putShortValue(int type,short value) { 60 | byte[] bytes = ByteBuffer.allocate(2).order(DEFAULT_BYTE_ORDER).putShort(value).array(); 61 | putBytesValue(type,bytes); 62 | } 63 | 64 | public void putIntValue(int type,int value) { 65 | byte[] bytes = ByteBuffer.allocate(4).order(DEFAULT_BYTE_ORDER).putInt(value).array(); 66 | putBytesValue(type,bytes); 67 | } 68 | 69 | public void putLongValue(int type,long value) { 70 | byte[] bytes = ByteBuffer.allocate(8).order(DEFAULT_BYTE_ORDER).putLong(value).array(); 71 | putBytesValue(type,bytes); 72 | } 73 | 74 | public void putFloatValue(int type,float value) { 75 | byte[] bytes = ByteBuffer.allocate(4).order(DEFAULT_BYTE_ORDER).putFloat(value).array(); 76 | putBytesValue(type,bytes); 77 | } 78 | 79 | public void putDoubleValue(int type,double value) { 80 | byte[] bytes = ByteBuffer.allocate(8).order(DEFAULT_BYTE_ORDER).putDouble(value).array(); 81 | putBytesValue(type,bytes); 82 | } 83 | 84 | public void putStringValue(int type,String value) { 85 | putBytesValue(type,value.getBytes()); 86 | } 87 | 88 | public void putObjectValue(int type,TlvBox value) { 89 | putBytesValue(type,value.serialize()); 90 | } 91 | 92 | public void putBytesValue(int type,byte[] value) { 93 | mObjects.put(type, value); 94 | mTotalBytes += value.length + 8; 95 | } 96 | 97 | public Byte getByteValue(int type) { 98 | byte[] bytes = mObjects.get(type); 99 | if (bytes == null) { 100 | return null; 101 | } 102 | return bytes[0]; 103 | } 104 | 105 | public Short getShortValue(int type) { 106 | byte[] bytes = mObjects.get(type); 107 | if (bytes == null) { 108 | return null; 109 | } 110 | return ByteBuffer.wrap(bytes).order(DEFAULT_BYTE_ORDER).getShort(); 111 | } 112 | 113 | public Integer getIntValue(int type) { 114 | byte[] bytes = mObjects.get(type); 115 | if (bytes == null) { 116 | return null; 117 | } 118 | return ByteBuffer.wrap(bytes).order(DEFAULT_BYTE_ORDER).getInt(); 119 | } 120 | 121 | public Long getLongValue(int type) { 122 | byte[] bytes = mObjects.get(type); 123 | if (bytes == null) { 124 | return null; 125 | } 126 | return ByteBuffer.wrap(bytes).order(DEFAULT_BYTE_ORDER).getLong(); 127 | } 128 | 129 | public Float getFloatValue(int type) { 130 | byte[] bytes = mObjects.get(type); 131 | if (bytes == null) { 132 | return null; 133 | } 134 | return ByteBuffer.wrap(bytes).order(DEFAULT_BYTE_ORDER).getFloat(); 135 | } 136 | 137 | public Double getDoubleValue(int type) { 138 | byte[] bytes = mObjects.get(type); 139 | if (bytes == null) { 140 | return null; 141 | } 142 | return ByteBuffer.wrap(bytes).order(DEFAULT_BYTE_ORDER).getDouble(); 143 | } 144 | 145 | public TlvBox getObjectValue(int type) { 146 | byte[] bytes = mObjects.get(type); 147 | if (bytes == null) { 148 | return null; 149 | } 150 | return TlvBox.parse(bytes, 0, bytes.length); 151 | } 152 | 153 | public String getStringValue(int type) { 154 | byte[] bytes = mObjects.get(type); 155 | if (bytes == null) { 156 | return null; 157 | } 158 | return new String(bytes).trim(); 159 | } 160 | 161 | public byte[] getBytesValue(int type) { 162 | byte[] bytes = mObjects.get(type); 163 | return bytes; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /poc/src/codec/UnifiTlv.java: -------------------------------------------------------------------------------- 1 | package codec; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | public class UnifiTlv { 7 | 8 | public static final byte MAC_ADDRESS = 0x01; 9 | public static final byte IP_INFO = 0x02; 10 | public static final byte FIRMWARE_VERSION = 0x03; 11 | public static final byte USERNAME = 0x06; 12 | public static final byte UPTIME = 0xA; 13 | public static final byte HOSTNAME = 0xB; 14 | public static final byte PLATFORM = 0xC; 15 | 16 | public static byte[] toTlv(byte type, String value) throws IOException { 17 | byte[] bytesString = value.getBytes(); 18 | int length = bytesString.length; 19 | 20 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); 21 | outputStream.write(type); 22 | outputStream.write((byte) ((length >> 8) & 0xFF)); 23 | outputStream.write((byte) (length & 0xFF)); 24 | outputStream.write(bytesString); 25 | 26 | return outputStream.toByteArray(); 27 | } 28 | 29 | public static byte[] toTlv(byte type, byte[] value) throws IOException { 30 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); 31 | outputStream.write(type); 32 | outputStream.write((byte) ((value.length >> 8) & 0xFF)); 33 | outputStream.write((byte) (value.length & 0xFF)); 34 | outputStream.write(value); 35 | 36 | return outputStream.toByteArray(); 37 | } 38 | 39 | public static byte[] generate(int version, int command, byte[]... tlvs) throws IOException { 40 | int size = 0; 41 | 42 | for (byte[] tlv : tlvs) { 43 | size += tlv.length; 44 | } 45 | 46 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); 47 | outputStream.write(version); 48 | outputStream.write(command); 49 | outputStream.write(0x0); 50 | outputStream.write(size); 51 | for (byte[] tlv : tlvs) { 52 | outputStream.write(tlv); 53 | } 54 | 55 | return outputStream.toByteArray(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /poc/ssh_server.py: -------------------------------------------------------------------------------- 1 | import MockSSH 2 | import sys 3 | 4 | from inform import send_inform 5 | 6 | users = {'ubnt': 'ubnt'} 7 | 8 | 9 | 10 | 11 | def execCommandImplemented(self, protocol, cmd): 12 | (_, _, url, key) = cmd.split(' ') 13 | print(cmd) 14 | 15 | with open('/tmp/cfg/log', 'w') as f: 16 | f.write('url=%s\nkey=%s\n' % (url, key)) 17 | 18 | send_inform(url, key, partial=True) 19 | send_inform(url, key) 20 | 21 | 22 | MockSSH.SSHAvatar.execCommand = execCommandImplemented 23 | 24 | 25 | commands = [ 26 | ] 27 | 28 | MockSSH.runServer( 29 | commands, prompt="ubnt#", interface='10.0.8.2', port=10022, **users) 30 | -------------------------------------------------------------------------------- /poc/unifi_inform_protocol.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | 3 | 4 | class TLV(object): 5 | 6 | def __init__(self): 7 | self.results = bytearray() 8 | 9 | def add(self, type, value): 10 | data = bytearray([type, ((len(value) >> 8) & 0xFF), (len(value) & 0xFF)]) 11 | data.extend(value) 12 | # print([c for c in data]) 13 | self.results.extend(data) 14 | 15 | def get(self, version, command): 16 | value = bytearray([version, command, 0, len(self.results)]) 17 | value.extend(self.results) 18 | 19 | # print([c for c in value]) 20 | return value 21 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | uptime==3.0.1 2 | MockSSH==1.4.5 3 | pycrypto==2.6.1 4 | Flask==0.12.2 5 | psutil==5.4.0 6 | -------------------------------------------------------------------------------- /tlv.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | class TLV(object): 3 | 4 | def __init__(self): 5 | self.results = bytearray() 6 | 7 | def add(self, type, value): 8 | data = bytearray([type, ((len(value) >> 8) & 0xFF), (len(value) & 0xFF)]) 9 | data.extend(value) 10 | self.results.extend(data) 11 | 12 | def get(self, **kwargs): 13 | return self.results 14 | 15 | 16 | class UnifiTLV(TLV): 17 | 18 | def get(self, version, command): 19 | value = bytearray([version, command, 0, len(self.results)]) 20 | value.extend(self.results) 21 | 22 | return value 23 | -------------------------------------------------------------------------------- /tools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | def mac_string_2_array(mac): 3 | return [int(i, 16) for i in mac.split(':')] 4 | 5 | 6 | def ip_string_2_array(mac): 7 | return [int(i) for i in mac.split('.')] 8 | -------------------------------------------------------------------------------- /unifi_gateway.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import ConfigParser 3 | import argparse 4 | import logging.handlers 5 | import socket 6 | import time 7 | import urllib2 8 | 9 | from daemon import Daemon 10 | from unifi_protocol import create_broadcast_message, create_inform, encode_inform, decode_inform 11 | 12 | handler = logging.handlers.SysLogHandler(address='/dev/log') 13 | handler.setFormatter(logging.Formatter('[unifi-gateway] : %(levelname)s : %(message)s')) 14 | logger = logging.getLogger('unifi-gateway') 15 | logger.setLevel(logging.DEBUG) 16 | logger.addHandler(handler) 17 | 18 | CONFIG_FILE = 'conf/unifi-gateway.conf' 19 | 20 | 21 | class UnifiGateway(Daemon): 22 | 23 | def __init__(self, **kwargs): 24 | self.interval = 10 25 | self.config = ConfigParser.RawConfigParser() 26 | self.config.read(CONFIG_FILE) 27 | 28 | Daemon.__init__(self, pidfile=self.config.get('global', 'pid_file'), **kwargs) 29 | 30 | def run(self): 31 | broadcast_index = 1 32 | while not self.config.getboolean('gateway', 'is_adopted'): 33 | self._send_broadcast(broadcast_index) 34 | time.sleep(self.interval) 35 | broadcast_index += 1 36 | 37 | while True: 38 | response = self._send_inform(create_inform(self.config)) 39 | logger.debug('Receive {} from controller'.format(response)) 40 | time.sleep(self.interval) 41 | 42 | def _send_broadcast(self, broadcast_index): 43 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 44 | sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) 45 | sock.sendto(create_broadcast_message(self.config, broadcast_index), ('233.89.188.1', 10001)) 46 | 47 | logger.debug('Send broadcast message #{} from gateway {}'.format(broadcast_index, self.config.get('gateway', 'lan_ip'))) 48 | 49 | def quit(self): 50 | pass 51 | 52 | def set_adopt(self, url, key): 53 | self.config.set('gateway', 'url', url) 54 | self.config.set('gateway', 'key', key) 55 | self._save_config() 56 | 57 | response = self._send_inform(create_inform(self.config)) 58 | logger.debug('Receive {} from controller'.format(response)) 59 | if response['_type'] == 'setparam': 60 | for key, value in response.items(): 61 | if key not in ['_type', 'server_time_in_utc', 'mgmt_cfg']: 62 | self.config.set('gateway', key, value) 63 | self.config.set('gateway', 'is_adopted', True) 64 | self._save_config() 65 | 66 | def _send_inform(self, data): 67 | headers = { 68 | 'Content-Type': 'application/x-binary', 69 | 'User-Agent': 'AirControl Agent v1.0' 70 | } 71 | url = self.config.get('gateway', 'url') 72 | 73 | request = urllib2.Request(url, encode_inform(data), headers) 74 | response = urllib2.urlopen(request) 75 | logger.debug('Send inform request to {} : {}'.format(url, data)) 76 | return decode_inform(self.config, response.read()) 77 | 78 | def _save_config(self): 79 | with open(CONFIG_FILE, 'w') as config_file: 80 | self.config.write(config_file) 81 | 82 | 83 | def restart(args): 84 | UnifiGateway().restart() 85 | 86 | 87 | def stop(args): 88 | UnifiGateway().stop() 89 | 90 | 91 | def start(args): 92 | UnifiGateway().start() 93 | 94 | 95 | def set_adopt(args): 96 | url, key = args.s, args.k 97 | UnifiGateway().set_adopt(url, key) 98 | 99 | 100 | if __name__ == '__main__': 101 | parser = argparse.ArgumentParser() 102 | subparsers = parser.add_subparsers() 103 | 104 | parser_start = subparsers.add_parser('start', help='start unifi gateway daemon') 105 | parser_start.set_defaults(func=start) 106 | 107 | parser_stop = subparsers.add_parser('stop', help='stop unifi gateway daemon') 108 | parser_stop.set_defaults(func=stop) 109 | 110 | parser_restart = subparsers.add_parser('restart', help='restart unifi gateway daemon') 111 | parser_restart.set_defaults(func=restart) 112 | 113 | parser_adopt = subparsers.add_parser('set-adopt', help='send the adoption request to the controller') 114 | parser_adopt.add_argument('-s', type=str, help='controller url', required=True) 115 | parser_adopt.add_argument('-k', type=str, help='key', required=True) 116 | parser_adopt.set_defaults(func=set_adopt) 117 | 118 | args = parser.parse_args(['set-adopt', '-s', 'http://toto', '-k', 'oeruchoreuch']) 119 | args.func(args) 120 | -------------------------------------------------------------------------------- /unifi_protocol.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | from random import Random 4 | 5 | import zlib 6 | 7 | from Crypto.Cipher import AES 8 | from struct import pack, unpack 9 | 10 | from binascii import a2b_hex 11 | from uptime import uptime 12 | 13 | from tlv import UnifiTLV 14 | from tools import mac_string_2_array, ip_string_2_array 15 | 16 | 17 | def encode_inform(config, data): 18 | iv = Random.new().read(16) 19 | 20 | payload = zlib.compress(data) 21 | pad_len = AES.block_size - (len(payload) % AES.block_size) 22 | payload += chr(pad_len) * pad_len 23 | payload = AES.new(a2b_hex(config.get('gateway', 'key')), AES.MODE_CBC, iv).encrypt(payload) 24 | 25 | encoded_data = 'TNBU' # magic 26 | encoded_data += pack('>I', 1) # packet version 27 | encoded_data += pack('BBBBBB', *(0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)) # mac address 28 | encoded_data += pack('>H', 3) # flags 29 | encoded_data += iv # encryption iv 30 | encoded_data += pack('>I', 1) # payload version 31 | encoded_data += pack('>I', len(payload)) # payload length 32 | encoded_data += payload 33 | 34 | return encoded_data 35 | 36 | 37 | def decode_inform(config, encoded_data): 38 | magic = encoded_data[0:4] 39 | if magic != 'TNBU': 40 | raise Exception("Missing magic in response: '{}' instead of 'TNBU'".format(magic)) 41 | 42 | # mac = unpack('BBBBBB', encoded_data[8:14]) 43 | # if mac != (0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9): 44 | # raise Exception('Mac address changed in response: %s -> %s'%(mac2a((0x00, 0x0d, 0xb9, 0x47, 0x65, 0xf9)), mac2a(mac))) 45 | 46 | flags = unpack('>H', encoded_data[14:16])[0] 47 | iv = encoded_data[16:32] 48 | version = unpack('>I', encoded_data[32:36])[0] 49 | payload_len = unpack('>I', encoded_data[36:40])[0] 50 | payload = encoded_data[40:(40+payload_len)] 51 | 52 | # decrypt if required 53 | if flags & 0x01: 54 | payload = AES.new(a2b_hex(config.get('gateway', 'key')), AES.MODE_CBC, iv).decrypt(payload) 55 | pad_size = ord(payload[-1]) 56 | if pad_size > AES.block_size: 57 | raise Exception('Response not padded or padding is corrupt') 58 | payload = payload[:(len(payload) - pad_size)] 59 | # uncompress if required 60 | if flags & 0x02: 61 | payload = zlib.decompress(payload) 62 | 63 | return payload 64 | 65 | 66 | def _create_partial_inform(config): 67 | return json.dumps({ 68 | 'mac': config.get('gateway', 'lan_mac'), 69 | 'ip': config.get('gateway', 'lan_ip'), 70 | 'model': 'UGW3', 71 | 'model-display': 'UniFi-Gateway-3', 72 | 'version': '4.3.49.5001150' 73 | }) 74 | 75 | 76 | def _create_complete_inform(config): 77 | # return json.dumps({ 78 | # 'bootrom_version': 'unknown', 79 | # 'cfgversion': cfg('_cfg', 'cfgversion'), 80 | # 'config_network_wan': { 81 | # 'type': 'dhcp', 82 | # }, 83 | # 'config_port_table': [ 84 | # { 85 | # 'ifname': 'eth0', 86 | # 'name': 'wan' 87 | # }, 88 | # { 89 | # 'ifname': 'eth1', 90 | # 'name': 'lan' 91 | # }, 92 | # { 93 | # 'ifname': 'eth2', 94 | # 'name': 'lan' 95 | # } 96 | # ], 97 | # 'connect_request_ip': gateway_lan_ip, 98 | # 'connect_request_port': '36424', 99 | # 'default': False, 100 | # 'discovery_response': False, 101 | # 'fw_caps': 3, 102 | # 'guest_token': '4C1D46707239C6EB5A2366F505A44A91', 103 | # 'has_default_route_distance': True, 104 | # 'has_dnsmasq_hostfile_update': False, 105 | # 'has_dpi': True, 106 | # 'dpi-clients': [ 107 | # '80:2a:a8:f0:ef:78' 108 | # ], 109 | # 'dpi-stats': [ 110 | # { 111 | # 'initialized': '94107792805', 112 | # 'mac': '80:2a:a8:f0:ef:78', 113 | # 'stats': [ 114 | # { 115 | # 'app': 5, 116 | # 'cat': 3, 117 | # 'rx_bytes': 82297468, 118 | # 'rx_packets': 57565, 119 | # 'tx_bytes': 1710174, 120 | # 'tx_packets': 25324 121 | # }, 122 | # { 123 | # 'app': 94, 124 | # 'cat': 19, 125 | # 'rx_bytes': 1593846895, 126 | # 'rx_packets': 1738901, 127 | # 'tx_bytes': 348738675, 128 | # 'tx_packets': 2004045 129 | # }, 130 | # { 131 | # 'app': 133, 132 | # 'cat': 3, 133 | # 'rx_bytes': 531190, 134 | # 'rx_packets': 2465, 135 | # 'tx_bytes': 676859, 136 | # 'tx_packets': 2760 137 | # }, 138 | # { 139 | # 'app': 222, 140 | # 'cat': 13, 141 | # 'rx_bytes': 3441437, 142 | # 'rx_packets': 3033, 143 | # 'tx_bytes': 203173, 144 | # 'tx_packets': 1468 145 | # }, 146 | # { 147 | # 'app': 23, 148 | # 'cat': 0, 149 | # 'rx_bytes': 0, 150 | # 'rx_packets': 0, 151 | # 'tx_bytes': 145, 152 | # 'tx_packets': 2 153 | # }, 154 | # { 155 | # 'app': 7, 156 | # 'cat': 0, 157 | # 'rx_bytes': 0, 158 | # 'rx_packets': 0, 159 | # 'tx_bytes': 145, 160 | # 'tx_packets': 2 161 | # }, 162 | # { 163 | # 'app': 7, 164 | # 'cat': 13, 165 | # 'rx_bytes': 24417806554, 166 | # 'rx_packets': 18415873, 167 | # 'tx_bytes': 2817966897, 168 | # 'tx_packets': 9910192 169 | # }, 170 | # { 171 | # 'app': 185, 172 | # 'cat': 20, 173 | # 'rx_bytes': 28812050, 174 | # 'rx_packets': 208945, 175 | # 'tx_bytes': 160819147, 176 | # 'tx_packets': 1228992 177 | # }, 178 | # { 179 | # 'app': 65535, 180 | # 'cat': 255, 181 | # 'rx_bytes': 182029551, 182 | # 'rx_packets': 1796815, 183 | # 'tx_bytes': 435732626, 184 | # 'tx_packets': 1933469 185 | # }, 186 | # { 187 | # 'app': 4, 188 | # 'cat': 10, 189 | # 'rx_bytes': 1522, 190 | # 'rx_packets': 20, 191 | # 'tx_bytes': 882, 192 | # 'tx_packets': 12 193 | # }, 194 | # { 195 | # 'app': 106, 196 | # 'cat': 18, 197 | # 'rx_bytes': 982710, 198 | # 'rx_packets': 10919, 199 | # 'tx_bytes': 1010970, 200 | # 'tx_packets': 11233 201 | # }, 202 | # { 203 | # 'app': 30, 204 | # 'cat': 18, 205 | # 'rx_bytes': 7819852, 206 | # 'rx_packets': 20378, 207 | # 'tx_bytes': 1293104, 208 | # 'tx_packets': 18686 209 | # }, 210 | # { 211 | # 'app': 1, 212 | # 'cat': 0, 213 | # 'rx_bytes': 0, 214 | # 'rx_packets': 0, 215 | # 'tx_bytes': 145, 216 | # 'tx_packets': 2 217 | # }, 218 | # { 219 | # 'app': 63, 220 | # 'cat': 18, 221 | # 'rx_bytes': 780358, 222 | # 'rx_packets': 3520, 223 | # 'tx_bytes': 545757, 224 | # 'tx_packets': 6545 225 | # }, 226 | # { 227 | # 'app': 8, 228 | # 'cat': 13, 229 | # 'rx_bytes': 180691586, 230 | # 'rx_packets': 132204, 231 | # 'tx_bytes': 5970383, 232 | # 'tx_packets': 74482 233 | # }, 234 | # { 235 | # 'app': 21, 236 | # 'cat': 10, 237 | # 'rx_bytes': 5521547718, 238 | # 'rx_packets': 73080390, 239 | # 'tx_bytes': 179999309100, 240 | # 'tx_packets': 130627577 241 | # } 242 | # ] 243 | # } 244 | # ], 245 | # 'dpi-stats-table': [ 246 | # { 247 | # '_id': '5875d9f9e4b02fd3851c55e4', 248 | # '_subid': '5875d9f5e4b02fd3851c55d8', 249 | # 'by_app': [ 250 | # { 251 | # 'app': 5, 252 | # 'cat': 3, 253 | # 'rx_bytes': 2652, 254 | # 'rx_packets': 4, 255 | # 'tx_bytes': 1797, 256 | # 'tx_packets': 7 257 | # }, 258 | # { 259 | # 'app': 94, 260 | # 'cat': 19, 261 | # 'rx_bytes': 9010458, 262 | # 'rx_packets': 6977, 263 | # 'tx_bytes': 518163, 264 | # 'tx_packets': 3533 265 | # }, 266 | # { 267 | # 'app': 209, 268 | # 'cat': 13, 269 | # 'rx_bytes': 39303, 270 | # 'rx_packets': 90, 271 | # 'tx_bytes': 17744, 272 | # 'tx_packets': 78 273 | # }, 274 | # { 275 | # 'app': 10, 276 | # 'cat': 4, 277 | # 'rx_bytes': 15273, 278 | # 'rx_packets': 15, 279 | # 'tx_bytes': 2728, 280 | # 'tx_packets': 23 281 | # }, 282 | # { 283 | # 'app': 7, 284 | # 'cat': 13, 285 | # 'rx_bytes': 369394, 286 | # 'rx_packets': 293, 287 | # 'tx_bytes': 24904, 288 | # 'tx_packets': 244 289 | # }, 290 | # { 291 | # 'app': 185, 292 | # 'cat': 20, 293 | # 'rx_bytes': 62070, 294 | # 'rx_packets': 130, 295 | # 'tx_bytes': 27219, 296 | # 'tx_packets': 169 297 | # }, 298 | # { 299 | # 'app': 65535, 300 | # 'cat': 255, 301 | # 'rx_bytes': 976848, 302 | # 'rx_packets': 1027, 303 | # 'tx_bytes': 77317, 304 | # 'tx_packets': 695 305 | # }, 306 | # { 307 | # 'app': 12, 308 | # 'cat': 13, 309 | # 'rx_bytes': 92924774, 310 | # 'rx_packets': 70496, 311 | # 'tx_bytes': 17360339, 312 | # 'tx_packets': 69509 313 | # }, 314 | # { 315 | # 'app': 150, 316 | # 'cat': 3, 317 | # 'rx_bytes': 54609, 318 | # 'rx_packets': 71, 319 | # 'tx_bytes': 19749, 320 | # 'tx_packets': 85 321 | # }, 322 | # { 323 | # 'app': 95, 324 | # 'cat': 5, 325 | # 'rx_bytes': 9835, 326 | # 'rx_packets': 41, 327 | # 'tx_bytes': 3956, 328 | # 'tx_packets': 41 329 | # }, 330 | # { 331 | # 'app': 168, 332 | # 'cat': 20, 333 | # 'rx_bytes': 100049, 334 | # 'rx_packets': 198, 335 | # 'tx_bytes': 60396, 336 | # 'tx_packets': 275 337 | # }, 338 | # { 339 | # 'app': 3, 340 | # 'cat': 10, 341 | # 'rx_bytes': 12538, 342 | # 'rx_packets': 36, 343 | # 'tx_bytes': 10607, 344 | # 'tx_packets': 75 345 | # }, 346 | # { 347 | # 'app': 84, 348 | # 'cat': 3, 349 | # 'rx_bytes': 45115, 350 | # 'rx_packets': 135, 351 | # 'tx_bytes': 91866, 352 | # 'tx_packets': 158 353 | # }, 354 | # { 355 | # 'app': 84, 356 | # 'cat': 13, 357 | # 'rx_bytes': 42563, 358 | # 'rx_packets': 102, 359 | # 'tx_bytes': 32676, 360 | # 'tx_packets': 113 361 | # }, 362 | # { 363 | # 'app': 186, 364 | # 'cat': 20, 365 | # 'rx_bytes': 44618, 366 | # 'rx_packets': 68, 367 | # 'tx_bytes': 8826, 368 | # 'tx_packets': 86 369 | # } 370 | # ], 371 | # 'by_cat': [ 372 | # { 373 | # 'apps': [ 374 | # 5, 375 | # 150, 376 | # 84 377 | # ], 378 | # 'cat': 3, 379 | # 'rx_bytes': 102376, 380 | # 'rx_packets': 210, 381 | # 'tx_bytes': 113412, 382 | # 'tx_packets': 250 383 | # }, 384 | # { 385 | # 'apps': [ 386 | # 10 387 | # ], 388 | # 'cat': 4, 389 | # 'rx_bytes': 15273, 390 | # 'rx_packets': 15, 391 | # 'tx_bytes': 2728, 392 | # 'tx_packets': 23 393 | # }, 394 | # { 395 | # 'apps': [ 396 | # 95 397 | # ], 398 | # 'cat': 5, 399 | # 'rx_bytes': 9835, 400 | # 'rx_packets': 41, 401 | # 'tx_bytes': 3956, 402 | # 'tx_packets': 41 403 | # }, 404 | # { 405 | # 'apps': [ 406 | # 3 407 | # ], 408 | # 'cat': 10, 409 | # 'rx_bytes': 12538, 410 | # 'rx_packets': 36, 411 | # 'tx_bytes': 10607, 412 | # 'tx_packets': 75 413 | # }, 414 | # { 415 | # 'apps': [ 416 | # 209, 417 | # 7, 418 | # 12, 419 | # 84 420 | # ], 421 | # 'cat': 13, 422 | # 'rx_bytes': 93376034, 423 | # 'rx_packets': 70981, 424 | # 'tx_bytes': 17435663, 425 | # 'tx_packets': 69944 426 | # }, 427 | # { 428 | # 'apps': [ 429 | # 94 430 | # ], 431 | # 'cat': 19, 432 | # 'rx_bytes': 9010458, 433 | # 'rx_packets': 6977, 434 | # 'tx_bytes': 518163, 435 | # 'tx_packets': 3533 436 | # }, 437 | # { 438 | # 'apps': [ 439 | # 185, 440 | # 168, 441 | # 186 442 | # ], 443 | # 'cat': 20, 444 | # 'rx_bytes': 206737, 445 | # 'rx_packets': 396, 446 | # 'tx_bytes': 96441, 447 | # 'tx_packets': 530 448 | # }, 449 | # { 450 | # 'apps': [ 451 | # 65535 452 | # ], 453 | # 'cat': 255, 454 | # 'rx_bytes': 976848, 455 | # 'rx_packets': 1027, 456 | # 'tx_bytes': 77317, 457 | # 'tx_packets': 695 458 | # } 459 | # ], 460 | # 'initialized': '88122111307' 461 | # }, 462 | # { 463 | # '_id': '5875d9f9e4b02fd3851c55e4', 464 | # '_subid': '5875e1f8e4b0ba28be0f8335', 465 | # 'by_app': [ 466 | # { 467 | # 'app': 5, 468 | # 'cat': 3, 469 | # 'clients': [ 470 | # { 471 | # 'mac': '80:2a:a8:f0:ef:78', 472 | # 'rx_bytes': 82297468, 473 | # 'rx_packets': 57565, 474 | # 'tx_bytes': 1710174, 475 | # 'tx_packets': 25324 476 | # } 477 | # ], 478 | # 'known_clients': 1, 479 | # 'rx_bytes': 82300120, 480 | # 'rx_packets': 57569, 481 | # 'tx_bytes': 1711971, 482 | # 'tx_packets': 25331 483 | # }, 484 | # { 485 | # 'app': 94, 486 | # 'cat': 19, 487 | # 'clients': [ 488 | # { 489 | # 'mac': '80:2a:a8:f0:ef:78', 490 | # 'rx_bytes': 1593846895, 491 | # 'rx_packets': 1738901, 492 | # 'tx_bytes': 348738675, 493 | # 'tx_packets': 2004045 494 | # } 495 | # ], 496 | # 'known_clients': 1, 497 | # 'rx_bytes': 1622602418, 498 | # 'rx_packets': 1760201, 499 | # 'tx_bytes': 349693010, 500 | # 'tx_packets': 2012708 501 | # }, 502 | # { 503 | # 'app': 209, 504 | # 'cat': 13, 505 | # 'rx_bytes': 43670, 506 | # 'rx_packets': 100, 507 | # 'tx_bytes': 20728, 508 | # 'tx_packets': 91 509 | # }, 510 | # { 511 | # 'app': 10, 512 | # 'cat': 4, 513 | # 'rx_bytes': 15273, 514 | # 'rx_packets': 15, 515 | # 'tx_bytes': 2728, 516 | # 'tx_packets': 23 517 | # }, 518 | # { 519 | # 'app': 133, 520 | # 'cat': 3, 521 | # 'clients': [ 522 | # { 523 | # 'mac': '80:2a:a8:f0:ef:78', 524 | # 'rx_bytes': 531190, 525 | # 'rx_packets': 2465, 526 | # 'tx_bytes': 676859, 527 | # 'tx_packets': 2760 528 | # } 529 | # ], 530 | # 'known_clients': 1, 531 | # 'rx_bytes': 531190, 532 | # 'rx_packets': 2465, 533 | # 'tx_bytes': 676859, 534 | # 'tx_packets': 2760 535 | # }, 536 | # { 537 | # 'app': 222, 538 | # 'cat': 13, 539 | # 'clients': [ 540 | # { 541 | # 'mac': '80:2a:a8:f0:ef:78', 542 | # 'rx_bytes': 3441437, 543 | # 'rx_packets': 3033, 544 | # 'tx_bytes': 203173, 545 | # 'tx_packets': 1468 546 | # } 547 | # ], 548 | # 'known_clients': 1, 549 | # 'rx_bytes': 3441437, 550 | # 'rx_packets': 3033, 551 | # 'tx_bytes': 203173, 552 | # 'tx_packets': 1468 553 | # }, 554 | # { 555 | # 'app': 23, 556 | # 'cat': 0, 557 | # 'clients': [ 558 | # { 559 | # 'mac': '80:2a:a8:f0:ef:78', 560 | # 'rx_bytes': 0, 561 | # 'rx_packets': 0, 562 | # 'tx_bytes': 145, 563 | # 'tx_packets': 2 564 | # } 565 | # ], 566 | # 'known_clients': 1, 567 | # 'rx_bytes': 0, 568 | # 'rx_packets': 0, 569 | # 'tx_bytes': 145, 570 | # 'tx_packets': 2 571 | # }, 572 | # { 573 | # 'app': 7, 574 | # 'cat': 0, 575 | # 'clients': [ 576 | # { 577 | # 'mac': '80:2a:a8:f0:ef:78', 578 | # 'rx_bytes': 0, 579 | # 'rx_packets': 0, 580 | # 'tx_bytes': 145, 581 | # 'tx_packets': 2 582 | # } 583 | # ], 584 | # 'known_clients': 1, 585 | # 'rx_bytes': 0, 586 | # 'rx_packets': 0, 587 | # 'tx_bytes': 145, 588 | # 'tx_packets': 2 589 | # }, 590 | # { 591 | # 'app': 7, 592 | # 'cat': 13, 593 | # 'clients': [ 594 | # { 595 | # 'mac': '80:2a:a8:f0:ef:78', 596 | # 'rx_bytes': 24417806554, 597 | # 'rx_packets': 18415873, 598 | # 'tx_bytes': 2817966897, 599 | # 'tx_packets': 9910192 600 | # } 601 | # ], 602 | # 'known_clients': 1, 603 | # 'rx_bytes': 24418175948, 604 | # 'rx_packets': 18416166, 605 | # 'tx_bytes': 2817991801, 606 | # 'tx_packets': 9910436 607 | # }, 608 | # { 609 | # 'app': 185, 610 | # 'cat': 20, 611 | # 'clients': [ 612 | # { 613 | # 'mac': '80:2a:a8:f0:ef:78', 614 | # 'rx_bytes': 28812050, 615 | # 'rx_packets': 208945, 616 | # 'tx_bytes': 160819147, 617 | # 'tx_packets': 1228992 618 | # } 619 | # ], 620 | # 'known_clients': 1, 621 | # 'rx_bytes': 28874120, 622 | # 'rx_packets': 209075, 623 | # 'tx_bytes': 160846366, 624 | # 'tx_packets': 1229161 625 | # }, 626 | # { 627 | # 'app': 65535, 628 | # 'cat': 255, 629 | # 'clients': [ 630 | # { 631 | # 'mac': '80:2a:a8:f0:ef:78', 632 | # 'rx_bytes': 182029551, 633 | # 'rx_packets': 1796815, 634 | # 'tx_bytes': 435732626, 635 | # 'tx_packets': 1933469 636 | # } 637 | # ], 638 | # 'known_clients': 1, 639 | # 'rx_bytes': 183022079, 640 | # 'rx_packets': 1798016, 641 | # 'tx_bytes': 435832672, 642 | # 'tx_packets': 1934359 643 | # }, 644 | # { 645 | # 'app': 12, 646 | # 'cat': 13, 647 | # 'rx_bytes': 92925290, 648 | # 'rx_packets': 70498, 649 | # 'tx_bytes': 17360839, 650 | # 'tx_packets': 69512 651 | # }, 652 | # { 653 | # 'app': 4, 654 | # 'cat': 10, 655 | # 'clients': [ 656 | # { 657 | # 'mac': '80:2a:a8:f0:ef:78', 658 | # 'rx_bytes': 1522, 659 | # 'rx_packets': 20, 660 | # 'tx_bytes': 882, 661 | # 'tx_packets': 12 662 | # } 663 | # ], 664 | # 'known_clients': 1, 665 | # 'rx_bytes': 1522, 666 | # 'rx_packets': 20, 667 | # 'tx_bytes': 882, 668 | # 'tx_packets': 12 669 | # }, 670 | # { 671 | # 'app': 106, 672 | # 'cat': 18, 673 | # 'clients': [ 674 | # { 675 | # 'mac': '80:2a:a8:f0:ef:78', 676 | # 'rx_bytes': 982710, 677 | # 'rx_packets': 10919, 678 | # 'tx_bytes': 1010970, 679 | # 'tx_packets': 11233 680 | # } 681 | # ], 682 | # 'known_clients': 1, 683 | # 'rx_bytes': 982710, 684 | # 'rx_packets': 10919, 685 | # 'tx_bytes': 1010970, 686 | # 'tx_packets': 11233 687 | # }, 688 | # { 689 | # 'app': 30, 690 | # 'cat': 18, 691 | # 'clients': [ 692 | # { 693 | # 'mac': '80:2a:a8:f0:ef:78', 694 | # 'rx_bytes': 7819852, 695 | # 'rx_packets': 20378, 696 | # 'tx_bytes': 1293104, 697 | # 'tx_packets': 18686 698 | # } 699 | # ], 700 | # 'known_clients': 1, 701 | # 'rx_bytes': 7819852, 702 | # 'rx_packets': 20378, 703 | # 'tx_bytes': 1293104, 704 | # 'tx_packets': 18686 705 | # }, 706 | # { 707 | # 'app': 1, 708 | # 'cat': 0, 709 | # 'clients': [ 710 | # { 711 | # 'mac': '80:2a:a8:f0:ef:78', 712 | # 'rx_bytes': 0, 713 | # 'rx_packets': 0, 714 | # 'tx_bytes': 145, 715 | # 'tx_packets': 2 716 | # } 717 | # ], 718 | # 'known_clients': 1, 719 | # 'rx_bytes': 0, 720 | # 'rx_packets': 0, 721 | # 'tx_bytes': 145, 722 | # 'tx_packets': 2 723 | # }, 724 | # { 725 | # 'app': 150, 726 | # 'cat': 3, 727 | # 'rx_bytes': 54609, 728 | # 'rx_packets': 71, 729 | # 'tx_bytes': 19749, 730 | # 'tx_packets': 85 731 | # }, 732 | # { 733 | # 'app': 95, 734 | # 'cat': 5, 735 | # 'rx_bytes': 9835, 736 | # 'rx_packets': 41, 737 | # 'tx_bytes': 3956, 738 | # 'tx_packets': 41 739 | # }, 740 | # { 741 | # 'app': 168, 742 | # 'cat': 20, 743 | # 'rx_bytes': 100583, 744 | # 'rx_packets': 204, 745 | # 'tx_bytes': 62503, 746 | # 'tx_packets': 296 747 | # }, 748 | # { 749 | # 'app': 3, 750 | # 'cat': 10, 751 | # 'rx_bytes': 12916, 752 | # 'rx_packets': 41, 753 | # 'tx_bytes': 11501, 754 | # 'tx_packets': 86 755 | # }, 756 | # { 757 | # 'app': 84, 758 | # 'cat': 13, 759 | # 'rx_bytes': 42563, 760 | # 'rx_packets': 102, 761 | # 'tx_bytes': 32676, 762 | # 'tx_packets': 113 763 | # }, 764 | # { 765 | # 'app': 84, 766 | # 'cat': 3, 767 | # 'rx_bytes': 62456, 768 | # 'rx_packets': 166, 769 | # 'tx_bytes': 101105, 770 | # 'tx_packets': 183 771 | # }, 772 | # { 773 | # 'app': 63, 774 | # 'cat': 18, 775 | # 'clients': [ 776 | # { 777 | # 'mac': '80:2a:a8:f0:ef:78', 778 | # 'rx_bytes': 780358, 779 | # 'rx_packets': 3520, 780 | # 'tx_bytes': 545757, 781 | # 'tx_packets': 6545 782 | # } 783 | # ], 784 | # 'known_clients': 1, 785 | # 'rx_bytes': 780358, 786 | # 'rx_packets': 3520, 787 | # 'tx_bytes': 545757, 788 | # 'tx_packets': 6545 789 | # }, 790 | # { 791 | # 'app': 8, 792 | # 'cat': 13, 793 | # 'clients': [ 794 | # { 795 | # 'mac': '80:2a:a8:f0:ef:78', 796 | # 'rx_bytes': 180691586, 797 | # 'rx_packets': 132204, 798 | # 'tx_bytes': 5970383, 799 | # 'tx_packets': 74482 800 | # } 801 | # ], 802 | # 'known_clients': 1, 803 | # 'rx_bytes': 180691586, 804 | # 'rx_packets': 132204, 805 | # 'tx_bytes': 5970383, 806 | # 'tx_packets': 74482 807 | # }, 808 | # { 809 | # 'app': 186, 810 | # 'cat': 20, 811 | # 'rx_bytes': 44618, 812 | # 'rx_packets': 68, 813 | # 'tx_bytes': 8826, 814 | # 'tx_packets': 86 815 | # }, 816 | # { 817 | # 'app': 21, 818 | # 'cat': 10, 819 | # 'clients': [ 820 | # { 821 | # 'mac': '80:2a:a8:f0:ef:78', 822 | # 'rx_bytes': 5521547718, 823 | # 'rx_packets': 73080390, 824 | # 'tx_bytes': 179999309100, 825 | # 'tx_packets': 130627577 826 | # } 827 | # ], 828 | # 'known_clients': 1, 829 | # 'rx_bytes': 5521547718, 830 | # 'rx_packets': 73080390, 831 | # 'tx_bytes': 179999309100, 832 | # 'tx_packets': 130627577 833 | # } 834 | # ], 835 | # 'by_cat': [ 836 | # { 837 | # 'apps': [ 838 | # 23, 839 | # 7, 840 | # 1 841 | # ], 842 | # 'cat': 0, 843 | # 'rx_bytes': 0, 844 | # 'rx_packets': 0, 845 | # 'tx_bytes': 435, 846 | # 'tx_packets': 6 847 | # }, 848 | # { 849 | # 'apps': [ 850 | # 5, 851 | # 133, 852 | # 150, 853 | # 84 854 | # ], 855 | # 'cat': 3, 856 | # 'rx_bytes': 82948375, 857 | # 'rx_packets': 60271, 858 | # 'tx_bytes': 2509684, 859 | # 'tx_packets': 28359 860 | # }, 861 | # { 862 | # 'apps': [ 863 | # 10 864 | # ], 865 | # 'cat': 4, 866 | # 'rx_bytes': 15273, 867 | # 'rx_packets': 15, 868 | # 'tx_bytes': 2728, 869 | # 'tx_packets': 23 870 | # }, 871 | # { 872 | # 'apps': [ 873 | # 95 874 | # ], 875 | # 'cat': 5, 876 | # 'rx_bytes': 9835, 877 | # 'rx_packets': 41, 878 | # 'tx_bytes': 3956, 879 | # 'tx_packets': 41 880 | # }, 881 | # { 882 | # 'apps': [ 883 | # 4, 884 | # 3, 885 | # 21 886 | # ], 887 | # 'cat': 10, 888 | # 'rx_bytes': 5521562156, 889 | # 'rx_packets': 73080451, 890 | # 'tx_bytes': 179999321483, 891 | # 'tx_packets': 130627675 892 | # }, 893 | # { 894 | # 'apps': [ 895 | # 209, 896 | # 222, 897 | # 7, 898 | # 12, 899 | # 84, 900 | # 8 901 | # ], 902 | # 'cat': 13, 903 | # 'rx_bytes': 24695320494, 904 | # 'rx_packets': 18622103, 905 | # 'tx_bytes': 2841579600, 906 | # 'tx_packets': 10056102 907 | # }, 908 | # { 909 | # 'apps': [ 910 | # 106, 911 | # 30, 912 | # 63 913 | # ], 914 | # 'cat': 18, 915 | # 'rx_bytes': 9582920, 916 | # 'rx_packets': 34817, 917 | # 'tx_bytes': 2849831, 918 | # 'tx_packets': 36464 919 | # }, 920 | # { 921 | # 'apps': [ 922 | # 94 923 | # ], 924 | # 'cat': 19, 925 | # 'rx_bytes': 1622602418, 926 | # 'rx_packets': 1760201, 927 | # 'tx_bytes': 349693010, 928 | # 'tx_packets': 2012708 929 | # }, 930 | # { 931 | # 'apps': [ 932 | # 185, 933 | # 168, 934 | # 186 935 | # ], 936 | # 'cat': 20, 937 | # 'rx_bytes': 29019321, 938 | # 'rx_packets': 209347, 939 | # 'tx_bytes': 160917695, 940 | # 'tx_packets': 1229543 941 | # }, 942 | # { 943 | # 'apps': [ 944 | # 65535 945 | # ], 946 | # 'cat': 255, 947 | # 'rx_bytes': 183022079, 948 | # 'rx_packets': 1798016, 949 | # 'tx_bytes': 435832672, 950 | # 'tx_packets': 1934359 951 | # } 952 | # ], 953 | # 'initialized': '88121276686', 954 | # 'is_ugw': True 955 | # } 956 | # ], 957 | # 'has_eth1': True, 958 | # 'has_porta': True, 959 | # 'has_ssh_disable': True, 960 | # 'has_vti': True, 961 | # 'hostname': 'pfSense', 962 | # 'inform_url': 'http://192.168.0.7:8080/inform', 963 | # 'ip': '82.238.9.250', 964 | # 'isolated': False, 965 | # 'locating': False, 966 | # 'mac': gateway_lan_mac, 967 | # 'model': 'UGW3', 968 | # 'model_display': 'UniFi-Gateway-3', 969 | # 'netmask': '255.255.248.0', 970 | # 'required_version': '4.0.0', 971 | # 'selfrun_beacon': True, 972 | # 'serial': gateway_lan_mac.replace(':', ''), 973 | # 'pfor-stats': [ 974 | # { 975 | # 'id': '596add99e4b0a76e35003e00', 976 | # 'rx_bytes': 41444574, 977 | # 'rx_packets': 305634, 978 | # 'tx_bytes': 88048319, 979 | # 'tx_packets': 364768 980 | # } 981 | # ], 982 | # 'speedtest-status': { 983 | # 'latency': 9, 984 | # 'rundate': int(time.time()), 985 | # 'runtime': 6, 986 | # 'status_download': 2, 987 | # 'status_ping': 2, 988 | # 'status_summary': 2, 989 | # 'status_upload': 2, 990 | # 'xput_download': 385.30819702148, 991 | # 'xput_upload': 68.445808410645 992 | # }, 993 | # 'state': 2, 994 | # 'system-stats': { 995 | # 'cpu': '%s' % psutil.cpu_percent(), 996 | # 'mem': '%s' % (100 - psutil.virtual_memory()[2]), 997 | # 'uptime': '%s' % uptime() 998 | # }, 999 | # 'time': int(time.time()), 1000 | # 'uplink': 'eth0', 1001 | # 'uptime': uptime(), 1002 | # 'routes': [ 1003 | # { 1004 | # 'nh': [ 1005 | # { 1006 | # 'intf': 'eth0', 1007 | # 'metric': '1/0', 1008 | # 't': 'S>*', 1009 | # 'via': '20.1.1.1' 1010 | # } 1011 | # ], 1012 | # 'pfx': '0.0.0.0/0' 1013 | # }, 1014 | # { 1015 | # 'nh': [ 1016 | # { 1017 | # 'intf': 'eth2', 1018 | # 'metric': '220/0', 1019 | # 't': 'S ', 1020 | # 'via': '10.1.1.1' 1021 | # } 1022 | # ], 1023 | # 'pfx': '0.0.0.0/0' 1024 | # }, 1025 | # { 1026 | # 'nh': [ 1027 | # { 1028 | # 'intf': 'eth2', 1029 | # 'metric': '1/0', 1030 | # 't': 'S ' 1031 | # } 1032 | # ], 1033 | # 'pfx': '10.1.1.0/24' 1034 | # }, 1035 | # { 1036 | # 'nh': [ 1037 | # { 1038 | # 'intf': 'eth2', 1039 | # 't': 'C>*' 1040 | # } 1041 | # ], 1042 | # 'pfx': '10.1.1.0/24' 1043 | # }, 1044 | # { 1045 | # 'nh': [ 1046 | # { 1047 | # 'intf': 'lo', 1048 | # 't': 'C>*' 1049 | # } 1050 | # ], 1051 | # 'pfx': '127.0.0.0/8' 1052 | # }, 1053 | # { 1054 | # 'nh': [ 1055 | # { 1056 | # 'intf': 'eth1', 1057 | # 't': 'C>*' 1058 | # } 1059 | # ], 1060 | # 'pfx': '192.168.1.0/24' 1061 | # }, 1062 | # { 1063 | # 'nh': [ 1064 | # { 1065 | # 'intf': 'eth0', 1066 | # 't': 'C>*' 1067 | # } 1068 | # ], 1069 | # 'pfx': '20.1.1.0/21' 1070 | # } 1071 | # ], 1072 | # 'network_table': [ 1073 | # { 1074 | # 'address': '192.168.1.1/24', 1075 | # 'addresses': [ 1076 | # '%s/24' % gateway_lan_ip 1077 | # ], 1078 | # 'autoneg': 'true', 1079 | # 'duplex': 'full', 1080 | # 'host_table': [ 1081 | # { 1082 | # 'age': 0, 1083 | # 'authorized': True, 1084 | # 'bc_bytes': 4814073447, 1085 | # 'bc_packets': 104642338, 1086 | # 'dev_cat': 1, 1087 | # 'dev_family': 4, 1088 | # 'dev_id': 239, 1089 | # 'dev_vendor': 47, 1090 | # 'ip': '192.168.1.8', 1091 | # 'mac': '80:2a:a8:f0:ef:78', 1092 | # 'mc_bytes': 4814073447, 1093 | # 'mc_packets': 104642338, 1094 | # 'os_class': 15, 1095 | # 'os_name': 19, 1096 | # 'rx_bytes': 802239963372, 1097 | # 'rx_packets': 805925675, 1098 | # 'tx_bytes': 35371476651, 1099 | # 'tx_packets': 104136843, 1100 | # 'uptime': 5822032 1101 | # }, 1102 | # { 1103 | # 'age': 41, 1104 | # 'authorized': True, 1105 | # 'bc_bytes': 9202676, 1106 | # 'bc_packets': 200043, 1107 | # 'hostname': 'switch', 1108 | # 'ip': '192.168.1.10', 1109 | # 'mac': 'f0:9f:c2:09:2b:f2', 1110 | # 'mc_bytes': 21366640, 1111 | # 'mc_packets': 406211, 1112 | # 'rx_bytes': 30862046, 1113 | # 'rx_packets': 610310, 1114 | # 'tx_bytes': 13628015, 1115 | # 'tx_packets': 204110, 1116 | # 'uptime': 5821979 1117 | # }, 1118 | # { 1119 | # 'age': 8, 1120 | # 'authorized': True, 1121 | # 'bc_bytes': 2000, 1122 | # 'bc_packets': 3000, 1123 | # 'mac': 'f0:9f:c2:09:2b:f3', 1124 | # 'mc_bytes': 21232297, 1125 | # 'mc_packets': 206139, 1126 | # 'rx_bytes': 21232297, 1127 | # 'rx_packets': 206139, 1128 | # 'tx_bytes': 4000, 1129 | # 'tx_packets': 5000, 1130 | # 'uptime': 5822017 1131 | # } 1132 | # ], 1133 | # 'l1up': 'true', 1134 | # 'mac': '80:2a:a8:cd:a9:53', 1135 | # 'mtu': '1500', 1136 | # 'name': 'eth1', 1137 | # 'speed': '1000', 1138 | # 'stats': { 1139 | # 'multicast': '412294', 1140 | # 'rx_bps': '342', 1141 | # 'rx_bytes': 52947224765, 1142 | # 'rx_dropped': 2800, 1143 | # 'rx_errors': 0, 1144 | # 'rx_multicast': 412314, 1145 | # 'rx_packets': 341232922, 1146 | # 'tx_bps': '250', 1147 | # 'tx_bytes': 792205417381, 1148 | # 'tx_dropped': 0, 1149 | # 'tx_errors': 0, 1150 | # 'tx_packets': 590930778 1151 | # }, 1152 | # 'up': 'true' 1153 | # }, 1154 | # { 1155 | # 'address': '20.1.2.10/21', 1156 | # 'addresses': [ 1157 | # '20.1.2.10/21' 1158 | # ], 1159 | # 'autoneg': 'true', 1160 | # 'duplex': 'full', 1161 | # 'gateways': [ 1162 | # '20.1.1.1' 1163 | # ], 1164 | # 'l1up': 'true', 1165 | # 'mac': gateway_wan_mac, 1166 | # 'mtu': '1500', 1167 | # 'name': 'eth0', 1168 | # 'nameservers': [ 1169 | # gateway_lan_ip, 1170 | # '212.27.40.240', 1171 | # '212.27.40.241' 1172 | # ], 1173 | # 'speed': '1000', 1174 | # 'stats': { 1175 | # 'multicast': '65627', 1176 | # 'rx_bps': '262', 1177 | # 'rx_bytes': 353519562926, 1178 | # 'rx_dropped': 19137, 1179 | # 'rx_errors': 0, 1180 | # 'rx_multicast': 65629, 1181 | # 'rx_packets': 645343103, 1182 | # 'tx_bps': '328', 1183 | # 'tx_bytes': 953646055362, 1184 | # 'tx_dropped': 0, 1185 | # 'tx_errors': 0, 1186 | # 'tx_packets': 863173990 1187 | # }, 1188 | # 'up': 'true' 1189 | # } 1190 | # ], 1191 | # 'if_table': [ 1192 | # { 1193 | # 'drops': 333, 1194 | # 'enable': True, 1195 | # 'full_duplex': True, 1196 | # 'gateways': [ 1197 | # gateway_lan_ip 1198 | # ], 1199 | # 'ip': gateway_wan_ip, 1200 | # 'latency': randint(0, 200), 1201 | # 'mac': gateway_wan_mac, 1202 | # 'name': 'eth0', 1203 | # 'nameservers': [ 1204 | # gateway_lan_ip, 1205 | # '212.27.40.240', 1206 | # '212.27.40.241' 1207 | # ], 1208 | # 'netmask': '255.255.255.0', 1209 | # 'num_port': 1, 1210 | # 'rx_bytes': 353519562926 + randint(0, 200000), 1211 | # 'rx_dropped': 19137 + randint(0, 2000), 1212 | # 'rx_errors': 0, 1213 | # 'rx_multicast': 65629 + randint(0, 2000), 1214 | # 'rx_packets': 645343103 + randint(0, 200000), 1215 | # 'speed': 1000, 1216 | # 'speedtest_lastrun': int(time.time()), 1217 | # 'speedtest_ping': randint(0, 2000), 1218 | # 'speedtest_status': 'Idle', 1219 | # 'tx_bytes': 953646055362 + randint(0, 200000), 1220 | # 'tx_dropped': 0, 1221 | # 'tx_errors': 0, 1222 | # 'tx_packets': 863173990 + randint(0, 200000), 1223 | # 'up': True, 1224 | # 'uptime': uptime(), 1225 | # 'xput_down': randint(0, 100), 1226 | # 'xput_up': randint(0, 30) 1227 | # }, 1228 | # { 1229 | # 'enable': True, 1230 | # 'full_duplex': True, 1231 | # 'ip': gateway_lan_ip, 1232 | # 'mac': '80:2a:a8:cd:a9:53', 1233 | # 'name': 'eth1', 1234 | # 'netmask': '255.255.255.0', 1235 | # 'num_port': 1, 1236 | # 'rx_bytes': 807912794876, 1237 | # 'rx_dropped': 2800, 1238 | # 'rx_errors': 0, 1239 | # 'rx_multicast': 412314, 1240 | # 'rx_packets': 700376545, 1241 | # 'speed': 1000, 1242 | # 'tx_bytes': 58901673253, 1243 | # 'tx_dropped': 0, 1244 | # 'tx_errors': 0, 1245 | # 'tx_packets': 347161831, 1246 | # 'up': True 1247 | # }, 1248 | # { 1249 | # 'enable': False, 1250 | # 'full_duplex': True, 1251 | # 'up': False 1252 | # } 1253 | # ], 1254 | # 'version': '4.3.49.5001150', 1255 | # }) 1256 | pass 1257 | 1258 | 1259 | def create_inform(config): 1260 | return _create_partial_inform(config) if not config.getboolean('gateway', 'is_adopted') else _create_complete_inform(config) 1261 | 1262 | 1263 | def create_broadcast_message(config, index, version=2, command=6): 1264 | lan_mac = config.get('gateway', 'lan_mac') 1265 | lan_ip = config.get('gateway', 'lan_ip') 1266 | firmware = config.get('gateway', 'firmware') 1267 | device = config.get('gateway', 'device') 1268 | 1269 | tlv = UnifiTLV() 1270 | tlv.add(1, bytearray(mac_string_2_array(lan_mac))) 1271 | tlv.add(2, bytearray(mac_string_2_array(lan_mac) + ip_string_2_array(lan_ip))) 1272 | tlv.add(3, bytearray('{}.v{}'.format(device, firmware))) 1273 | tlv.add(10, bytearray([ord(c) for c in pack('!I', uptime())])) 1274 | tlv.add(11, bytearray('PFSENSE')) 1275 | tlv.add(12, bytearray(device)) 1276 | tlv.add(19, bytearray(mac_string_2_array(lan_mac))) 1277 | tlv.add(18, bytearray([ord(c) for c in pack('!I', index)])) 1278 | tlv.add(21, bytearray(device)) 1279 | tlv.add(27, bytearray(firmware)) 1280 | tlv.add(22, bytearray(firmware)) 1281 | return tlv.get(version=version, command=command) 1282 | --------------------------------------------------------------------------------