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