OLD | NEW |
| (Empty) |
1 /* | |
2 * dhcpcd - DHCP client daemon | |
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name> | |
4 * All rights reserved | |
5 | |
6 * Redistribution and use in source and binary forms, with or without | |
7 * modification, are permitted provided that the following conditions | |
8 * are met: | |
9 * 1. Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * | |
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
25 * SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include <sys/stat.h> | |
29 #include <sys/uio.h> | |
30 #include <sys/wait.h> | |
31 | |
32 #include <netinet/in.h> | |
33 #include <arpa/inet.h> | |
34 | |
35 #include <ctype.h> | |
36 #include <errno.h> | |
37 #include <signal.h> | |
38 #include <stdlib.h> | |
39 #include <string.h> | |
40 #include <syslog.h> | |
41 #include <unistd.h> | |
42 | |
43 #include "config.h" | |
44 #include "common.h" | |
45 #include "configure.h" | |
46 #include "dhcp.h" | |
47 #include "if-options.h" | |
48 #include "if-pref.h" | |
49 #include "net.h" | |
50 #include "signals.h" | |
51 | |
52 #define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" | |
53 | |
54 /* Some systems have route metrics */ | |
55 #ifndef HAVE_ROUTE_METRIC | |
56 # ifdef __linux__ | |
57 # define HAVE_ROUTE_METRIC 1 | |
58 # endif | |
59 # ifndef HAVE_ROUTE_METRIC | |
60 # define HAVE_ROUTE_METRIC 0 | |
61 # endif | |
62 #endif | |
63 | |
64 static struct rt *routes; | |
65 | |
66 | |
67 static int | |
68 exec_script(char *const *argv, char *const *env) | |
69 { | |
70 pid_t pid; | |
71 sigset_t full; | |
72 sigset_t old; | |
73 | |
74 /* OK, we need to block signals */ | |
75 sigfillset(&full); | |
76 sigprocmask(SIG_SETMASK, &full, &old); | |
77 signal_reset(); | |
78 | |
79 switch (pid = vfork()) { | |
80 case -1: | |
81 syslog(LOG_ERR, "vfork: %m"); | |
82 break; | |
83 case 0: | |
84 sigprocmask(SIG_SETMASK, &old, NULL); | |
85 execve(argv[0], argv, env); | |
86 syslog(LOG_ERR, "%s: %m", argv[0]); | |
87 _exit(127); | |
88 /* NOTREACHED */ | |
89 } | |
90 | |
91 /* Restore our signals */ | |
92 signal_setup(); | |
93 sigprocmask(SIG_SETMASK, &old, NULL); | |
94 return pid; | |
95 } | |
96 | |
97 static char * | |
98 make_var(const char *prefix, const char *var) | |
99 { | |
100 size_t len; | |
101 char *v; | |
102 | |
103 len = strlen(prefix) + strlen(var) + 2; | |
104 v = xmalloc(len); | |
105 snprintf(v, len, "%s_%s", prefix, var); | |
106 return v; | |
107 } | |
108 | |
109 | |
110 static void | |
111 append_config(char ***env, ssize_t *len, | |
112 const char *prefix, const char *const *config) | |
113 { | |
114 ssize_t i, j, e1; | |
115 char **ne, *eq; | |
116 | |
117 if (config == NULL) | |
118 return; | |
119 | |
120 ne = *env; | |
121 for (i = 0; config[i] != NULL; i++) { | |
122 eq = strchr(config[i], '='); | |
123 e1 = eq - config[i] + 1; | |
124 for (j = 0; j < *len; j++) { | |
125 if (strncmp(ne[j] + strlen(prefix) + 1, | |
126 config[i], e1) == 0) | |
127 { | |
128 free(ne[j]); | |
129 ne[j] = make_var(prefix, config[i]); | |
130 break; | |
131 } | |
132 } | |
133 if (j == *len) { | |
134 j++; | |
135 ne = xrealloc(ne, sizeof(char *) * (j + 1)); | |
136 ne[j - 1] = make_var(prefix, config[i]); | |
137 *len = j; | |
138 } | |
139 } | |
140 *env = ne; | |
141 } | |
142 | |
143 static size_t | |
144 arraytostr(const char *const *argv, char **s) | |
145 { | |
146 const char *const *ap; | |
147 char *p; | |
148 size_t len, l; | |
149 | |
150 len = 0; | |
151 ap = argv; | |
152 while (*ap) | |
153 len += strlen(*ap++) + 1; | |
154 *s = p = xmalloc(len); | |
155 ap = argv; | |
156 while (*ap) { | |
157 l = strlen(*ap) + 1; | |
158 memcpy(p, *ap, l); | |
159 p += l; | |
160 ap++; | |
161 } | |
162 return len; | |
163 } | |
164 | |
165 static ssize_t | |
166 make_env(const struct interface *iface, char ***argv) | |
167 { | |
168 char **env, *p; | |
169 ssize_t e, elen, l; | |
170 const struct if_options *ifo = iface->state->options; | |
171 const struct interface *ifp; | |
172 | |
173 /* Make our env */ | |
174 elen = 8; | |
175 env = xmalloc(sizeof(char *) * (elen + 1)); | |
176 e = strlen("interface") + strlen(iface->name) + 2; | |
177 env[0] = xmalloc(e); | |
178 snprintf(env[0], e, "interface=%s", iface->name); | |
179 e = strlen("reason") + strlen(iface->state->reason) + 2; | |
180 env[1] = xmalloc(e); | |
181 snprintf(env[1], e, "reason=%s", iface->state->reason); | |
182 e = 20; | |
183 env[2] = xmalloc(e); | |
184 snprintf(env[2], e, "pid=%d", getpid()); | |
185 env[3] = xmalloc(e); | |
186 snprintf(env[3], e, "ifmetric=%d", iface->metric); | |
187 env[4] = xmalloc(e); | |
188 snprintf(env[4], e, "ifwireless=%d", iface->wireless); | |
189 env[5] = xmalloc(e); | |
190 snprintf(env[5], e, "ifflags=%u", iface->flags); | |
191 env[6] = xmalloc(e); | |
192 snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name)); | |
193 l = e = strlen("interface_order="); | |
194 for (ifp = ifaces; ifp; ifp = ifp->next) | |
195 e += strlen(ifp->name) + 1; | |
196 p = env[7] = xmalloc(e); | |
197 strlcpy(p, "interface_order=", e); | |
198 e -= l; | |
199 p += l; | |
200 for (ifp = ifaces; ifp; ifp = ifp->next) { | |
201 l = strlcpy(p, ifp->name, e); | |
202 p += l; | |
203 e -= l; | |
204 *p++ = ' '; | |
205 e--; | |
206 } | |
207 *--p = '\0'; | |
208 if (*iface->state->profile) { | |
209 e = strlen("profile=") + strlen(iface->state->profile) + 2; | |
210 env[elen] = xmalloc(e); | |
211 snprintf(env[elen++], e, "profile=%s", iface->state->profile); | |
212 } | |
213 if (iface->wireless) { | |
214 e = strlen("new_ssid=") + strlen(iface->ssid) + 2; | |
215 if (iface->state->new != NULL || | |
216 strcmp(iface->state->reason, "CARRIER") == 0) | |
217 { | |
218 env = xrealloc(env, sizeof(char *) * (elen + 2)); | |
219 env[elen] = xmalloc(e); | |
220 snprintf(env[elen++], e, "new_ssid=%s", iface->ssid); | |
221 } | |
222 if (iface->state->old != NULL || | |
223 strcmp(iface->state->reason, "NOCARRIER") == 0) | |
224 { | |
225 env = xrealloc(env, sizeof(char *) * (elen + 2)); | |
226 env[elen] = xmalloc(e); | |
227 snprintf(env[elen++], e, "old_ssid=%s", iface->ssid); | |
228 } | |
229 } | |
230 if (iface->state->old) { | |
231 e = configure_env(NULL, NULL, iface->state->old, ifo); | |
232 if (e > 0) { | |
233 env = xrealloc(env, sizeof(char *) * (elen + e + 1)); | |
234 elen += configure_env(env + elen, "old", | |
235 iface->state->old, ifo); | |
236 } | |
237 append_config(&env, &elen, "old", | |
238 (const char *const *)ifo->config); | |
239 } | |
240 if (iface->state->new) { | |
241 e = configure_env(NULL, NULL, iface->state->new, ifo); | |
242 if (e > 0) { | |
243 env = xrealloc(env, sizeof(char *) * (elen + e + 1)); | |
244 elen += configure_env(env + elen, "new", | |
245 iface->state->new, ifo); | |
246 } | |
247 append_config(&env, &elen, "new", | |
248 (const char *const *)ifo->config); | |
249 } | |
250 | |
251 /* Add our base environment */ | |
252 if (ifo->environ) { | |
253 e = 0; | |
254 while (ifo->environ[e++]) | |
255 ; | |
256 env = xrealloc(env, sizeof(char *) * (elen + e + 1)); | |
257 e = 0; | |
258 while (ifo->environ[e]) { | |
259 env[elen + e] = xstrdup(ifo->environ[e]); | |
260 e++; | |
261 } | |
262 elen += e; | |
263 } | |
264 env[elen] = '\0'; | |
265 | |
266 *argv = env; | |
267 return elen; | |
268 } | |
269 | |
270 int | |
271 send_interface(int fd, const struct interface *iface) | |
272 { | |
273 char **env, **ep, *s; | |
274 ssize_t elen; | |
275 struct iovec iov[2]; | |
276 int retval; | |
277 | |
278 retval = 0; | |
279 make_env(iface, &env); | |
280 elen = arraytostr((const char *const *)env, &s); | |
281 iov[0].iov_base = &elen; | |
282 iov[0].iov_len = sizeof(ssize_t); | |
283 iov[1].iov_base = s; | |
284 iov[1].iov_len = elen; | |
285 retval = writev(fd, iov, 2); | |
286 ep = env; | |
287 while (*ep) | |
288 free(*ep++); | |
289 free(env); | |
290 free(s); | |
291 return retval; | |
292 } | |
293 | |
294 int | |
295 run_script(const struct interface *iface) | |
296 { | |
297 char *const argv[2] = { UNCONST(iface->state->options->script), NULL }; | |
298 char **env = NULL, **ep; | |
299 char *path, *bigenv; | |
300 ssize_t e, elen = 0; | |
301 pid_t pid; | |
302 int status = 0; | |
303 const struct fd_list *fd; | |
304 struct iovec iov[2]; | |
305 | |
306 syslog(LOG_DEBUG, "%s: executing `%s', reason %s", | |
307 iface->name, argv[0], iface->state->reason); | |
308 | |
309 /* Make our env */ | |
310 elen = make_env(iface, &env); | |
311 env = xrealloc(env, sizeof(char *) * (elen + 2)); | |
312 /* Add path to it */ | |
313 path = getenv("PATH"); | |
314 if (path) { | |
315 e = strlen("PATH") + strlen(path) + 2; | |
316 env[elen] = xmalloc(e); | |
317 snprintf(env[elen], e, "PATH=%s", path); | |
318 } else | |
319 env[elen] = xstrdup(DEFAULT_PATH); | |
320 env[++elen] = '\0'; | |
321 | |
322 pid = exec_script(argv, env); | |
323 if (pid == -1) | |
324 status = -1; | |
325 else if (pid != 0) { | |
326 /* Wait for the script to finish */ | |
327 while (waitpid(pid, &status, 0) == -1) { | |
328 if (errno != EINTR) { | |
329 syslog(LOG_ERR, "waitpid: %m"); | |
330 status = -1; | |
331 break; | |
332 } | |
333 } | |
334 } | |
335 | |
336 /* Send to our listeners */ | |
337 bigenv = NULL; | |
338 for (fd = fds; fd != NULL; fd = fd->next) { | |
339 if (fd->listener) { | |
340 if (bigenv == NULL) { | |
341 elen = arraytostr((const char *const *)env, | |
342 &bigenv); | |
343 iov[0].iov_base = &elen; | |
344 iov[0].iov_len = sizeof(ssize_t); | |
345 iov[1].iov_base = bigenv; | |
346 iov[1].iov_len = elen; | |
347 } | |
348 if (writev(fd->fd, iov, 2) == -1) | |
349 syslog(LOG_ERR, "writev: %m"); | |
350 } | |
351 } | |
352 free(bigenv); | |
353 | |
354 /* Cleanup */ | |
355 ep = env; | |
356 while (*ep) | |
357 free(*ep++); | |
358 free(env); | |
359 return status; | |
360 } | |
361 | |
362 static struct rt * | |
363 find_route(struct rt *rts, const struct rt *r, struct rt **lrt, | |
364 const struct rt *srt) | |
365 { | |
366 struct rt *rt; | |
367 | |
368 if (lrt) | |
369 *lrt = NULL; | |
370 for (rt = rts; rt; rt = rt->next) { | |
371 if (rt->dest.s_addr == r->dest.s_addr && | |
372 #if HAVE_ROUTE_METRIC | |
373 (srt || (!rt->iface || | |
374 rt->iface->metric == r->iface->metric)) && | |
375 #endif | |
376 (!srt || srt != rt) && | |
377 rt->net.s_addr == r->net.s_addr) | |
378 return rt; | |
379 if (lrt) | |
380 *lrt = rt; | |
381 } | |
382 return NULL; | |
383 } | |
384 | |
385 static void | |
386 desc_route(const char *cmd, const struct rt *rt, const char *ifname) | |
387 { | |
388 char addr[sizeof("000.000.000.000") + 1]; | |
389 | |
390 strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr)); | |
391 if (rt->gate.s_addr == INADDR_ANY) | |
392 syslog(LOG_DEBUG, "%s: %s route to %s/%d", ifname, cmd, | |
393 addr, inet_ntocidr(rt->net)); | |
394 else if (rt->gate.s_addr == rt->dest.s_addr && | |
395 rt->net.s_addr == INADDR_BROADCAST) | |
396 syslog(LOG_DEBUG, "%s: %s host route to %s", ifname, cmd, | |
397 addr); | |
398 else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY) | |
399 syslog(LOG_DEBUG, "%s: %s default route via %s", ifname, cmd, | |
400 inet_ntoa(rt->gate)); | |
401 else | |
402 syslog(LOG_DEBUG, "%s: %s route to %s/%d via %s", ifname, cmd, | |
403 addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate)); | |
404 } | |
405 | |
406 /* If something other than dhcpcd removes a route, | |
407 * we need to remove it from our internal table. */ | |
408 int | |
409 route_deleted(const struct rt *rt) | |
410 { | |
411 struct rt *f, *l; | |
412 | |
413 f = find_route(routes, rt, &l, NULL); | |
414 if (f == NULL) | |
415 return 0; | |
416 desc_route("removing", f, f->iface->name); | |
417 if (l) | |
418 l->next = f->next; | |
419 else | |
420 routes = f->next; | |
421 free(f); | |
422 return 1; | |
423 } | |
424 | |
425 static int | |
426 n_route(struct rt *rt, const struct interface *iface) | |
427 { | |
428 /* Don't set default routes if not asked to */ | |
429 if (rt->dest.s_addr == 0 && | |
430 rt->net.s_addr == 0 && | |
431 !(iface->state->options->options & DHCPCD_GATEWAY)) | |
432 return -1; | |
433 | |
434 desc_route("adding", rt, iface->name); | |
435 if (!add_route(iface, &rt->dest, &rt->net, &rt->gate, iface->metric)) | |
436 return 0; | |
437 if (errno == EEXIST) { | |
438 /* Pretend we added the subnet route */ | |
439 if (rt->dest.s_addr == (iface->addr.s_addr & iface->net.s_addr)
&& | |
440 rt->net.s_addr == iface->net.s_addr && | |
441 rt->gate.s_addr == 0) | |
442 return 0; | |
443 else | |
444 return -1; | |
445 } | |
446 syslog(LOG_ERR, "%s: add_route: %m", iface->name); | |
447 return -1; | |
448 } | |
449 | |
450 static int | |
451 c_route(struct rt *ort, struct rt *nrt, const struct interface *iface) | |
452 { | |
453 /* Don't set default routes if not asked to */ | |
454 if (nrt->dest.s_addr == 0 && | |
455 nrt->net.s_addr == 0 && | |
456 !(iface->state->options->options & DHCPCD_GATEWAY)) | |
457 return -1; | |
458 | |
459 desc_route("changing", nrt, iface->name); | |
460 /* We delete and add the route so that we can change metric. | |
461 * This also has the nice side effect of flushing ARP entries so | |
462 * we don't have to do that manually. */ | |
463 del_route(ort->iface, &ort->dest, &ort->net, &ort->gate, | |
464 ort->iface->metric); | |
465 if (!add_route(iface, &nrt->dest, &nrt->net, &nrt->gate, | |
466 iface->metric)) | |
467 return 0; | |
468 syslog(LOG_ERR, "%s: add_route: %m", iface->name); | |
469 return -1; | |
470 } | |
471 | |
472 static int | |
473 d_route(struct rt *rt, const struct interface *iface, int metric) | |
474 { | |
475 int retval; | |
476 | |
477 desc_route("deleting", rt, iface->name); | |
478 retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric); | |
479 if (retval != 0 && errno != ENOENT && errno != ESRCH) | |
480 syslog(LOG_ERR,"%s: del_route: %m", iface->name); | |
481 return retval; | |
482 } | |
483 | |
484 static struct rt * | |
485 get_subnet_route(struct dhcp_message *dhcp) | |
486 { | |
487 in_addr_t addr; | |
488 struct in_addr net; | |
489 struct rt *rt; | |
490 | |
491 addr = dhcp->yiaddr; | |
492 if (addr == 0) | |
493 addr = dhcp->ciaddr; | |
494 /* Ensure we have all the needed values */ | |
495 if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) | |
496 net.s_addr = get_netmask(addr); | |
497 if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY) | |
498 return NULL; | |
499 rt = malloc(sizeof(*rt)); | |
500 rt->dest.s_addr = addr & net.s_addr; | |
501 rt->net.s_addr = net.s_addr; | |
502 rt->gate.s_addr = 0; | |
503 return rt; | |
504 } | |
505 | |
506 static struct rt * | |
507 add_subnet_route(struct rt *rt, const struct interface *iface) | |
508 { | |
509 struct rt *r; | |
510 | |
511 if (iface->net.s_addr == INADDR_BROADCAST || | |
512 iface->net.s_addr == INADDR_ANY || | |
513 (iface->state->options->options & | |
514 (DHCPCD_INFORM | DHCPCD_STATIC) && | |
515 iface->state->options->req_addr.s_addr == INADDR_ANY)) | |
516 return rt; | |
517 | |
518 r = xmalloc(sizeof(*r)); | |
519 r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr; | |
520 r->net.s_addr = iface->net.s_addr; | |
521 r->gate.s_addr = 0; | |
522 r->next = rt; | |
523 return r; | |
524 } | |
525 | |
526 static struct rt * | |
527 get_routes(const struct interface *iface) | |
528 { | |
529 struct rt *rt, *nrt = NULL, *r = NULL; | |
530 | |
531 if (iface->state->options->routes != NULL) { | |
532 for (rt = iface->state->options->routes; | |
533 rt != NULL; | |
534 rt = rt->next) | |
535 { | |
536 if (rt->gate.s_addr == 0) | |
537 break; | |
538 if (r == NULL) | |
539 r = nrt = xmalloc(sizeof(*r)); | |
540 else { | |
541 r->next = xmalloc(sizeof(*r)); | |
542 r = r->next; | |
543 } | |
544 memcpy(r, rt, sizeof(*r)); | |
545 r->next = NULL; | |
546 } | |
547 return nrt; | |
548 } | |
549 | |
550 return get_option_routes(iface->state->new, | |
551 iface->name, &iface->state->options->options); | |
552 } | |
553 | |
554 static struct rt * | |
555 add_destination_route(struct rt *rt, const struct interface *iface) | |
556 { | |
557 struct rt *r; | |
558 | |
559 if (!(iface->flags & IFF_POINTOPOINT) || | |
560 !has_option_mask(iface->state->options->dstmask, DHO_ROUTER)) | |
561 return rt; | |
562 r = xmalloc(sizeof(*r)); | |
563 r->dest.s_addr = INADDR_ANY; | |
564 r->net.s_addr = INADDR_ANY; | |
565 r->gate.s_addr = iface->dst.s_addr; | |
566 r->next = rt; | |
567 return r; | |
568 } | |
569 | |
570 void | |
571 build_routes(void) | |
572 { | |
573 struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL; | |
574 const struct interface *ifp; | |
575 | |
576 for (ifp = ifaces; ifp; ifp = ifp->next) { | |
577 if (ifp->state->new == NULL) | |
578 continue; | |
579 dnr = get_routes(ifp); | |
580 dnr = add_subnet_route(dnr, ifp); | |
581 dnr = add_destination_route(dnr, ifp); | |
582 for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) { | |
583 rt->iface = ifp; | |
584 /* Is this route already in our table? */ | |
585 if ((find_route(nrs, rt, NULL, NULL)) != NULL) | |
586 continue; | |
587 /* Do we already manage it? */ | |
588 if ((or = find_route(routes, rt, &rtl, NULL))) { | |
589 if (or->iface != ifp || | |
590 rt->gate.s_addr != or->gate.s_addr) | |
591 { | |
592 if (c_route(or, rt, ifp) != 0) | |
593 continue; | |
594 } | |
595 if (rtl != NULL) | |
596 rtl->next = or->next; | |
597 else | |
598 routes = or->next; | |
599 free(or); | |
600 } else { | |
601 if (n_route(rt, ifp) != 0) | |
602 continue; | |
603 } | |
604 if (dnr == rt) | |
605 dnr = rtn; | |
606 else if (lrt) | |
607 lrt->next = rtn; | |
608 rt->next = nrs; | |
609 nrs = rt; | |
610 } | |
611 free_routes(dnr); | |
612 } | |
613 | |
614 /* Remove old routes we used to manage */ | |
615 for (rt = routes; rt; rt = rt->next) { | |
616 if (find_route(nrs, rt, NULL, NULL) == NULL) | |
617 d_route(rt, rt->iface, rt->iface->metric); | |
618 } | |
619 | |
620 free_routes(routes); | |
621 routes = nrs; | |
622 } | |
623 | |
624 static int | |
625 delete_address(struct interface *iface) | |
626 { | |
627 int retval; | |
628 struct if_options *ifo; | |
629 | |
630 ifo = iface->state->options; | |
631 if (ifo->options & DHCPCD_INFORM || | |
632 (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0)) | |
633 return 0; | |
634 syslog(LOG_DEBUG, "%s: deleting IP address %s/%d", | |
635 iface->name, | |
636 inet_ntoa(iface->addr), | |
637 inet_ntocidr(iface->net)); | |
638 retval = del_address(iface, &iface->addr, &iface->net); | |
639 if (retval == -1 && errno != EADDRNOTAVAIL) | |
640 syslog(LOG_ERR, "del_address: %m"); | |
641 iface->addr.s_addr = 0; | |
642 iface->net.s_addr = 0; | |
643 return retval; | |
644 } | |
645 | |
646 int | |
647 configure(struct interface *iface) | |
648 { | |
649 struct dhcp_message *dhcp = iface->state->new; | |
650 struct dhcp_lease *lease = &iface->state->lease; | |
651 struct if_options *ifo = iface->state->options; | |
652 struct rt *rt; | |
653 | |
654 /* As we are now adjusting an interface, we need to ensure | |
655 * we have them in the right order for routing and configuration. */ | |
656 sort_interfaces(); | |
657 | |
658 if (dhcp == NULL) { | |
659 if (!(ifo->options & DHCPCD_PERSISTENT)) { | |
660 build_routes(); | |
661 if (iface->addr.s_addr != 0) | |
662 delete_address(iface); | |
663 run_script(iface); | |
664 } | |
665 return 0; | |
666 } | |
667 | |
668 /* This also changes netmask */ | |
669 if (!(ifo->options & DHCPCD_INFORM) || | |
670 !has_address(iface->name, &lease->addr, &lease->net)) | |
671 { | |
672 syslog(LOG_DEBUG, "%s: adding IP address %s/%d", | |
673 iface->name, inet_ntoa(lease->addr), | |
674 inet_ntocidr(lease->net)); | |
675 if (add_address(iface, | |
676 &lease->addr, &lease->net, &lease->brd) == -1 && | |
677 errno != EEXIST) | |
678 { | |
679 syslog(LOG_ERR, "add_address: %m"); | |
680 return -1; | |
681 } | |
682 } | |
683 | |
684 /* Now delete the old address if different */ | |
685 if (iface->addr.s_addr != lease->addr.s_addr && | |
686 iface->addr.s_addr != 0) | |
687 delete_address(iface); | |
688 | |
689 iface->addr.s_addr = lease->addr.s_addr; | |
690 iface->net.s_addr = lease->net.s_addr; | |
691 | |
692 /* We need to delete the subnet route to have our metric or | |
693 * prefer the interface. */ | |
694 rt = get_subnet_route(dhcp); | |
695 if (rt != NULL) { | |
696 rt->iface = iface; | |
697 if (!find_route(routes, rt, NULL, NULL)) | |
698 del_route(iface, &rt->dest, &rt->net, &rt->gate, 0); | |
699 free(rt); | |
700 } | |
701 | |
702 build_routes(); | |
703 if (!iface->state->lease.frominfo && | |
704 !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) | |
705 if (write_lease(iface, dhcp) == -1) | |
706 syslog(LOG_ERR, "write_lease: %m"); | |
707 run_script(iface); | |
708 return 0; | |
709 } | |
OLD | NEW |