1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2010 Roy Marples <roy (at) 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 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 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