-
Notifications
You must be signed in to change notification settings - Fork 0
/
dhcp6-prefix-config.py
executable file
·136 lines (106 loc) · 4.29 KB
/
dhcp6-prefix-config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/bin/env python
'''
This script will dynamically generate a dhcpd6.conf file for
prefix delegation. An example scenario, using default variables:
Server (public, dynamic) IPv6 address on eth0:
2601:43:0:1000:abcd:abcd:abcd:2ddc/64
First delegated prefix for delegation (delegation_offset = 1):
2601:43:0:1001::/64
Last delegated prefix (delegation_range = 2):
2601:43:0:1002::/64
Offset can be a negative value, if you want to place your delegations
below the local subnet. 'delegation_range' is essentially the number
of ::/64 prefixes you want to delegate.
In additional to setting up prefixes for delegation, the config
generated by this script will also set up a pool of DHCP6 addresses
that can be used by clients on the local link in the case where
they are choosing to use DHCP rather than SLAAC for autoconfig.
The client IP pool generated by this config will be converted to
an IPv6 quad (hex) as needed, while the config variables here expect
a decimal input. For example if client_offset = 101 and
client_range = 100, then the generated client pool would be:
range6 2601:43:0:1000::65 2601:43:0:1000::c8;
This script has been tested on on CentOS 7, Python 2.7.
Also requires: python-netaddr, python-jinja2
'''
### start configurables
conf_file = '/etc/dhcp/dhcpd6.conf'
iface = 'eth0'
delegation_offset = 1 # relative to my local prefix (can be negative)
delegation_range = 2 # how many ::/64 prefixes to delegate
client_offset = 101 # start address for client on my local link (converts to hex in config)
client_range = 100 # size of DHCP client range
default_lease_time = 604800 # dhcp6 vltime
preferred_lifetime = 345600 # dhcp6 pltime
name_servers = '2001:558:FEED::1,2001:558:FEED::2' # enter the correct nameservers for your ISP
### end configurables
from filecmp import cmp
from jinja2 import Template
from shutil import copyfile
from tempfile import mkstemp
import datetime, netaddr, os, re, subprocess, sys
import logging, logging.handlers
# set up logging
my_logger = logging.getLogger(__name__)
my_logger.setLevel(logging.DEBUG)
handler = logging.handlers.SysLogHandler(address = '/dev/log')
my_logger.addHandler(handler)
formatter = logging.Formatter('%(module)s: %(message)s')
handler.setFormatter(formatter)
# get server's global IPv6 address, use it to calculate DHCP server configs params
ipout = subprocess.Popen(
['/usr/sbin/ip', '-6', 'addr', 'list', 'dev', iface, 'scope', 'global'],
stdout=subprocess.PIPE)
prot, ipaddr = re.findall(r'inet6.*/\d{1,2}', ipout.stdout.read())[0].split(" ")
ip = netaddr.IPNetwork(ipaddr)
# DHCP server's prefix
my_quad = list(ip.network.words)
my_prefix = str(ip.network) + '/' + str(ip.prefixlen)
# calculate the starting prefix to delegate
start_quad = my_quad
start_quad[3] = start_quad[3] + delegation_offset
s = [str(hex(i)).lstrip('0x') for i in start_quad]
start_prefix = ':'.join([s[0], s[1], s[2], s[3]]) + '::'
# calculate the end prefix to delegate
end_quad = start_quad
end_quad[3] = end_quad[3] + delegation_range - 1
e = [str(hex(i)).lstrip('0x') for i in end_quad]
end_prefix = ':'.join([e[0], e[1], e[2], e[3]]) + '::'
# define our DHCP server config template
config = Template('''# generated by {{ script }}
#
default-lease-time {{ ldefault }};
preferred-lifetime {{ lpreferred }};
log-facility local7;
option dhcp6.name-servers {{ ns }};
subnet6 {{ subnet6 }} {
# Range for clients
range6 {{ range_start }} {{ range_end }};
# Prefix range for delegation to sub-routers
prefix6 {{ prefix_start }} {{ prefix_end }} /64;
}
''')
# open temp file, write config
fd, temp_file = mkstemp(prefix="dhcp6s.")
os.write(fd, config.render(
ldefault=str(default_lease_time),
lpreferred=str(preferred_lifetime),
script=os.path.basename(__file__),
range_start=ip[client_offset],
range_end=ip[client_offset + client_range -1],
prefix_start=start_prefix,
prefix_end=end_prefix,
subnet6=my_prefix,
ns=name_servers
)
)
os.close(fd)
# if new config differs from running config, install and restart server
if cmp(temp_file, conf_file):
test = "foobar"
my_logger.info('dhcpd6 configuration unchanged')
else:
copyfile(temp_file, conf_file)
os.remove(temp_file)
my_logger.info('dhcpd6 configuration updated')
subprocess.call(['systemctl', 'restart', 'dhcpd6'])