|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +import ipaddress, argparse, itertools |
| 4 | + |
| 5 | +def hexroute(routes: list, uppercase=True) -> str: |
| 6 | + ''' |
| 7 | + Takes a list of lists or tuples in the form ('network/prefix', 'gateway_ip') |
| 8 | + and returns a DHCP option 121/249 hex string |
| 9 | +
|
| 10 | + >>> hexroute([('192.168.100.0/24','192.168.100.1')]) |
| 11 | + '18:C0:A8:64:C0:A8:64:01' |
| 12 | + >>> hexroute([('172.16.0.0/24', '172.16.0.1')]) |
| 13 | + '18:AC:10:00:AC:10:00:01' |
| 14 | + >>> hexroute([('10.1.1.10/8', '10.254.254.1')]) |
| 15 | + '08:0A:0A:FE:FE:01' |
| 16 | + >>> hexroute([('192.168.1.0/23','192.168.0.1'), ('192.168.0.0/23', '192.168.0.1')]) |
| 17 | + '17:C0:A8:00:C0:A8:00:01' |
| 18 | + ''' |
| 19 | + |
| 20 | + hex = [] |
| 21 | + networks = [] |
| 22 | + for route in routes: |
| 23 | + net = ipaddress.IPv4Network(route[0], strict=False) |
| 24 | + if net in networks: |
| 25 | + continue |
| 26 | + prefix = net.prefixlen |
| 27 | + net_address = [int(i) for i in str(net.network_address).split('.')] |
| 28 | + gateway_address = [int(i) for i in str(route[1]).split('.')] |
| 29 | + octets = [] |
| 30 | + if prefix > 0: |
| 31 | + octets.append(net_address[0]) |
| 32 | + if prefix > 8: |
| 33 | + octets.append(net_address[1]) |
| 34 | + if prefix > 16: |
| 35 | + octets.append(net_address[2]) |
| 36 | + if prefix > 24: |
| 37 | + octets.append(net_address[3]) |
| 38 | + container = [prefix] |
| 39 | + container += octets |
| 40 | + container += gateway_address |
| 41 | + hex += ['{:02X}'.format(i) for i in container] |
| 42 | + networks.append(net) |
| 43 | + |
| 44 | + opt249str = ':'.join(hex) |
| 45 | + if not uppercase: |
| 46 | + return opt249str.lower() |
| 47 | + return opt249str |
| 48 | + |
| 49 | +def hexroute_reverse(hex_string): |
| 50 | + ''' |
| 51 | + Takes a hexadecimal DHCP option 249 string and returns the IPv4 networks and their gateways |
| 52 | +
|
| 53 | + >>> hexroute_reverse('18:C0:A8:64:C0:A8:64:01') |
| 54 | + [(IPv4Network('192.168.100.0/24'), IPv4Address('192.168.100.1'))] |
| 55 | + >>> hexroute_reverse('18:AC:10:00:AC:10:00:01') |
| 56 | + [(IPv4Network('172.16.0.0/24'), IPv4Address('172.16.0.1'))] |
| 57 | + >>> hexroute_reverse('08:0A:0A:FE:FE:01') |
| 58 | + [(IPv4Network('10.0.0.0/8'), IPv4Address('10.254.254.1'))] |
| 59 | + >>> hexroute_reverse('17:C0:A8:00:C0:A8:00:01') |
| 60 | + [(IPv4Network('192.168.0.0/23'), IPv4Address('192.168.0.1'))] |
| 61 | + ''' |
| 62 | + |
| 63 | + decimal_vals = [int(i, 16) for i in hex_string.split(':')] |
| 64 | + routes = [] |
| 65 | + while len(decimal_vals): |
| 66 | + next = 0 |
| 67 | + subnet = decimal_vals.pop(0) |
| 68 | + for i in (0, 8, 16, 24): |
| 69 | + if subnet > i: |
| 70 | + next += 1 |
| 71 | + subnet_octets = decimal_vals[:next] |
| 72 | + while len(subnet_octets) < 4: |
| 73 | + subnet_octets.append(0) |
| 74 | + network = ipaddress.IPv4Network('.'.join([str(i) for i in subnet_octets]) + '/{}'.format(subnet), strict=False) |
| 75 | + del decimal_vals[:next] |
| 76 | + gateway_address = decimal_vals[:4] |
| 77 | + gateway = ipaddress.IPv4Address('.'.join([str(i) for i in gateway_address])) |
| 78 | + del decimal_vals[:4] |
| 79 | + routes.append((network, gateway)) |
| 80 | + return routes |
| 81 | + |
| 82 | +if __name__ == '__main__': |
| 83 | + parser = argparse.ArgumentParser(description = 'Generate or parse a DHCP option 249 hexadecimal string') |
| 84 | + group = parser.add_mutually_exclusive_group(required=True) |
| 85 | + group.add_argument( |
| 86 | + '-r', |
| 87 | + '--route', |
| 88 | + help='Specify a network/gateway pair', |
| 89 | + metavar=('192.168.0.0/16', '192.168.0.1'), |
| 90 | + nargs=2, |
| 91 | + action='append' |
| 92 | + ) |
| 93 | + group.add_argument( |
| 94 | + '-R', |
| 95 | + '--reverse', |
| 96 | + help='Convert an option 121/249 hex string into IPv4 network/route pairs', |
| 97 | + metavar='18:C0:A8:64:C0:A8:64:01' |
| 98 | + ) |
| 99 | + args = parser.parse_args() |
| 100 | + if args.route: |
| 101 | + print(hexroute(args.route)) |
| 102 | + if args.reverse: |
| 103 | + print(hexroute_reverse(args.reverse)) |
0 commit comments