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