]>
Commit | Line | Data |
---|---|---|
1 | #!/bin/bash | |
2 | # dhclient-script for Linux. Dan Halbert, March, 1997. | |
3 | # Updated for Linux 2.[12] by Brian J. Murrell, January 1999. | |
4 | # No guarantees about this. I'm a novice at the details of Linux | |
5 | # networking. | |
6 | ||
7 | # Notes: | |
8 | ||
9 | # 0. This script is based on the netbsd script supplied with dhcp-970306. | |
10 | ||
11 | # 1. ifconfig down apparently deletes all relevant routes and flushes | |
12 | # the arp cache, so this doesn't need to be done explicitly. | |
13 | ||
14 | # 2. The alias address handling here has not been tested AT ALL. | |
15 | # I'm just going by the doc of modern Linux ip aliasing, which uses | |
16 | # notations like eth0:0, eth0:1, for each alias. | |
17 | ||
18 | # 3. I have to calculate the network address, and calculate the broadcast | |
19 | # address if it is not supplied. This might be much more easily done | |
20 | # by the dhclient C code, and passed on. | |
21 | ||
22 | # 4. TIMEOUT not tested. ping has a flag I don't know, and I'm suspicious | |
23 | # of the $1 in its args. | |
24 | ||
25 | # 5. Script refresh in 2017. The aliasing code was too convoluted and needs | |
26 | # to go away. Migrated DHCPv4 script to ip command from iproute2 suite. | |
27 | # This is based on Debian script with some tweaks. ifconfig is no longer | |
28 | # used. Everything is done using ip tool from ip-route2. | |
29 | ||
30 | # 6. LXC Fork | |
31 | # Remove hooks and dependency on ifconfig. | |
32 | # Resolve every paths against the $ROOTFS environment variable. | |
33 | ||
34 | # 'ip' just looks too weird. Also, we now have unit-tests! Those unit-tests | |
35 | # override this line to use a fake ip-echo tool. It's also convenient | |
36 | # if your system holds ip tool in a non-standard location. | |
37 | ip=/sbin/ip | |
38 | ||
39 | # update /etc/resolv.conf based on received values | |
40 | # This updated version mostly follows Debian script by Andrew Pollock et al. | |
41 | make_resolv_conf() { | |
42 | local resolv_conf="${ROOTFS}/etc/resolv.conf" | |
43 | local new_resolv_conf="${ROOTFS}/etc/resolv.conf.dhclient-new" | |
44 | ||
45 | # DHCPv4 | |
46 | if [ -n "$new_domain_search" ] || [ -n "$new_domain_name" ] || | |
47 | [ -n "$new_domain_name_servers" ]; then | |
48 | rm -f $new_resolv_conf | |
49 | ||
50 | if [ -n "$new_domain_name" ]; then | |
51 | echo domain ${new_domain_name%% *} >>$new_resolv_conf | |
52 | fi | |
53 | ||
54 | if [ -n "$new_domain_search" ]; then | |
55 | if [ -n "$new_domain_name" ]; then | |
56 | domain_in_search_list="" | |
57 | for domain in $new_domain_search; do | |
58 | if [ "$domain" = "${new_domain_name}" ] || | |
59 | [ "$domain" = "${new_domain_name}." ]; then | |
60 | domain_in_search_list="Yes" | |
61 | fi | |
62 | done | |
63 | if [ -z "$domain_in_search_list" ]; then | |
64 | new_domain_search="$new_domain_name $new_domain_search" | |
65 | fi | |
66 | fi | |
67 | echo "search ${new_domain_search}" >> $new_resolv_conf | |
68 | elif [ -n "$new_domain_name" ]; then | |
69 | echo "search ${new_domain_name}" >> $new_resolv_conf | |
70 | fi | |
71 | ||
72 | if [ -n "$new_domain_name_servers" ]; then | |
73 | for nameserver in $new_domain_name_servers; do | |
74 | echo nameserver $nameserver >>$new_resolv_conf | |
75 | done | |
76 | else # keep 'old' nameservers | |
77 | sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p $resolv_conf >>$new_resolv_conf | |
78 | fi | |
79 | ||
80 | if [ -f "$resolv_conf" ]; then | |
81 | chown --reference=$resolv_conf $new_resolv_conf | |
82 | chmod --reference=$resolv_conf $new_resolv_conf | |
83 | fi | |
84 | mv -f $new_resolv_conf $resolv_conf | |
85 | # DHCPv6 | |
86 | elif [ -n "$new_dhcp6_domain_search" ] || [ -n "$new_dhcp6_name_servers" ]; then | |
87 | rm -f $new_resolv_conf | |
88 | ||
89 | if [ -n "$new_dhcp6_domain_search" ]; then | |
90 | echo "search ${new_dhcp6_domain_search}" >> $new_resolv_conf | |
91 | fi | |
92 | ||
93 | if [ -n "$new_dhcp6_name_servers" ]; then | |
94 | for nameserver in $new_dhcp6_name_servers; do | |
95 | # append %interface to link-local-address nameservers | |
96 | if [ "${nameserver##fe80::}" != "$nameserver" ] || | |
97 | [ "${nameserver##FE80::}" != "$nameserver" ]; then | |
98 | nameserver="${nameserver}%${interface}" | |
99 | fi | |
100 | echo nameserver $nameserver >>$new_resolv_conf | |
101 | done | |
102 | else # keep 'old' nameservers | |
103 | sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p $resolv_conf >>$new_resolv_conf | |
104 | fi | |
105 | ||
106 | if [ -f "$resolv_conf" ]; then | |
107 | chown --reference=$resolv_conf $new_resolv_conf | |
108 | chmod --reference=$resolv_conf $new_resolv_conf | |
109 | fi | |
110 | mv -f $new_resolv_conf $resolv_conf | |
111 | fi | |
112 | } | |
113 | ||
114 | # set host name | |
115 | set_hostname() { | |
116 | local current_hostname | |
117 | ||
118 | if [ -n "$new_host_name" ]; then | |
119 | current_hostname=$(hostname) | |
120 | ||
121 | # current host name is empty, '(none)' or 'localhost' or differs from new one from DHCP | |
122 | if [ -z "$current_hostname" ] || | |
123 | [ "$current_hostname" = '(none)' ] || | |
124 | [ "$current_hostname" = 'localhost' ] || | |
125 | [ "$current_hostname" = "$old_host_name" ]; then | |
126 | if [ "$new_host_name" != "$old_host_name" ]; then | |
127 | hostname "$new_host_name" | |
128 | fi | |
129 | fi | |
130 | fi | |
131 | } | |
132 | ||
133 | # Execute the operation | |
134 | case "$reason" in | |
135 | ||
136 | ### DHCPv4 Handlers | |
137 | ||
138 | MEDIUM|ARPCHECK|ARPSEND) | |
139 | # Do nothing | |
140 | ;; | |
141 | PREINIT) | |
142 | # The DHCP client is requesting that an interface be | |
143 | # configured as required in order to send packets prior to | |
144 | # receiving an actual address. - dhclient-script(8) | |
145 | ||
146 | # ensure interface is up | |
147 | ${ip} link set dev ${interface} up | |
148 | ||
149 | if [ -n "$alias_ip_address" ]; then | |
150 | # flush alias IP from interface | |
151 | ${ip} -4 addr flush dev ${interface} label ${interface}:0 | |
152 | fi | |
153 | ||
154 | ;; | |
155 | ||
156 | BOUND|RENEW|REBIND|REBOOT) | |
157 | set_hostname | |
158 | ||
159 | if [ -n "$old_ip_address" ] && [ -n "$alias_ip_address" ] && | |
160 | [ "$alias_ip_address" != "$old_ip_address" ]; then | |
161 | # alias IP may have changed => flush it | |
162 | ${ip} -4 addr flush dev ${interface} label ${interface}:0 | |
163 | fi | |
164 | ||
165 | if [ -n "$old_ip_address" ] && | |
166 | [ "$old_ip_address" != "$new_ip_address" ]; then | |
167 | # leased IP has changed => flush it | |
168 | ${ip} -4 addr flush dev ${interface} label ${interface} | |
169 | fi | |
170 | ||
171 | if [ -z "$old_ip_address" ] || | |
172 | [ "$old_ip_address" != "$new_ip_address" ] || | |
173 | [ "$reason" = "BOUND" ] || [ "$reason" = "REBOOT" ]; then | |
174 | # new IP has been leased or leased IP changed => set it | |
175 | ${ip} -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \ | |
176 | ${new_broadcast_address:+broadcast $new_broadcast_address} \ | |
177 | dev ${interface} label ${interface} | |
178 | ||
179 | if [ -n "$new_interface_mtu" ]; then | |
180 | # set MTU | |
181 | ${ip} link set dev ${interface} mtu ${new_interface_mtu} | |
182 | fi | |
183 | ||
184 | # if we have $new_rfc3442_classless_static_routes then we have to | |
185 | # ignore $new_routers entirely | |
186 | if [ ! "$new_rfc3442_classless_static_routes" ]; then | |
187 | # set if_metric if IF_METRIC is set or there's more than one router | |
188 | if_metric="$IF_METRIC" | |
189 | if [ "${new_routers%% *}" != "${new_routers}" ]; then | |
190 | if_metric=${if_metric:-1} | |
191 | fi | |
192 | ||
193 | for router in $new_routers; do | |
194 | if [ "$new_subnet_mask" = "255.255.255.255" ]; then | |
195 | # point-to-point connection => set explicit route | |
196 | ${ip} -4 route add ${router} dev $interface >/dev/null 2>&1 | |
197 | fi | |
198 | ||
199 | # set default route | |
200 | ${ip} -4 route add default via ${router} dev ${interface} \ | |
201 | ${if_metric:+metric $if_metric} >/dev/null 2>&1 | |
202 | ||
203 | if [ -n "$if_metric" ]; then | |
204 | if_metric=$((if_metric+1)) | |
205 | fi | |
206 | done | |
207 | fi | |
208 | fi | |
209 | ||
210 | if [ -n "$alias_ip_address" ] && | |
211 | [ "$new_ip_address" != "$alias_ip_address" ]; then | |
212 | # separate alias IP given, which may have changed | |
213 | # => flush it, set it & add host route to it | |
214 | ${ip} -4 addr flush dev ${interface} label ${interface}:0 | |
215 | ${ip} -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \ | |
216 | dev ${interface} label ${interface}:0 | |
217 | ${ip} -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1 | |
218 | fi | |
219 | ||
220 | # update /etc/resolv.conf | |
221 | make_resolv_conf | |
222 | ||
223 | ;; | |
224 | ||
225 | EXPIRE|FAIL|RELEASE|STOP) | |
226 | if [ -n "$alias_ip_address" ]; then | |
227 | # flush alias IP | |
228 | ${ip} -4 addr flush dev ${interface} label ${interface}:0 | |
229 | fi | |
230 | ||
231 | if [ -n "$old_ip_address" ]; then | |
232 | # flush leased IP | |
233 | ${ip} -4 addr flush dev ${interface} label ${interface} | |
234 | fi | |
235 | ||
236 | if [ -n "$alias_ip_address" ]; then | |
237 | # alias IP given => set it & add host route to it | |
238 | ${ip} -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \ | |
239 | dev ${interface} label ${interface}:0 | |
240 | ${ip} -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1 | |
241 | fi | |
242 | ||
243 | ;; | |
244 | ||
245 | TIMEOUT) | |
246 | if [ -n "$alias_ip_address" ]; then | |
247 | # flush alias IP | |
248 | ${ip} -4 addr flush dev ${interface} label ${interface}:0 | |
249 | fi | |
250 | ||
251 | # set IP from recorded lease | |
252 | ${ip} -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \ | |
253 | ${new_broadcast_address:+broadcast $new_broadcast_address} \ | |
254 | dev ${interface} label ${interface} | |
255 | ||
256 | if [ -n "$new_interface_mtu" ]; then | |
257 | # set MTU | |
258 | ${ip} link set dev ${interface} mtu ${new_interface_mtu} | |
259 | fi | |
260 | ||
261 | # if there is no router recorded in the lease or the 1st router answers pings | |
262 | if [ -z "$new_routers" ] || ping -q -c 1 "${new_routers%% *}"; then | |
263 | # if we have $new_rfc3442_classless_static_routes then we have to | |
264 | # ignore $new_routers entirely | |
265 | if [ ! "$new_rfc3442_classless_static_routes" ]; then | |
266 | if [ -n "$alias_ip_address" ] && | |
267 | [ "$new_ip_address" != "$alias_ip_address" ]; then | |
268 | # separate alias IP given => set up the alias IP & add host route to it | |
269 | ${ip} -4 addr add \ | |
270 | ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \ | |
271 | dev ${interface} label ${interface}:0 | |
272 | ${ip} -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1 | |
273 | fi | |
274 | ||
275 | # set if_metric if IF_METRIC is set or there's more than one router | |
276 | if_metric="$IF_METRIC" | |
277 | if [ "${new_routers%% *}" != "${new_routers}" ]; then | |
278 | if_metric=${if_metric:-1} | |
279 | fi | |
280 | ||
281 | # set default route | |
282 | for router in $new_routers; do | |
283 | ${ip} -4 route add default via ${router} dev ${interface} \ | |
284 | ${if_metric:+metric $if_metric} >/dev/null 2>&1 | |
285 | ||
286 | if [ -n "$if_metric" ]; then | |
287 | if_metric=$((if_metric+1)) | |
288 | fi | |
289 | done | |
290 | fi | |
291 | ||
292 | # update /etc/resolv.conf | |
293 | make_resolv_conf | |
294 | else | |
295 | # flush all IPs from interface | |
296 | ${ip} -4 addr flush dev ${interface} | |
297 | exit 2 | |
298 | fi | |
299 | ||
300 | ;; | |
301 | ||
302 | ### DHCPv6 Handlers | |
303 | # TODO handle prefix change: ?based on ${old_ip6_prefix} and ${new_ip6_prefix}? | |
304 | ||
305 | PREINIT6) | |
306 | # ensure interface is up | |
307 | ${ip} link set ${interface} up | |
308 | ||
309 | # We need to give the kernel some time to active interface | |
310 | interface_up_wait_time=5 | |
311 | for i in $(seq 0 ${interface_up_wait_time}) | |
312 | do | |
313 | ${ip} addr show ${interface} | grep NO-CARRIER >/dev/null 2>&1 | |
314 | if [ $? -ne 0 ]; then | |
315 | break; | |
316 | fi | |
317 | sleep 1 | |
318 | done | |
319 | ||
320 | # flush any stale global permanent IPs from interface | |
321 | ${ip} -6 addr flush dev ${interface} scope global permanent | |
322 | ||
323 | # Wait for duplicate address detection for this interface if the | |
324 | # --dad-wait-time parameter has been specified and is greater than | |
325 | # zero. | |
326 | if [ ${dad_wait_time} -gt 0 ]; then | |
327 | # Check if any IPv6 address on this interface is marked as | |
328 | # tentative. | |
329 | ${ip} addr show ${interface} | grep inet6 | grep tentative \ | |
330 | &> /dev/null | |
331 | if [ $? -eq 0 ]; then | |
332 | # Wait for duplicate address detection to complete or for | |
333 | # the timeout specified as --dad-wait-time. | |
334 | for i in $(seq 0 $dad_wait_time) | |
335 | do | |
336 | # We're going to poll for the tentative flag every second. | |
337 | sleep 1 | |
338 | ${ip} addr show ${interface} | grep inet6 | grep tentative \ | |
339 | &> /dev/null | |
340 | if [ $? -ne 0 ]; then | |
341 | break; | |
342 | fi | |
343 | done | |
344 | fi | |
345 | fi | |
346 | ||
347 | ;; | |
348 | ||
349 | BOUND6|RENEW6|REBIND6) | |
350 | if [ "${new_ip6_address}" ] && [ "${new_ip6_prefixlen}" ]; then | |
351 | # set leased IP | |
352 | ${ip} -6 addr add ${new_ip6_address}/${new_ip6_prefixlen} \ | |
353 | dev ${interface} scope global | |
354 | fi | |
355 | ||
356 | # update /etc/resolv.conf | |
357 | if [ "${reason}" = BOUND6 ] || | |
358 | [ "${new_dhcp6_name_servers}" != "${old_dhcp6_name_servers}" ] || | |
359 | [ "${new_dhcp6_domain_search}" != "${old_dhcp6_domain_search}" ]; then | |
360 | make_resolv_conf | |
361 | fi | |
362 | ||
363 | ;; | |
364 | ||
365 | DEPREF6) | |
366 | if [ -z "${cur_ip6_prefixlen}" ]; then | |
367 | exit 2 | |
368 | fi | |
369 | ||
370 | # set preferred lifetime of leased IP to 0 | |
371 | ${ip} -6 addr change ${cur_ip6_address}/${cur_ip6_prefixlen} \ | |
372 | dev ${interface} scope global preferred_lft 0 | |
373 | ||
374 | ;; | |
375 | ||
376 | EXPIRE6|RELEASE6|STOP6) | |
377 | if [ -z "${old_ip6_address}" ] || [ -z "${old_ip6_prefixlen}" ]; then | |
378 | exit 2 | |
379 | fi | |
380 | ||
381 | # delete leased IP | |
382 | ${ip} -6 addr del ${old_ip6_address}/${old_ip6_prefixlen} \ | |
383 | dev ${interface} | |
384 | ||
385 | ;; | |
386 | esac | |
387 | ||
388 | exit 0 |