From: Roy Marples Date: Thu, 30 Nov 2006 13:04:23 +0000 (+0000) Subject: Quote all vars in the info file. X-Git-Tag: v3.2.3~370 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=479225b66be5928818dd7b61cee4247e39338350;p=thirdparty%2Fdhcpcd.git Quote all vars in the info file. -n and -G options now work as stated in the man page. Handle select loops with large timeouts and infinite lease times. Correctly set the broadcast flag. make_dhcp_packet already has byte ordered addresses, thanks to TGL for the fix. If we get a NAK then always re-enter the INIT state. --- diff --git a/ChangeLog b/ChangeLog index 3acca3d3..514b3f9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +dhcpcd-3.0.1 +Quote all vars in the info file. +-n and -G options now work as stated in the man page. +Handle select loops with large timeouts and infinite lease times. +Correctly set the broadcast flag. +make_dhcp_packet already has byte ordered addresses, thanks to TGL +for the fix. +If we get a NAK then always re-enter the INIT state. + dhcpcd-3.0.0 A complete rewrite by Roy Marples diff --git a/Makefile b/Makefile index c6329728..bf03a21b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Should work for both GNU make and BSD mke -VERSION = 3.0.0 +VERSION = 3.0.1 INSTALL ?= install CFLAGS ?= -Wall -O2 -pedantic -std=gnu99 diff --git a/client.c b/client.c index 0ed7fb5c..46a07ba2 100644 --- a/client.c +++ b/client.c @@ -43,6 +43,10 @@ #include "signals.h" #include "socket.h" +/* We need this for our maximum timeout as FreeBSD's select cannot handle + any higher than this. Is there a better way of working this out? */ +#define SELECT_MAX 100000000 + /* This is out mini timeout. Basically we resend the last request every TIMEOUT_MINI seconds. */ #define TIMEOUT_MINI 3 @@ -73,22 +77,13 @@ send_message (iface, &dhcp, xid, _type, options); static int daemonise (char *pidfile) { - FILE *fp; - if (daemon (0, 0) < 0) { logger (LOG_ERR, "unable to daemonise: %s", strerror (errno)); return -1; } - if ((fp = fopen (pidfile, "w")) == NULL) - { - logger (LOG_ERR, "fopen `%s': %m", pidfile); - return -1; - } - - fprintf (fp, "%u\n", getpid ()); - fclose (fp); + make_pid (pidfile); return 0; } @@ -127,7 +122,7 @@ int dhcp_run (options_t *options) int state = STATE_INIT; struct timeval tv; int xid = 0; - unsigned long timeout = 0; + long timeout = 0; fd_set rset; int maxfd; int retval; @@ -150,14 +145,12 @@ int dhcp_run (options_t *options) /* Remove all existing addresses. After all, we ARE a DHCP client whose job it is to configure the interface. We only do this on start, so persistent addresses can be added - afterwards by the user if needed. - */ + afterwards by the user if needed. */ flush_addresses (iface->name); memset (&dhcp, 0, sizeof (dhcp_t)); memset (&last_dhcp, 0, sizeof (dhcp_t)); - dhcp.leasetime = options->leasetime; strcpy (dhcp.classid, options->classid); if (options->clientid[0]) strcpy (dhcp.clientid, options->clientid); @@ -165,22 +158,18 @@ int dhcp_run (options_t *options) sprintf (dhcp.clientid, "%s", ether_ntoa (&iface->ethernet_address)); if (options->requestaddress.s_addr != 0) - memcpy (&dhcp.address, &options->requestaddress, sizeof (struct in_addr)); + dhcp.address.s_addr = options->requestaddress.s_addr; signal_setup (); while (1) { - int timeout_secs = timeout - uptime(); - tv.tv_sec = timeout - uptime (); - tv.tv_usec = 0; - maxfd = signal_fd_set (&rset, iface->fd); - if (timeout_secs > 0 || (options->timeout == 0 && - (state != STATE_INIT || xid))) + if (timeout > 0 || (options->timeout == 0 && + (state != STATE_INIT || xid))) { - if (options->timeout == 0) + if (options->timeout == 0 || dhcp.leasetime == -1) { logger (LOG_DEBUG, "waiting on select for infinity"); retval = select (maxfd + 1, &rset, NULL, NULL, NULL); @@ -188,27 +177,24 @@ int dhcp_run (options_t *options) else { logger (LOG_DEBUG, "waiting on select for %d seconds", - timeout_secs); + timeout); /* If we're waiting for a reply, then we re-send the last DHCP request periodically in-case of a bad line */ - if (iface->fd == -1) + retval = 0; + while (timeout > 0 && retval == 0) { - tv.tv_sec = timeout_secs; + if (iface->fd == -1) + tv.tv_sec = SELECT_MAX; + else + tv.tv_sec = TIMEOUT_MINI; + if (timeout < tv.tv_sec) + tv.tv_sec = timeout; tv.tv_usec = 0; + start = uptime (); retval = select (maxfd + 1, &rset, NULL, NULL, &tv); - } - else - { - while (timeout_secs > 0) - { - tv.tv_sec = TIMEOUT_MINI; - tv.tv_usec = 0; - retval = select (maxfd + 1, &rset, NULL, NULL, &tv); - if (retval != 0) - break; - send_message (iface, &last_dhcp, xid, last_type, options); - timeout_secs -= TIMEOUT_MINI; - } + if (retval == 0 && iface->fd != -1) + send_message (iface, &last_dhcp, xid, last_type, options); + timeout -= uptime () - start; } } } @@ -236,7 +222,6 @@ int dhcp_run (options_t *options) switch (state) { case STATE_BOUND: - SOCKET_MODE (SOCKET_OPEN); case STATE_RENEWING: case STATE_REBINDING: state = STATE_RENEW_REQUESTED; @@ -313,51 +298,54 @@ int dhcp_run (options_t *options) } } - timeout = uptime () + options->timeout; + SOCKET_MODE (SOCKET_OPEN); + timeout = options->timeout; if (dhcp.address.s_addr == 0) - logger (LOG_INFO, "broadcasting for lease"); + { + logger (LOG_INFO, "broadcasting for a lease"); + SEND_MESSAGE (DHCP_DISCOVER); + } else - logger (LOG_INFO, "broadcasting for lease of %s", - inet_ntoa (dhcp.address)); + { + logger (LOG_INFO, "broadcasting for a lease of %s", + inet_ntoa (dhcp.address)); + SEND_MESSAGE (DHCP_REQUEST); + state = STATE_REQUESTING; + } - SOCKET_MODE (SOCKET_OPEN); - SEND_MESSAGE (DHCP_DISCOVER); break; case STATE_BOUND: + case STATE_RENEW_REQUESTED: state = STATE_RENEWING; + xid = random_xid (); case STATE_RENEWING: logger (LOG_INFO, "renewing lease of %s", inet_ntoa (dhcp.address)); SOCKET_MODE (SOCKET_OPEN); - xid = random_xid (); SEND_MESSAGE (DHCP_REQUEST); - timeout = uptime() + (dhcp.rebindtime - dhcp.renewaltime); + timeout = dhcp.rebindtime - dhcp.renewaltime; state = STATE_REBINDING; break; case STATE_REBINDING: logger (LOG_ERR, "lost lease, attemping to rebind"); - xid = random_xid (); + SOCKET_MODE (SOCKET_OPEN); SEND_MESSAGE (DHCP_DISCOVER); - timeout = uptime() + (dhcp.leasetime - dhcp.rebindtime); + timeout = dhcp.leasetime - dhcp.rebindtime; state = STATE_INIT; break; case STATE_REQUESTING: - case STATE_RENEW_REQUESTED: logger (LOG_ERR, "timed out"); - if (! daemonised) - { - retval = -1; - goto eexit; - } - state = STATE_INIT; - timeout = uptime(); + SOCKET_MODE (SOCKET_CLOSED); + timeout = 0; xid = 0; - SOCKET_MODE (SOCKET_OPEN); + free_dhcp (&dhcp); + memset (&dhcp, 0, sizeof (dhcp_t)); + memset (&last_dhcp, 0, sizeof (dhcp_t)); break; case STATE_RELEASED: - timeout = 0x7fffffff; + dhcp.leasetime = -1; break; } } @@ -386,15 +374,16 @@ int dhcp_run (options_t *options) if (xid != message.xid) { - logger (LOG_ERR, "ignoring transaction %d as it's not ours (%d)", + logger (LOG_ERR, + "ignoring packet with xid %d as it's not ours (%d)", message.xid, xid); continue; } - logger (LOG_DEBUG, "got packet with transaction %d", message.xid); + logger (LOG_DEBUG, "got a packet with xid %d", message.xid); if ((type = parse_dhcpmessage (&dhcp, &message)) < 0) { - logger (LOG_ERR, "failed to parse message"); + logger (LOG_ERR, "failed to parse packet"); continue; } @@ -409,6 +398,20 @@ int dhcp_run (options_t *options) if (! valid) continue; + /* We should restart on a NAK */ + if (type == DHCP_NAK) + { + logger (LOG_INFO, "received NAK: %s", dhcp.message); + state = STATE_INIT; + timeout = 0; + xid = 0; + free_dhcp (&dhcp); + memset (&dhcp, 0, sizeof (dhcp_t)); + memset (&last_dhcp, 0, sizeof (dhcp_t)); + configure (options, iface, &dhcp); + continue; + } + switch (state) { case STATE_INIT: @@ -474,11 +477,16 @@ int dhcp_run (options_t *options) dhcp.rebindtime); } - logger (LOG_INFO, "leased %s for %d seconds", - inet_ntoa (dhcp.address), dhcp.leasetime); + if (dhcp.leasetime == -1) + logger (LOG_INFO, "leased %s for infinity", + inet_ntoa (dhcp.address)); + else + logger (LOG_INFO, "leased %s for %u seconds", + inet_ntoa (dhcp.address), + dhcp.leasetime, dhcp.renewaltime); + state = STATE_BOUND; - start = uptime (); - timeout = start + dhcp.renewaltime; + timeout = dhcp.renewaltime; xid = 0; if (configure (options, iface, &dhcp) < 0 && ! daemonised) @@ -497,8 +505,6 @@ int dhcp_run (options_t *options) daemonised = true; } } - else if (type == DHCP_NAK) - logger (LOG_INFO, "received NAK: %s", dhcp.message); else if (type == DHCP_OFFER) logger (LOG_INFO, "got subsequent offer of %s, ignoring ", inet_ntoa (dhcp.address)); @@ -511,12 +517,14 @@ int dhcp_run (options_t *options) } else if (retval == -1 && errno == EINTR) { - /* Signal interupt will be handled above */ + /* The interupt will be handled above */ } else { - /* An error occured */ + /* An error occured. As we heavily depend on select, we abort. */ logger (LOG_ERR, "error on select: %s", strerror (errno)); + retval = -1; + goto eexit; } } @@ -524,15 +532,10 @@ eexit: SOCKET_MODE (SOCKET_CLOSED); /* Remove our config if we need to */ - if (dhcp.address.s_addr != 0 && ! options->persistent && daemonised) - { - dhcp.address.s_addr = 0; - dhcp.netmask.s_addr = 0; - dhcp.broadcast.s_addr = 0; - configure (options, iface, &dhcp); - } - free_dhcp (&dhcp); + memset (&dhcp, 0, sizeof (dhcp_t)); + if (iface->previous_address.s_addr != 0 && ! options->persistent && daemonised) + configure (options, iface, &dhcp); if (iface) { diff --git a/configure.c b/configure.c index ff6cecf4..a70859a5 100644 --- a/configure.c +++ b/configure.c @@ -252,11 +252,11 @@ static int write_info(interface_t *iface, dhcp_t *dhcp) return -1; } - fprintf (f, "IPADDR=%s\n", inet_ntoa (dhcp->address)); - fprintf (f, "NETMASK=%s\n", inet_ntoa (dhcp->netmask)); - fprintf (f, "BROADCAST=%s\n", inet_ntoa (dhcp->broadcast)); + fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); + fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); + fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); if (dhcp->mtu > 0) - fprintf (f, "MTU=%d\n", dhcp->mtu); + fprintf (f, "MTU='%d'\n", dhcp->mtu); if (dhcp->routes) { @@ -295,9 +295,9 @@ static int write_info(interface_t *iface, dhcp_t *dhcp) if (dhcp->fqdn) { - fprintf (f, "FQDNFLAGS=%u\n", dhcp->fqdn->flags); - fprintf (f, "FQDNRCODE1=%u\n", dhcp->fqdn->r1); - fprintf (f, "FQDNRCODE2=%u\n", dhcp->fqdn->r2); + fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags); + fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1); + fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2); fprintf (f, "FQDNHOSTNAME='%s'\n", dhcp->fqdn->name); } @@ -331,12 +331,12 @@ static int write_info(interface_t *iface, dhcp_t *dhcp) if (dhcp->rootpath) fprintf (f, "ROOTPATH='%s'\n", cleanmetas (dhcp->rootpath)); - fprintf (f, "DHCPSID=%s\n", inet_ntoa (dhcp->serveraddress)); - fprintf (f, "DHCPCHADDR=%s\n", ether_ntoa (&iface->ethernet_address)); + fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); + fprintf (f, "DHCPCHADDR='%s'\n", ether_ntoa (&iface->ethernet_address)); fprintf (f, "DHCPSNAME='%s'\n", cleanmetas (dhcp->servername)); - fprintf (f, "LEASETIME=%u\n", dhcp->leasetime); - fprintf (f, "RENEWALTIME=%u\n", dhcp->renewaltime); - fprintf (f, "REBINDTIME=%u\n", dhcp->rebindtime); + fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); + fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); + fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); fprintf (f, "INTERFACE='%s'\n", iface->name); fprintf (f, "CLASSID='%s'\n", cleanmetas (dhcp->classid)); fprintf (f, "CLIENTID='%s'\n", cleanmetas (dhcp->clientid)); @@ -392,14 +392,17 @@ int configure (options_t *options, interface_t *iface, dhcp_t *dhcp) iface->previous_routes = NULL; } + /* Only reset things if we had set them before */ if (iface->previous_address.s_addr != 0) - del_address (iface->name, iface->previous_address); - memset (&iface->previous_address, 0, sizeof (struct in_addr)); + { + del_address (iface->name, iface->previous_address); + memset (&iface->previous_address, 0, sizeof (struct in_addr)); - restore_resolv (iface->name); - - /* We currently don't have a resolvconf style programs for ntp/nis */ - exec_script (options->script, iface->infofile, "down"); + restore_resolv (iface->name); + + /* we currently don't have a resolvconf style programs for ntp/nis */ + exec_script (options->script, iface->infofile, "down"); + } return 0; } @@ -434,6 +437,11 @@ int configure (options_t *options, interface_t *iface, dhcp_t *dhcp) for (route = dhcp->routes; route; route = route->next) { + /* Don't set default routes if not asked to */ + if (route->destination.s_addr == 0 && route->netmask.s_addr == 0 + && ! options->dogateway) + continue; + int remember = add_route (iface->name, route->destination, route->netmask, route->gateway, options->metric); diff --git a/dhcp.c b/dhcp.c index 486b964d..dc9f6539 100644 --- a/dhcp.c +++ b/dhcp.c @@ -36,6 +36,8 @@ #include "logger.h" #include "socket.h" +#define BROADCAST_FLAG 0x8000 + static char *dhcp_message[] = { [DHCP_DISCOVER] = "DHCP_DISCOVER", [DHCP_OFFER] = "DHCP_OFFER", @@ -55,10 +57,24 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp, unsigned char *p = (unsigned char *) &message.options; unsigned char *n_params = NULL; unsigned long l; + struct in_addr from; + struct in_addr to; if (!iface || !options || !dhcp) return -1; + if (type == DHCP_RELEASE || type == DHCP_INFORM || + (type == DHCP_REQUEST && + iface->previous_address.s_addr == dhcp->address.s_addr)) + from.s_addr = dhcp->address.s_addr; + else + from.s_addr = 0; + + if (type == DHCP_RELEASE) + to.s_addr = dhcp->serveraddress.s_addr; + else + to.s_addr = 0; + memset (&message, 0, sizeof (dhcpmessage_t)); message.op = DHCP_BOOTREQUEST; @@ -67,11 +83,22 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp, message.secs = htons (10); message.xid = xid; memcpy (&message.hwaddr, &iface->ethernet_address, ETHER_ADDR_LEN); - message.cookie = htonl(MAGIC_COOKIE); + message.cookie = htonl (MAGIC_COOKIE); + + /* This logic should be improved so that we don't need to set the 0 + flag as it's done in the above memset statement */ + if (type == DHCP_REQUEST + && dhcp->address.s_addr == iface->previous_address.s_addr + && iface->previous_address.s_addr != 0) + message.flags = 0; + else + message.flags = htons (BROADCAST_FLAG); - if (iface->previous_address.s_addr != 0 && - iface->previous_address.s_addr == dhcp->address.s_addr) - message.ciaddr = iface->previous_address.s_addr; + if (iface->previous_address.s_addr != 0 + && (type == DHCP_INFORM || type == DHCP_RELEASE + || (type == DHCP_REQUEST + && iface->previous_address.s_addr == dhcp->address.s_addr))) + message.ciaddr = iface->previous_address.s_addr; *p++ = DHCP_MESSAGETYPE; *p++ = 1; @@ -86,72 +113,73 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp, p += 2; } - if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0) - { - *p++ = DHCP_ADDRESS; - *p++ = 4; - memcpy (p, &dhcp->address.s_addr, 4); - p += 4; +#define PUTADDR(_type, _val) \ + { \ + *p++ = _type; \ + *p++ = 4; \ + memcpy (p, &_val.s_addr, 4); \ + p += 4; \ } + if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0 + && type != DHCP_RELEASE) + PUTADDR (DHCP_ADDRESS, dhcp->address); if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 && - iface->previous_address.s_addr == 0) - { - *p++ = DHCP_SERVERIDENTIFIER; - *p++ = 4; - memcpy (p, &dhcp->serveraddress.s_addr, 4); - p += 4; - - /* Blank out the server address so we broadcast */ - if (type == DHCP_REQUEST) dhcp->serveraddress.s_addr = 0; - } + (iface->previous_address.s_addr == 0 || type == DHCP_RELEASE)) + PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress); +#undef PUTADDR if (type == DHCP_REQUEST || type == DHCP_DISCOVER) { - if (dhcp->leasetime > 0) + if (options->leasetime != 0) { *p++ = DHCP_LEASETIME; *p++ = 4; - uint32_t ul = htonl (dhcp->leasetime); + uint32_t ul = htonl (options->leasetime); memcpy (p, &ul, 4); p += 4; } } - *p++ = DHCP_PARAMETERREQUESTLIST; - n_params = p; - *p++ = 0; - - if (type == DHCP_REQUEST) + if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST) { - *p++ = DHCP_RENEWALTIME; - *p++ = DHCP_REBINDTIME; - *p++ = DHCP_NETMASK; - *p++ = DHCP_BROADCAST; - *p++ = DHCP_CSR; - /* RFC 3442 states classless static routes should be before routers - * and static routes as classless static routes override them both */ - *p++ = DHCP_ROUTERS; - *p++ = DHCP_STATICROUTE; - *p++ = DHCP_HOSTNAME; - *p++ = DHCP_DNSSEARCH; - *p++ = DHCP_DNSDOMAIN; - *p++ = DHCP_DNSSERVER; - *p++ = DHCP_NISDOMAIN; - *p++ = DHCP_NISSERVER; - *p++ = DHCP_NTPSERVER; - /* These parameters were requested by dhcpcd-2.0 and earlier - but we never did anything with them */ - /* *p++ = DHCP_DEFAULTIPTTL; - *p++ = DHCP_MASKDISCOVERY; - *p++ = DHCP_ROUTERDISCOVERY; */ - } - else - /* Always request one parameter so we don't get the server default - when we don't actally need any at this time */ - *p++ = DHCP_DNSSERVER; + *p++ = DHCP_PARAMETERREQUESTLIST; + n_params = p; + *p++ = 0; - *n_params = p - n_params - 1; + /* If we don't request one item, then we get defaults back which + we don't want */ + if (type == DHCP_DISCOVER) + { + *p++ = DHCP_DNSSERVER; + } + else + { + *p++ = DHCP_RENEWALTIME; + *p++ = DHCP_REBINDTIME; + *p++ = DHCP_NETMASK; + *p++ = DHCP_BROADCAST; + *p++ = DHCP_CSR; + /* RFC 3442 states classless static routes should be before routers + * and static routes as classless static routes override them both */ + *p++ = DHCP_ROUTERS; + *p++ = DHCP_STATICROUTE; + *p++ = DHCP_HOSTNAME; + *p++ = DHCP_DNSSEARCH; + *p++ = DHCP_DNSDOMAIN; + *p++ = DHCP_DNSSERVER; + *p++ = DHCP_NISDOMAIN; + *p++ = DHCP_NISSERVER; + *p++ = DHCP_NTPSERVER; + /* These parameters were requested by dhcpcd-2.0 and earlier + but we never did anything with them */ + /* *p++ = DHCP_DEFAULTIPTTL; + *p++ = DHCP_MASKDISCOVERY; + *p++ = DHCP_ROUTERDISCOVERY; */ + } + + *n_params = p - n_params - 1; + } if (type == DHCP_REQUEST) { @@ -184,19 +212,22 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp, } } - if (options->userclass) + if (type != DHCP_DECLINE && type != DHCP_RELEASE) { - *p++ = DHCP_USERCLASS; - *p++ = l = strlen (options->userclass); - memcpy (p, options->userclass, l); + if (options->userclass) + { + *p++ = DHCP_USERCLASS; + *p++ = l = strlen (options->userclass); + memcpy (p, options->userclass, l); + p += l; + } + + *p++ = DHCP_CLASSID; + *p++ = l = strlen (options->classid); + memcpy (p, options->classid, l); p += l; } - *p++ = DHCP_CLASSID; - *p++ = l = strlen (options->classid); - memcpy (p, options->classid, l); - p += l; - *p++ = DHCP_CLIENTID; if (options->clientid[0]) { @@ -218,8 +249,7 @@ size_t send_message (interface_t *iface, dhcp_t *dhcp, struct udp_dhcp_packet packet; memset (&packet, 0, sizeof (struct udp_dhcp_packet)); - make_dhcp_packet (&packet, (unsigned char *) &message, - dhcp->address, dhcp->serveraddress); + make_dhcp_packet (&packet, (unsigned char *) &message, from, to); logger (LOG_DEBUG, "Sending %s with xid %d", dhcp_message[(int) type], xid); return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet, @@ -330,7 +360,7 @@ static route_t *decodeCSR(unsigned char *p, int len) { memset (route, 0, sizeof (route_t)); - cidr = (int) *q++; + cidr = *q++; if (cidr == 0) ocets = 0; else if (cidr < 9) @@ -475,94 +505,77 @@ int parse_dhcpmessage (dhcp_t *dhcp, dhcpmessage_t *message) case DHCP_MESSAGETYPE: retval = (int) *p; break; - +#define GET_UINT32(_val) \ + memcpy (&_val, p, sizeof (uint32_t)); +#define GET_UINT32_H(_val) \ + GET_UINT32 (_val); \ + _val = ntohl (_val); case DHCP_ADDRESS: - memcpy (&dhcp->address.s_addr, p, 4); + GET_UINT32 (dhcp->address.s_addr); break; case DHCP_NETMASK: - memcpy (&dhcp->netmask.s_addr, p, 4); + GET_UINT32 (dhcp->netmask.s_addr); break; case DHCP_BROADCAST: - memcpy (&dhcp->broadcast.s_addr, p, 4); + GET_UINT32 (dhcp->broadcast.s_addr); break; case DHCP_SERVERIDENTIFIER: - memcpy (&dhcp->serveraddress.s_addr, p, 4); + GET_UINT32 (dhcp->serveraddress.s_addr); break; - case DHCP_LEASETIME: - dhcp->leasetime = ntohl (* (uint32_t *) p); + GET_UINT32_H (dhcp->leasetime); break; case DHCP_RENEWALTIME: - dhcp->renewaltime = ntohl (* (uint32_t *) p); + GET_UINT32_H (dhcp->renewaltime); break; case DHCP_REBINDTIME: - dhcp->rebindtime = ntohl (* (uint32_t *) p); + GET_UINT32_H (dhcp->rebindtime); break; case DHCP_MTU: - dhcp->mtu = ntohs (* (uint16_t *) p); + GET_UINT32_H (dhcp->mtu); /* Minimum legal mtu is 68 */ if (dhcp->mtu > 0 && dhcp->mtu < 68) dhcp->mtu = 68; break; - +#undef GET_UINT32_H +#undef GET_UINT32 + +#define GETSTR(_var) \ + if (_var) free (_var); \ + _var = xmalloc (length + 1); \ + memcpy (_var, p, length); \ + memset (_var + length, 0, 1); case DHCP_HOSTNAME: - if (dhcp->hostname) - free (dhcp->hostname); - dhcp->hostname = xmalloc (length + 1); - memcpy (dhcp->hostname, p, length); - dhcp->hostname[length] = '\0'; + GETSTR (dhcp->hostname); break; - case DHCP_DNSDOMAIN: - if (dhcp->dnsdomain) - free (dhcp->dnsdomain); - dhcp->dnsdomain = xmalloc (length + 1); - memcpy (dhcp->dnsdomain, p, length); - dhcp->dnsdomain[length] = '\0'; + GETSTR (dhcp->dnsdomain); break; - case DHCP_MESSAGE: - if (dhcp->message) - free (dhcp->message); - dhcp->message = xmalloc (length + 1); - memcpy (dhcp->message, p, length); - dhcp->message[length] = '\0'; + GETSTR (dhcp->message); break; - case DHCP_ROOTPATH: - if (dhcp->rootpath) - free (dhcp->rootpath); - dhcp->rootpath = xmalloc (length + 1); - memcpy (dhcp->rootpath, p, length); - dhcp->rootpath[length] = '\0'; + GETSTR (dhcp->rootpath); break; - case DHCP_NISDOMAIN: - if (dhcp->nisdomain) - free (dhcp->nisdomain); - dhcp->nisdomain = xmalloc (length + 1); - memcpy (dhcp->nisdomain, p, length); - dhcp->nisdomain[length] = '\0'; + GETSTR (dhcp->nisdomain); break; +#undef GETSTR +#define GETADDR(_var) \ + if (_var) free (_var); \ + _var = xmalloc (sizeof (address_t)); \ + dhcp_add_address (_var, p, length); case DHCP_DNSSERVER: - if (dhcp->dnsservers) - free_address (dhcp->dnsservers); - dhcp->dnsservers = xmalloc (sizeof (address_t)); - dhcp_add_address (dhcp->dnsservers, p, length); + GETADDR (dhcp->dnsservers); break; case DHCP_NTPSERVER: - if (dhcp->ntpservers) - free_address (dhcp->ntpservers); - dhcp->ntpservers = xmalloc (sizeof (address_t)); - dhcp_add_address (dhcp->ntpservers, p, length); + GETADDR (dhcp->ntpservers); break; case DHCP_NISSERVER: - if (dhcp->nisservers) - free_address (dhcp->nisservers); - dhcp->nisservers = xmalloc (sizeof (address_t)); - dhcp_add_address (dhcp->nisservers, p, length); + GETADDR (dhcp->nisservers); break; +#undef GETADDR case DHCP_DNSSEARCH: if (dhcp->dnssearch) @@ -612,9 +625,9 @@ int parse_dhcpmessage (dhcp_t *dhcp, dhcpmessage_t *message) eexit: /* Fill in any missing fields */ - if (!dhcp->netmask.s_addr) + if (! dhcp->netmask.s_addr) dhcp->netmask.s_addr = getnetmask (dhcp->address.s_addr); - if (!dhcp->broadcast.s_addr) + if (! dhcp->broadcast.s_addr) dhcp->broadcast.s_addr = dhcp->address.s_addr | ~dhcp->netmask.s_addr; /* If we have classess static routes then we discard diff --git a/dhcp.h b/dhcp.h index 93af9cfc..b5076b38 100644 --- a/dhcp.h +++ b/dhcp.h @@ -128,9 +128,9 @@ typedef struct dhcp_t struct in_addr broadcast; unsigned short mtu; - unsigned leasetime; - unsigned renewaltime; - unsigned rebindtime; + unsigned int leasetime; + unsigned int renewaltime; + unsigned int rebindtime; route_t *routes; diff --git a/dhcpcd.8 b/dhcpcd.8 index 936d27a4..7bdf9753 100644 --- a/dhcpcd.8 +++ b/dhcpcd.8 @@ -1,6 +1,6 @@ .\" $Id$ .\" -.TH dhcpcd 8 "15 August 2006" "dhcpcd 3.0" +.TH dhcpcd 8 "30 November 2006" "dhcpcd 3.0" .SH NAME dhcpcd \- DHCP client daemon @@ -144,9 +144,11 @@ is stopped it can no longer down an interface at the end of its lease period when the lease is not renewed. .TP .BI \-s \ ipaddr -Sends DHCP_DISCOVER message to DHCP server requesting to lease ip address -ipaddr. +Sends DHCP_REQUEST message requesting to lease IP address ipaddr. The ipaddr parameter must be in the form xxx.xxx.xxx.xxx. +This effectively doubles the timeout period, as if we fail to get +this IP address then we enter the INIT state and try to get any +IP address. .TP .BI \-t \ timeout Specifies (in seconds ) for how long diff --git a/dhcpcd.c b/dhcpcd.c index 9b03fb03..0e5a5b20 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -56,7 +56,7 @@ _int = (int) _number; \ } -static pid_t readpid(char *pidfile) +static pid_t read_pid(const char *pidfile) { FILE *fp; pid_t pid; @@ -73,18 +73,18 @@ static pid_t readpid(char *pidfile) return pid; } -static int kill_pid (char *pidfile, int sig) +void make_pid (const char *pidfile) { - pid_t pid = readpid (pidfile); - int r = 0; + FILE *fp; - if (!pid || (r = kill (pid, sig))) + if ((fp = fopen (pidfile, "w")) == NULL) { - logger (LOG_ERR, ""PACKAGE" not running"); - unlink (pidfile); + logger (LOG_ERR, "fopen `%s': %s", pidfile, strerror (errno)); + return; } - return r; + fprintf (fp, "%u\n", getpid ()); + fclose (fp); } static void usage () @@ -330,20 +330,31 @@ int main(int argc, char **argv) options.interface); if (options.signal != 0) - exit (kill_pid (options.pidfile, options.signal)); - - umask (022); - - if (readpid (options.pidfile)) { - logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile); - exit (EXIT_FAILURE); + pid_t pid = read_pid (options.pidfile); + if (pid != 0) + logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid); + + int killed = -1; + if (! pid || (killed = kill (pid, options.signal))) + logger (options.signal == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); + + if (pid != 0 && (options.signal != SIGALRM || killed != 0)) + unlink (options.pidfile); + + if (killed == 0) + exit (EXIT_SUCCESS); + + if (options.signal != SIGALRM) + exit (EXIT_FAILURE); } + umask (022); + if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { - logger( LOG_ERR, "mkdir(\"%s\",0): %m\n", CONFIGDIR); + logger (LOG_ERR, "mkdir(\"%s\",0): %m\n", CONFIGDIR); exit (EXIT_FAILURE); } @@ -354,6 +365,14 @@ int main(int argc, char **argv) exit (EXIT_FAILURE); } + if (read_pid (options.pidfile)) + { + logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile); + exit (EXIT_FAILURE); + } + + make_pid (options.pidfile); + logger (LOG_INFO, PACKAGE " " VERSION " starting"); if (dhcp_run (&options)) exit (EXIT_FAILURE); diff --git a/dhcpcd.h b/dhcpcd.h index f0ffb5a5..820ab86c 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -64,4 +64,6 @@ typedef struct options_t { char pidfile[PATH_MAX]; } options_t; +void make_pid (const char *pidfile); + #endif diff --git a/interface.c b/interface.c index c55a662c..abdfbfc1 100644 --- a/interface.c +++ b/interface.c @@ -51,10 +51,6 @@ #include "logger.h" #include "pathnames.h" -#ifndef IFF_NOTRAILERS -#define IFF_NOTRAILERS 0 -#endif - void free_address (address_t *addresses) { if (!addresses) @@ -99,7 +95,6 @@ interface_t *read_interface (const char *ifname, int metric) struct ifaddrs *ifap; struct ifaddrs *p; - unsigned int flags; if (getifaddrs (&ifap) != 0) return NULL; @@ -122,7 +117,6 @@ interface_t *read_interface (const char *ifname, int metric) return NULL; } - flags = p->ifa_flags; #ifdef __linux__ memcpy (hwaddr, sll->sll_addr, ETHER_ADDR_LEN); #else @@ -146,30 +140,34 @@ interface_t *read_interface (const char *ifname, int metric) return NULL; } - if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) +#ifndef __linux__ + ifr.ifr_metric = metric; + if (ioctl(s, SIOCSIFMETRIC, &ifr) < 0) { - logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); + logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); close (s); return NULL; } +#endif - ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING; - if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) + if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { - logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno)); + logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); close (s); return NULL; } -#ifndef __linux__ - ifr.ifr_metric = metric; - if (ioctl(s, SIOCSIFMETRIC, &ifr) < 0) + /* Bring the interface up if we need to */ + if (! (ifr.ifr_flags & IFF_UP)) { - logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); - close (s); - return NULL; + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) + { + logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno)); + close (s); + return NULL; + } } -#endif close (s); diff --git a/socket.c b/socket.c index 3996d3b2..5c33ba60 100644 --- a/socket.c +++ b/socket.c @@ -94,11 +94,11 @@ void make_dhcp_packet(struct udp_dhcp_packet *packet, memcpy (&packet->dhcp, data, sizeof (dhcpmessage_t)); ip->ip_p = IPPROTO_UDP; - ip->ip_src.s_addr = htonl (source.s_addr); + ip->ip_src.s_addr = source.s_addr; if (dest.s_addr == 0) - ip->ip_dst.s_addr = htonl (INADDR_BROADCAST); + ip->ip_dst.s_addr = INADDR_BROADCAST; else - ip->ip_dst.s_addr = htonl (dest.s_addr); + ip->ip_dst.s_addr = dest.s_addr; udp->uh_sport = htons (DHCP_CLIENT_PORT); udp->uh_dport = htons (DHCP_SERVER_PORT);