1 /*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2010 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/param.h>
29 #include <sys/time.h>
30
31 #include <fcntl.h>
32 #ifdef BSD
33 # include <paths.h>
34 #endif
35 #include <signal.h>
36 #include <stdlib.h>
37 #include <syslog.h>
38 #include <unistd.h>
39
40 #include "arp.h"
41 #include "bind.h"
42 #include "common.h"
43 #include "configure.h"
44 #include "dhcpcd.h"
45 #include "eloop.h"
46 #include "if-options.h"
47 #include "net.h"
48 #include "signals.h"
49
50 #ifndef _PATH_DEVNULL
51 # define _PATH_DEVNULL "/dev/null"
52 #endif
53
54 /* We do things after aquiring the lease, so ensure we have enough time for them */
55 #define DHCP_MIN_LEASE 20
56
57 #ifndef THERE_IS_NO_FORK
58 pid_t
daemonise(void)59 daemonise(void)
60 {
61 pid_t pid;
62 sigset_t full;
63 sigset_t old;
64 char buf = '\0';
65 int sidpipe[2], fd;
66
67 if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
68 return 0;
69 sigfillset(&full);
70 sigprocmask(SIG_SETMASK, &full, &old);
71 /* Setup a signal pipe so parent knows when to exit. */
72 if (pipe(sidpipe) == -1) {
73 syslog(LOG_ERR, "pipe: %m");
74 return -1;
75 }
76 syslog(LOG_DEBUG, "forking to background");
77 switch (pid = fork()) {
78 case -1:
79 syslog(LOG_ERR, "fork: %m");
80 exit(EXIT_FAILURE);
81 /* NOTREACHED */
82 case 0:
83 setsid();
84 /* Notify parent it's safe to exit as we've detached. */
85 close(sidpipe[0]);
86 if (write(sidpipe[1], &buf, 1) == -1)
87 syslog(LOG_ERR, "failed to notify parent: %m");
88 close(sidpipe[1]);
89 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
90 dup2(fd, STDIN_FILENO);
91 dup2(fd, STDOUT_FILENO);
92 dup2(fd, STDERR_FILENO);
93 if (fd > STDERR_FILENO)
94 close(fd);
95 }
96 break;
97 default:
98 signal_reset();
99 /* Wait for child to detach */
100 close(sidpipe[1]);
101 if (read(sidpipe[0], &buf, 1) == -1)
102 syslog(LOG_ERR, "failed to read child: %m");
103 close(sidpipe[0]);
104 break;
105 }
106 /* Done with the fd now */
107 if (pid != 0) {
108 syslog(LOG_INFO, "forked to background, child pid %d",pid);
109 writepid(pidfd, pid);
110 close(pidfd);
111 pidfd = -1;
112 exit(EXIT_SUCCESS);
113 }
114 options |= DHCPCD_DAEMONISED;
115 sigprocmask(SIG_SETMASK, &old, NULL);
116 return pid;
117 }
118 #endif
119
120 void
bind_interface(void * arg)121 bind_interface(void *arg)
122 {
123 struct interface *iface = arg;
124 struct if_state *state = iface->state;
125 struct if_options *ifo = state->options;
126 struct dhcp_lease *lease = &state->lease;
127 struct timeval tv;
128
129 /* We're binding an address now - ensure that sockets are closed */
130 close_sockets(iface);
131 state->reason = NULL;
132 delete_timeout(handle_exit_timeout, NULL);
133 if (clock_monotonic)
134 get_monotonic(&lease->boundtime);
135 state->xid = 0;
136 free(state->old);
137 state->old = state->new;
138 state->new = state->offer;
139 state->offer = NULL;
140 get_lease(lease, state->new);
141 if (ifo->options & DHCPCD_STATIC) {
142 syslog(LOG_INFO, "%s: using static address %s",
143 iface->name, inet_ntoa(lease->addr));
144 lease->leasetime = ~0U;
145 lease->net.s_addr = ifo->req_mask.s_addr;
146 state->reason = "STATIC";
147 } else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
148 syslog(LOG_INFO, "%s: using IPv4LL address %s",
149 iface->name, inet_ntoa(lease->addr));
150 lease->leasetime = ~0U;
151 state->reason = "IPV4LL";
152 } else if (ifo->options & DHCPCD_INFORM) {
153 if (ifo->req_addr.s_addr != 0)
154 lease->addr.s_addr = ifo->req_addr.s_addr;
155 else
156 lease->addr.s_addr = iface->addr.s_addr;
157 syslog(LOG_INFO, "%s: received approval for %s", iface->name,
158 inet_ntoa(lease->addr));
159 lease->leasetime = ~0U;
160 state->reason = "INFORM";
161 } else {
162 if (gettimeofday(&tv, NULL) == 0)
163 lease->leasedfrom = tv.tv_sec;
164 else if (lease->frominfo)
165 state->reason = "TIMEOUT";
166 if (lease->leasetime == ~0U) {
167 lease->renewaltime =
168 lease->rebindtime =
169 lease->leasetime;
170 syslog(LOG_INFO, "%s: leased %s for infinity",
171 iface->name, inet_ntoa(lease->addr));
172 } else {
173 if (lease->leasetime < DHCP_MIN_LEASE) {
174 syslog(LOG_WARNING,
175 "%s: minimum lease is %d seconds",
176 iface->name, DHCP_MIN_LEASE);
177 lease->leasetime = DHCP_MIN_LEASE;
178 }
179 if (lease->rebindtime == 0)
180 lease->rebindtime = lease->leasetime * T2;
181 else if (lease->rebindtime >= lease->leasetime) {
182 lease->rebindtime = lease->leasetime * T2;
183 syslog(LOG_ERR,
184 "%s: rebind time greater than lease "
185 "time, forcing to %u seconds",
186 iface->name, lease->rebindtime);
187 }
188 if (lease->renewaltime == 0)
189 lease->renewaltime = lease->leasetime * T1;
190 else if (lease->renewaltime > lease->rebindtime) {
191 lease->renewaltime = lease->leasetime * T1;
192 syslog(LOG_ERR,
193 "%s: renewal time greater than rebind "
194 "time, forcing to %u seconds",
195 iface->name, lease->renewaltime);
196 }
197 syslog(LOG_INFO,
198 "%s: leased %s for %u seconds", iface->name,
199 inet_ntoa(lease->addr), lease->leasetime);
200 }
201 }
202 if (options & DHCPCD_TEST) {
203 state->reason = "TEST";
204 run_script(iface);
205 exit(EXIT_SUCCESS);
206 }
207 if (state->reason == NULL) {
208 if (state->old) {
209 if (state->old->yiaddr == state->new->yiaddr &&
210 lease->server.s_addr)
211 state->reason = "RENEW";
212 else
213 state->reason = "REBIND";
214 } else if (state->state == DHS_REBOOT)
215 state->reason = "REBOOT";
216 else
217 state->reason = "BOUND";
218 }
219 if (lease->leasetime == ~0U)
220 lease->renewaltime = lease->rebindtime = lease->leasetime;
221 else {
222 add_timeout_sec(lease->renewaltime, start_renew, iface);
223 add_timeout_sec(lease->rebindtime, start_rebind, iface);
224 add_timeout_sec(lease->leasetime, start_expire, iface);
225 }
226 ifo->options &= ~ DHCPCD_CSR_WARNED;
227 configure(iface);
228 daemonise();
229 state->state = DHS_BOUND;
230 if (ifo->options & DHCPCD_ARP) {
231 state->claims = 0;
232 send_arp_announce(iface);
233 }
234 }
235