2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
45 #include "configure.h"
47 #include "if-options.h"
52 #define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
54 /* Some systems have route metrics */
55 #ifndef HAVE_ROUTE_METRIC
57 # define HAVE_ROUTE_METRIC 1
59 # ifndef HAVE_ROUTE_METRIC
60 # define HAVE_ROUTE_METRIC 0
64 static struct rt
*routes
;
68 exec_script(char *const *argv
, char *const *env
)
74 /* OK, we need to block signals */
76 sigprocmask(SIG_SETMASK
, &full
, &old
);
79 switch (pid
= vfork()) {
81 syslog(LOG_ERR
, "vfork: %m");
84 sigprocmask(SIG_SETMASK
, &old
, NULL
);
85 execve(argv
[0], argv
, env
);
86 syslog(LOG_ERR
, "%s: %m", argv
[0]);
91 /* Restore our signals */
93 sigprocmask(SIG_SETMASK
, &old
, NULL
);
98 make_var(const char *prefix
, const char *var
)
103 len
= strlen(prefix
) + strlen(var
) + 2;
105 snprintf(v
, len
, "%s_%s", prefix
, var
);
111 append_config(char ***env
, ssize_t
*len
,
112 const char *prefix
, const char *const *config
)
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,
129 ne
[j
] = make_var(prefix
, config
[i
]);
135 ne
= xrealloc(ne
, sizeof(char *) * (j
+ 1));
136 ne
[j
- 1] = make_var(prefix
, config
[i
]);
144 arraytostr(const char *const *argv
, char **s
)
146 const char *const *ap
;
153 len
+= strlen(*ap
++) + 1;
154 *s
= p
= xmalloc(len
);
166 make_env(const struct interface
*iface
, char ***argv
)
170 const struct if_options
*ifo
= iface
->state
->options
;
171 const struct interface
*ifp
;
175 env
= xmalloc(sizeof(char *) * (elen
+ 1));
176 e
= strlen("interface") + strlen(iface
->name
) + 2;
178 snprintf(env
[0], e
, "interface=%s", iface
->name
);
179 e
= strlen("reason") + strlen(iface
->state
->reason
) + 2;
181 snprintf(env
[1], e
, "reason=%s", iface
->state
->reason
);
184 snprintf(env
[2], e
, "pid=%d", getpid());
186 snprintf(env
[3], e
, "ifmetric=%d", iface
->metric
);
188 snprintf(env
[4], e
, "ifwireless=%d", iface
->wireless
);
190 snprintf(env
[5], e
, "ifflags=%u", iface
->flags
);
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
);
200 for (ifp
= ifaces
; ifp
; ifp
= ifp
->next
) {
201 l
= strlcpy(p
, ifp
->name
, e
);
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
);
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)
218 env
= xrealloc(env
, sizeof(char *) * (elen
+ 2));
219 env
[elen
] = xmalloc(e
);
220 snprintf(env
[elen
++], e
, "new_ssid=%s", iface
->ssid
);
222 if (iface
->state
->old
!= NULL
||
223 strcmp(iface
->state
->reason
, "NOCARRIER") == 0)
225 env
= xrealloc(env
, sizeof(char *) * (elen
+ 2));
226 env
[elen
] = xmalloc(e
);
227 snprintf(env
[elen
++], e
, "old_ssid=%s", iface
->ssid
);
230 if (iface
->state
->old
) {
231 e
= configure_env(NULL
, NULL
, iface
->state
->old
, ifo
);
233 env
= xrealloc(env
, sizeof(char *) * (elen
+ e
+ 1));
234 elen
+= configure_env(env
+ elen
, "old",
235 iface
->state
->old
, ifo
);
237 append_config(&env
, &elen
, "old",
238 (const char *const *)ifo
->config
);
240 if (iface
->state
->new) {
241 e
= configure_env(NULL
, NULL
, iface
->state
->new, ifo
);
243 env
= xrealloc(env
, sizeof(char *) * (elen
+ e
+ 1));
244 elen
+= configure_env(env
+ elen
, "new",
245 iface
->state
->new, ifo
);
247 append_config(&env
, &elen
, "new",
248 (const char *const *)ifo
->config
);
251 /* Add our base environment */
254 while (ifo
->environ
[e
++])
256 env
= xrealloc(env
, sizeof(char *) * (elen
+ e
+ 1));
258 while (ifo
->environ
[e
]) {
259 env
[elen
+ e
] = xstrdup(ifo
->environ
[e
]);
271 send_interface(int fd
, const struct interface
*iface
)
273 char **env
, **ep
, *s
;
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
);
284 iov
[1].iov_len
= elen
;
285 retval
= writev(fd
, iov
, 2);
295 run_script(const struct interface
*iface
)
297 char *const argv
[2] = { UNCONST(iface
->state
->options
->script
), NULL
};
298 char **env
= NULL
, **ep
;
303 const struct fd_list
*fd
;
306 syslog(LOG_DEBUG
, "%s: executing `%s', reason %s",
307 iface
->name
, argv
[0], iface
->state
->reason
);
310 elen
= make_env(iface
, &env
);
311 env
= xrealloc(env
, sizeof(char *) * (elen
+ 2));
313 path
= getenv("PATH");
315 e
= strlen("PATH") + strlen(path
) + 2;
316 env
[elen
] = xmalloc(e
);
317 snprintf(env
[elen
], e
, "PATH=%s", path
);
319 env
[elen
] = xstrdup(DEFAULT_PATH
);
322 pid
= exec_script(argv
, env
);
326 /* Wait for the script to finish */
327 while (waitpid(pid
, &status
, 0) == -1) {
328 if (errno
!= EINTR
) {
329 syslog(LOG_ERR
, "waitpid: %m");
336 /* Send to our listeners */
338 for (fd
= fds
; fd
!= NULL
; fd
= fd
->next
) {
340 if (bigenv
== NULL
) {
341 elen
= arraytostr((const char *const *)env
,
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
;
348 if (writev(fd
->fd
, iov
, 2) == -1)
349 syslog(LOG_ERR
, "writev: %m");
363 find_route(struct rt
*rts
, const struct rt
*r
, struct rt
**lrt
,
364 const struct rt
*srt
)
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
)) &&
376 (!srt
|| srt
!= rt
) &&
377 rt
->net
.s_addr
== r
->net
.s_addr
)
386 desc_route(const char *cmd
, const struct rt
*rt
, const char *ifname
)
388 char addr
[sizeof("000.000.000.000") + 1];
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
,
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
));
402 syslog(LOG_DEBUG
, "%s: %s route to %s/%d via %s", ifname
, cmd
,
403 addr
, inet_ntocidr(rt
->net
), inet_ntoa(rt
->gate
));
406 /* If something other than dhcpcd removes a route,
407 * we need to remove it from our internal table. */
409 route_deleted(const struct rt
*rt
)
413 f
= find_route(routes
, rt
, &l
, NULL
);
416 desc_route("removing", f
, f
->iface
->name
);
426 n_route(struct rt
*rt
, const struct interface
*iface
)
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
))
434 desc_route("adding", rt
, iface
->name
);
435 if (!add_route(iface
, &rt
->dest
, &rt
->net
, &rt
->gate
, iface
->metric
))
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)
446 syslog(LOG_ERR
, "%s: add_route: %m", iface
->name
);
451 c_route(struct rt
*ort
, struct rt
*nrt
, const struct interface
*iface
)
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
))
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
,
465 if (!add_route(iface
, &nrt
->dest
, &nrt
->net
, &nrt
->gate
,
468 syslog(LOG_ERR
, "%s: add_route: %m", iface
->name
);
473 d_route(struct rt
*rt
, const struct interface
*iface
, int metric
)
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
);
485 get_subnet_route(struct dhcp_message
*dhcp
)
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
)
499 rt
= malloc(sizeof(*rt
));
500 rt
->dest
.s_addr
= addr
& net
.s_addr
;
501 rt
->net
.s_addr
= net
.s_addr
;
507 add_subnet_route(struct rt
*rt
, const struct interface
*iface
)
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
))
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
;
527 get_routes(const struct interface
*iface
)
529 struct rt
*rt
, *nrt
= NULL
, *r
= NULL
;
531 if (iface
->state
->options
->routes
!= NULL
) {
532 for (rt
= iface
->state
->options
->routes
;
536 if (rt
->gate
.s_addr
== 0)
539 r
= nrt
= xmalloc(sizeof(*r
));
541 r
->next
= xmalloc(sizeof(*r
));
544 memcpy(r
, rt
, sizeof(*r
));
550 return get_option_routes(iface
->state
->new,
551 iface
->name
, &iface
->state
->options
->options
);
555 add_destination_route(struct rt
*rt
, const struct interface
*iface
)
559 if (!(iface
->flags
& IFF_POINTOPOINT
) ||
560 !has_option_mask(iface
->state
->options
->dstmask
, DHO_ROUTER
))
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
;
573 struct rt
*nrs
= NULL
, *dnr
, *or, *rt
, *rtn
, *rtl
, *lrt
= NULL
;
574 const struct interface
*ifp
;
576 for (ifp
= ifaces
; ifp
; ifp
= ifp
->next
) {
577 if (ifp
->state
->new == NULL
)
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
) {
584 /* Is this route already in our table? */
585 if ((find_route(nrs
, rt
, NULL
, NULL
)) != NULL
)
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
)
592 if (c_route(or, rt
, ifp
) != 0)
596 rtl
->next
= or->next
;
601 if (n_route(rt
, ifp
) != 0)
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
);
625 delete_address(struct interface
*iface
)
628 struct if_options
*ifo
;
630 ifo
= iface
->state
->options
;
631 if (ifo
->options
& DHCPCD_INFORM
||
632 (ifo
->options
& DHCPCD_STATIC
&& ifo
->req_addr
.s_addr
== 0))
634 syslog(LOG_DEBUG
, "%s: deleting IP address %s/%d",
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;
647 configure(struct interface
*iface
)
649 struct dhcp_message
*dhcp
= iface
->state
->new;
650 struct dhcp_lease
*lease
= &iface
->state
->lease
;
651 struct if_options
*ifo
= iface
->state
->options
;
654 /* As we are now adjusting an interface, we need to ensure
655 * we have them in the right order for routing and configuration. */
659 if (!(ifo
->options
& DHCPCD_PERSISTENT
)) {
661 if (iface
->addr
.s_addr
!= 0)
662 delete_address(iface
);
668 /* This also changes netmask */
669 if (!(ifo
->options
& DHCPCD_INFORM
) ||
670 !has_address(iface
->name
, &lease
->addr
, &lease
->net
))
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 &&
679 syslog(LOG_ERR
, "add_address: %m");
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
);
689 iface
->addr
.s_addr
= lease
->addr
.s_addr
;
690 iface
->net
.s_addr
= lease
->net
.s_addr
;
692 /* We need to delete the subnet route to have our metric or
693 * prefer the interface. */
694 rt
= get_subnet_route(dhcp
);
697 if (!find_route(routes
, rt
, NULL
, NULL
))
698 del_route(iface
, &rt
->dest
, &rt
->net
, &rt
->gate
, 0);
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");