Skip to content

Instantly share code, notes, and snippets.

@maxried
Created December 4, 2020 12:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxried/61f4a422c9c1b2f5698f02f43c3d5159 to your computer and use it in GitHub Desktop.
Save maxried/61f4a422c9c1b2f5698f02f43c3d5159 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
from ipaddress import IPv4Network, collapse_addresses
from argparse import ArgumentParser, RawDescriptionHelpFormatter
from typing import List
def main():
parser = ArgumentParser(description='Create excluding IPv4 routing tables, and simplify IPv4 routing tables.',
formatter_class=RawDescriptionHelpFormatter,
epilog='Examples:\n'
'198.51.100.0/25, and 198.51.100.128/25 will be merged to 198.51.100.0/24:\n'
'\troute-tool -s 198.51.100.0/25 198.51.100.128/25\n'
'\n'
'Create a set of routes which are nearly default, but exclude two subnets:\n'
'\troute-tool -e 198.51.100.0/24 203.0.113.0/24\n'
'\n'
'Route your network through a VPN, but exclude the VPN server at 192.0.2.62:\n'
'\troute-tool -i 192.0.2.0/24 -e 192.0.2.62')
parser.add_argument('--include', '-i', type=IPv4Network, nargs='*', default=[IPv4Network('0.0.0.0/0')],
help='The positive routing table. Defaults to 0.0.0.0/0.')
parser.add_argument('--exclude', '-e', type=IPv4Network, nargs='*', default=[],
help='The negative routing table, i. e. the list of networks to exclude from the positive '
'routing table. Defaults to empty list.')
parser.add_argument('--simplify', '-s', action='store_const', default=False, const=True,
help='Simplify the resulting routing table by merging adjacent networks.')
args = parser.parse_args()
result: List[IPv4Network] = []
include: IPv4Network
for include in args.include:
to_add = [include]
exclude: IPv4Network
something_changed = True
while something_changed:
something_changed = False
for exclude in args.exclude:
for net in to_add:
if net.subnet_of(exclude):
to_add = []
something_changed = True
break
elif exclude.subnet_of(net):
to_add.remove(net)
to_add.extend(net.address_exclude(exclude))
something_changed = True
break
if something_changed:
break
result.extend(to_add)
if args.simplify:
result = list(collapse_addresses(result))
for i in result:
print(f'{i.network_address}/{i.prefixlen}')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment