#define ar_sha(ap) (((unsigned char *) ((ap) + 1)) + 0)
#define ar_spa(ap) (((unsigned char *) ((ap) + 1)) + (ap)->ar_hln)
#define ar_tha(ap) (((unsigned char *) ((ap) + 1)) + \
- (ap)->ar_hln + (ap)->ar_pln)
+ (ap)->ar_hln + (ap)->ar_pln)
#define ar_tpa(ap) (((unsigned char *) ((ap) + 1)) + \
- 2 * (ap)->ar_hln + (ap)->ar_pln)
+ 2 * (ap)->ar_hln + (ap)->ar_pln)
#define arphdr_len2(ar_hln, ar_pln) (sizeof (struct arphdr) + \
- 2 * (ar_hln) + 2 * (ar_pln))
+ 2 * (ar_hln) + 2 * (ar_pln))
#define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln))
#endif
int arp_check (interface_t *iface, struct in_addr address)
{
- union
- {
- unsigned char buffer[iface->buffer_length];
- struct arphdr ah;
- } arp;
-
- int bytes;
- struct timeval tv;
- long timeout = 0;
- fd_set rset;
-
- if (! iface->arpable)
- {
- logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable",
- iface->name);
- return 0;
- }
-
- memset (arp.buffer, 0, sizeof (arp.buffer));
-
- arp.ah.ar_hrd = htons (iface->family);
- arp.ah.ar_pro = htons (ETHERTYPE_IP);
- arp.ah.ar_hln = iface->hwlen;
- arp.ah.ar_pln = sizeof (struct in_addr);
- arp.ah.ar_op = htons (ARPOP_REQUEST);
- memcpy (ar_sha (&arp.ah), &iface->hwaddr, arp.ah.ar_hln);
- memcpy (ar_tpa (&arp.ah), &address, arp.ah.ar_pln);
-
- logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa
- (address));
-
- open_socket (iface, true);
- send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &arp.buffer,
- arphdr_len (&arp.ah));
-
- timeout = uptime() + TIMEOUT;
- while (1)
- {
- int buflen = sizeof (arp.buffer);
- int bufpos = -1;
-
- tv.tv_sec = timeout - uptime ();
- tv.tv_usec = 0;
-
- if (tv.tv_sec < 1)
- break; /* Time out */
-
- FD_ZERO (&rset);
- FD_SET (iface->fd, &rset);
-
- if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0)
- break;
-
- if (! FD_ISSET (iface->fd, &rset))
- continue;
-
- memset (arp.buffer, 0, sizeof (arp.buffer));
-
- while (bufpos != 0)
- {
- union
- {
- unsigned char buffer[buflen];
- struct arphdr hdr;
- } reply;
- union
- {
- unsigned char *c;
- struct in_addr *a;
- } rp;
- union
- {
- unsigned char *c;
- struct ether_addr *a;
- } rh;
- memset (reply.buffer, 0, sizeof (reply.buffer));
- if ((bytes = get_packet (iface, reply.buffer, arp.buffer,
- &buflen, &bufpos)) < 0)
- break;
-
- /* Only these types are recognised */
- if (reply.hdr.ar_op != htons(ARPOP_REPLY))
- continue;
-
- /* Protocol must be IP. */
- if (reply.hdr.ar_pro != htons (ETHERTYPE_IP))
- continue;
- if (reply.hdr.ar_pln != sizeof (struct in_addr))
- continue;
-
- if (reply.hdr.ar_hln != ETHER_ADDR_LEN)
- continue;
- if ((unsigned) bytes < sizeof (reply.hdr) +
- 2 * (4 + reply.hdr.ar_hln))
- continue;
-
- rp.c = (unsigned char *) ar_spa (&reply.hdr);
- rh.c = (unsigned char *) ar_sha (&reply.hdr);
- logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)",
- inet_ntoa (*rp.a), ether_ntoa (rh.a));
- close (iface->fd);
- iface->fd = -1;
- return 1;
- }
- }
-
- close (iface->fd);
- iface->fd = -1;
- return 0;
+ union {
+ unsigned char buffer[iface->buffer_length];
+ struct arphdr ah;
+ } arp;
+
+ int bytes;
+ struct timeval tv;
+ long timeout = 0;
+ fd_set rset;
+
+ if (! iface->arpable) {
+ logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable",
+ iface->name);
+ return 0;
+ }
+
+ memset (arp.buffer, 0, sizeof (arp.buffer));
+
+ arp.ah.ar_hrd = htons (iface->family);
+ arp.ah.ar_pro = htons (ETHERTYPE_IP);
+ arp.ah.ar_hln = iface->hwlen;
+ arp.ah.ar_pln = sizeof (struct in_addr);
+ arp.ah.ar_op = htons (ARPOP_REQUEST);
+ memcpy (ar_sha (&arp.ah), &iface->hwaddr, arp.ah.ar_hln);
+ memcpy (ar_tpa (&arp.ah), &address, arp.ah.ar_pln);
+
+ logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa
+ (address));
+
+ open_socket (iface, true);
+ send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &arp.buffer,
+ arphdr_len (&arp.ah));
+
+ timeout = uptime() + TIMEOUT;
+ while (1) {
+ int buflen = sizeof (arp.buffer);
+ int bufpos = -1;
+
+ tv.tv_sec = timeout - uptime ();
+ tv.tv_usec = 0;
+
+ if (tv.tv_sec < 1)
+ break; /* Time out */
+
+ FD_ZERO (&rset);
+ FD_SET (iface->fd, &rset);
+
+ if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0)
+ break;
+
+ if (! FD_ISSET (iface->fd, &rset))
+ continue;
+
+ memset (arp.buffer, 0, sizeof (arp.buffer));
+
+ while (bufpos != 0) {
+ union {
+ unsigned char buffer[buflen];
+ struct arphdr hdr;
+ } reply;
+ union {
+ unsigned char *c;
+ struct in_addr *a;
+ } rp;
+ union {
+ unsigned char *c;
+ struct ether_addr *a;
+ } rh;
+
+ memset (reply.buffer, 0, sizeof (reply.buffer));
+ if ((bytes = get_packet (iface, reply.buffer, arp.buffer,
+ &buflen, &bufpos)) < 0)
+ break;
+
+ /* Only these types are recognised */
+ if (reply.hdr.ar_op != htons(ARPOP_REPLY))
+ continue;
+
+ /* Protocol must be IP. */
+ if (reply.hdr.ar_pro != htons (ETHERTYPE_IP))
+ continue;
+ if (reply.hdr.ar_pln != sizeof (struct in_addr))
+ continue;
+
+ if (reply.hdr.ar_hln != ETHER_ADDR_LEN)
+ continue;
+ if ((unsigned) bytes < sizeof (reply.hdr) +
+ 2 * (4 + reply.hdr.ar_hln))
+ continue;
+
+ rp.c = (unsigned char *) ar_spa (&reply.hdr);
+ rh.c = (unsigned char *) ar_sha (&reply.hdr);
+ logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)",
+ inet_ntoa (*rp.a), ether_ntoa (rh.a));
+ close (iface->fd);
+ iface->fd = -1;
+ return 1;
+ }
+ }
+
+ close (iface->fd);
+ iface->fd = -1;
+ return 0;
}
#define SOCKET_CLOSED 0
#define SOCKET_OPEN 1
-#define SOCKET_MODE(_mode) \
-{ \
- if (iface->fd >= 0) close (iface->fd); \
- iface->fd = -1; \
- if (_mode == SOCKET_OPEN) \
- if (open_socket (iface, false) < 0) { retval = -1; goto eexit; } \
- mode = _mode; \
+#define SOCKET_MODE(_mode) { \
+ if (iface->fd >= 0) close (iface->fd); \
+ iface->fd = -1; \
+ if (_mode == SOCKET_OPEN) \
+ if (open_socket (iface, false) < 0) { retval = -1; goto eexit; } \
+ mode = _mode; \
}
-#define SEND_MESSAGE(_type) \
-{ \
- last_type = _type; \
- last_send = uptime (); \
- send_message (iface, dhcp, xid, _type, options); \
+#define SEND_MESSAGE(_type) { \
+ last_type = _type; \
+ last_send = uptime (); \
+ send_message (iface, dhcp, xid, _type, options); \
}
-#define DROP_CONFIG \
-{ \
- memset (&dhcp->address, 0, sizeof (struct in_addr)); \
- if (iface->previous_address.s_addr != 0 && ! options->persistent) \
- configure (options, iface, dhcp); \
- free_dhcp (dhcp); \
- memset (dhcp, 0, sizeof (dhcp_t)); \
+#define DROP_CONFIG { \
+ memset (&dhcp->address, 0, sizeof (struct in_addr)); \
+ if (iface->previous_address.s_addr != 0 && ! options->persistent) \
+ configure (options, iface, dhcp); \
+ free_dhcp (dhcp); \
+ memset (dhcp, 0, sizeof (dhcp_t)); \
}
static int daemonise (const char *pidfile)
{
- logger (LOG_DEBUG, "forking to background");
- if (daemon (0, 0) < 0)
- {
- logger (LOG_ERR, "daemon: %s", strerror (errno));
- return -1;
- }
+ logger (LOG_DEBUG, "forking to background");
+ if (daemon (0, 0) < 0) {
+ logger (LOG_ERR, "daemon: %s", strerror (errno));
+ return -1;
+ }
- make_pid (pidfile);
+ make_pid (pidfile);
- return 0;
+ return 0;
}
static unsigned long random_xid (void)
{
- static int initialized;
-
- if (! initialized)
- {
- int fd;
- unsigned long seed;
-
- fd = open ("/dev/urandom", 0);
- if (fd < 0 || read (fd, &seed, sizeof(seed)) < 0)
- {
- logger (LOG_WARNING, "Could not load seed from /dev/urandom: %s",
- strerror (errno));
- seed = time (0);
- }
- if (fd >= 0)
- close(fd);
-
- srand(seed);
- initialized++;
- }
-
- return rand();
+ static int initialized;
+
+ if (! initialized) {
+ int fd;
+ unsigned long seed;
+
+ fd = open ("/dev/urandom", 0);
+ if (fd < 0 || read (fd, &seed, sizeof(seed)) < 0) {
+ logger (LOG_WARNING, "Could not load seed from /dev/urandom: %s",
+ strerror (errno));
+ seed = time (0);
+ }
+ if (fd >= 0)
+ close(fd);
+
+ srand(seed);
+ initialized++;
+ }
+
+ return rand();
}
/* This state machine is based on the one from udhcpc
written by Russ Dill */
int dhcp_run (const options_t *options)
{
- interface_t *iface;
- int mode = SOCKET_CLOSED;
- int state = STATE_INIT;
- struct timeval tv;
- int xid = 0;
- long timeout = 0;
- fd_set rset;
- int maxfd;
- int retval;
- dhcpmessage_t message;
- dhcp_t *dhcp;
- int type = DHCP_DISCOVER;
- int last_type = DHCP_DISCOVER;
- bool daemonised = false;
- unsigned long start = 0;
- unsigned long last_send = 0;
- int sig;
- unsigned char *buffer = NULL;
- int buffer_len = 0;
- int buffer_pos = 0;
-
- if (! options || (iface = (read_interface (options->interface,
- options->metric))) == NULL)
- return -1;
-
- /* 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. */
- flush_addresses (iface->name);
-
- dhcp = xmalloc (sizeof (dhcp_t));
- memset (dhcp, 0, sizeof (dhcp_t));
-
- if (options->requestaddress.s_addr != 0)
- dhcp->address.s_addr = options->requestaddress.s_addr;
-
- signal_setup ();
-
- while (1)
- {
- if (timeout > 0 || (options->timeout == 0 &&
- (state != STATE_INIT || xid)))
- {
- if (options->timeout == 0 ||
- (dhcp->leasetime == (unsigned) -1 && state == STATE_BOUND))
- {
- int retry = 0;
- logger (LOG_DEBUG, "waiting on select for infinity");
- retval = 0;
- while (retval == 0)
- {
- maxfd = signal_fd_set (&rset, iface->fd);
- if (iface->fd == -1)
- retval = select (maxfd + 1, &rset, NULL, NULL, NULL);
- else
- {
- /* Slow down our requests */
- if (retry < TIMEOUT_MINI_INF)
- retry += TIMEOUT_MINI;
- else if (retry > TIMEOUT_MINI_INF)
- retry = TIMEOUT_MINI_INF;
-
- tv.tv_sec = retry;
- tv.tv_usec = 0;
- retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
- if (retval == 0)
- SEND_MESSAGE (last_type);
- }
- }
- }
- else
- {
- /* Resend our message if we're getting loads of packets
- that aren't for us. This mainly happens on Linux as it
- doesn't have a nice BPF filter. */
- if (iface->fd > -1 && uptime () - last_send >= TIMEOUT_MINI)
- SEND_MESSAGE (last_type);
-
- logger (LOG_DEBUG, "waiting on select for %ld seconds",
- timeout);
- /* If we're waiting for a reply, then we re-send the last
- DHCP request periodically in-case of a bad line */
- retval = 0;
- while (timeout > 0 && retval == 0)
- {
- 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 ();
- maxfd = signal_fd_set (&rset, iface->fd);
- retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
- timeout -= uptime () - start;
- if (retval == 0 && iface->fd != -1 && timeout > 0)
- SEND_MESSAGE (last_type);
- }
- }
- }
- else
- retval = 0;
-
- /* We should always handle our signals first */
- if (retval > 0 && (sig = signal_read (&rset)))
- {
- switch (sig)
- {
- case SIGINT:
- logger (LOG_INFO, "received SIGINT, stopping");
- retval = (! daemonised);
- goto eexit;
-
- case SIGTERM:
- logger (LOG_INFO, "received SIGTERM, stopping");
- retval = (! daemonised);
- goto eexit;
-
- case SIGALRM:
-
- logger (LOG_INFO, "received SIGALRM, renewing lease");
- switch (state)
- {
- case STATE_BOUND:
- case STATE_RENEWING:
- case STATE_REBINDING:
- state = STATE_RENEW_REQUESTED;
- break;
- case STATE_RENEW_REQUESTED:
- case STATE_REQUESTING:
- case STATE_RELEASED:
- state = STATE_INIT;
- break;
- }
-
- timeout = 0;
- xid = 0;
- break;
-
- case SIGHUP:
- if (state == STATE_BOUND || state == STATE_RENEWING
- || state == STATE_REBINDING)
- {
- logger (LOG_INFO, "received SIGHUP, releasing lease");
- SOCKET_MODE (SOCKET_OPEN);
- xid = random_xid ();
- if ((open_socket (iface, false)) >= 0)
- SEND_MESSAGE (DHCP_RELEASE);
- SOCKET_MODE (SOCKET_CLOSED);
- unlink (iface->infofile);
- }
- else
- logger (LOG_ERR,
- "received SIGHUP, but no we have lease to release");
- retval = 0;
- goto eexit;
-
- default:
- logger (LOG_ERR,
- "received signal %d, but don't know what to do with it",
- sig);
- }
- }
- else if (retval == 0) /* timed out */
- {
- switch (state)
- {
- case STATE_INIT:
- if (iface->previous_address.s_addr != 0)
- {
- logger (LOG_ERR, "lost lease");
- xid = 0;
- SOCKET_MODE (SOCKET_CLOSED);
- if (! options->persistent)
- DROP_CONFIG;
- }
-
- if (xid == 0)
- xid = random_xid ();
- else
- {
- logger (LOG_ERR, "timed out");
- if (! daemonised)
- {
- retval = -1;
- goto eexit;
- }
- }
-
- SOCKET_MODE (SOCKET_OPEN);
- timeout = options->timeout;
- iface->start_uptime = uptime ();
- if (dhcp->address.s_addr == 0)
- {
- logger (LOG_INFO, "broadcasting for a lease");
- SEND_MESSAGE (DHCP_DISCOVER);
- }
- else
- {
- logger (LOG_INFO, "broadcasting for a lease of %s",
- inet_ntoa (dhcp->address));
- SEND_MESSAGE (DHCP_REQUEST);
- state = STATE_REQUESTING;
- }
-
- break;
- case STATE_BOUND:
- case STATE_RENEW_REQUESTED:
- state = STATE_RENEWING;
- xid = random_xid ();
- case STATE_RENEWING:
- iface->start_uptime = uptime ();
- logger (LOG_INFO, "renewing lease of %s", inet_ntoa
- (dhcp->address));
- SOCKET_MODE (SOCKET_OPEN);
- SEND_MESSAGE (DHCP_REQUEST);
- timeout = dhcp->rebindtime - dhcp->renewaltime;
- state = STATE_REBINDING;
- break;
- case STATE_REBINDING:
- logger (LOG_ERR, "lost lease, attemping to rebind");
- memset (&dhcp->address, 0, sizeof (struct in_addr));
- SOCKET_MODE (SOCKET_OPEN);
- SEND_MESSAGE (DHCP_REQUEST);
- timeout = dhcp->leasetime - dhcp->rebindtime;
- state = STATE_REQUESTING;
- break;
- case STATE_REQUESTING:
- if (iface->previous_address.s_addr != 0)
- logger (LOG_ERR, "lost lease");
- else
- logger (LOG_ERR, "timed out");
- if (! daemonised && options->daemonise)
- goto eexit;
-
- state = STATE_INIT;
- SOCKET_MODE (SOCKET_CLOSED);
- timeout = 0;
- xid = 0;
- DROP_CONFIG;
- break;
-
- case STATE_RELEASED:
- dhcp->leasetime = -1;
- break;
- }
- }
- else if (retval > 0 && mode != SOCKET_CLOSED && FD_ISSET(iface->fd, &rset))
- {
- int valid = 0;
- struct dhcp_t *new_dhcp;
-
- /* Allocate our buffer space for BPF.
- We cannot do this until we have opened our socket as we don't
- know how much of a buffer we need until then. */
- if (! buffer)
- buffer = xmalloc (iface->buffer_length);
- buffer_len = iface->buffer_length;
- buffer_pos = -1;
-
- /* We loop through until our buffer is empty.
- The benefit is that if we get >1 DHCP packet in our buffer and
- the first one fails for any reason, we can use the next. */
-
- memset (&message, 0, sizeof (struct dhcpmessage_t));
- new_dhcp = xmalloc (sizeof (dhcp_t));
-
- while (buffer_pos != 0)
- {
- if (get_packet (iface, (unsigned char *) &message, buffer,
- &buffer_len, &buffer_pos) < 0)
- break;
-
- if (xid != message.xid)
- {
- logger (LOG_ERR,
- "ignoring packet with xid 0x%x as it's not ours (0x%x)",
- message.xid, xid);
- continue;
- }
-
- logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid);
- memset (new_dhcp, 0, sizeof (dhcp_t));
- if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0)
- {
- logger (LOG_ERR, "failed to parse packet");
- free_dhcp (new_dhcp);
- continue;
- }
-
- /* If we got here then the DHCP packet is valid and appears to
- be for us, so let's clear the buffer as we don't care about
- any more DHCP packets at this point. */
- valid = 1;
- break;
- }
-
- /* No packets for us, so wait until we get one */
- if (! valid)
- {
- free (new_dhcp);
- continue;
- }
-
- /* new_dhcp is now our master DHCP message */
- free_dhcp (dhcp);
- free (dhcp);
- dhcp = new_dhcp;
- new_dhcp = NULL;
-
- /* 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;
- DROP_CONFIG;
- continue;
- }
-
- switch (state)
- {
- case STATE_INIT:
- if (type == DHCP_OFFER)
- {
- char *addr = strdup (inet_ntoa (dhcp->address));
- if (dhcp->servername[0])
- logger (LOG_INFO, "offered %s from %s `%s'",
- addr, inet_ntoa (dhcp->serveraddress),
- dhcp->servername);
- else
- logger (LOG_INFO, "offered %s from %s",
- addr, inet_ntoa (dhcp->serveraddress));
- free (addr);
-
- SEND_MESSAGE (DHCP_REQUEST);
- state = STATE_REQUESTING;
- }
- break;
-
- case STATE_RENEW_REQUESTED:
- case STATE_REQUESTING:
- case STATE_RENEWING:
- case STATE_REBINDING:
- if (type == DHCP_ACK)
- {
- SOCKET_MODE (SOCKET_CLOSED);
- if (options->doarp && iface->previous_address.s_addr !=
- dhcp->address.s_addr)
- {
- if (arp_check (iface, dhcp->address))
- {
- SOCKET_MODE (SOCKET_OPEN);
- SEND_MESSAGE (DHCP_DECLINE);
- SOCKET_MODE (SOCKET_CLOSED);
- DROP_CONFIG;
-
- xid = 0;
- timeout = 0;
- state = STATE_INIT;
- /* RFC 2131 says that we should wait for 10 seconds
- before doing anything else */
- logger (LOG_INFO, "sleeping for 10 seconds");
- tv.tv_sec = 10;
- tv.tv_usec = 0;
- select (0, NULL, NULL, NULL, &tv);
- continue;
- }
- }
-
- if (dhcp->leasetime == (unsigned) -1)
- {
- dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime;
- timeout = 1; /* So we select on infinity */
- logger (LOG_INFO, "leased %s for infinity",
- inet_ntoa (dhcp->address));
- }
- else
- {
- if (! dhcp->leasetime)
- {
- dhcp->leasetime = DEFAULT_LEASETIME;
- logger(LOG_INFO,
- "no lease time supplied, assuming %d seconds",
- dhcp->leasetime);
- }
- logger (LOG_INFO, "leased %s for %u seconds",
- inet_ntoa (dhcp->address), dhcp->leasetime);
-
- if (dhcp->rebindtime >= dhcp->leasetime)
- {
- dhcp->rebindtime = (dhcp->leasetime * 0.875);
- logger (LOG_ERR, "rebind time greater than lease "
- "time, forcing to %u seconds",
- dhcp->rebindtime);
- }
-
- if (dhcp->renewaltime > dhcp->rebindtime)
- {
-
- dhcp->renewaltime = (dhcp->leasetime * 0.5);
- logger (LOG_ERR, "renewal time greater than rebind time, "
- "forcing to %u seconds",
- dhcp->renewaltime);
- }
-
- if (! dhcp->renewaltime)
- {
- dhcp->renewaltime = (dhcp->leasetime * 0.5);
- logger (LOG_INFO,
- "no renewal time supplied, assuming %d seconds",
- dhcp->renewaltime);
- }
- else
- logger (LOG_DEBUG, "renew in %u seconds",
- dhcp->renewaltime);
-
- if (! dhcp->rebindtime)
- {
- dhcp->rebindtime = (dhcp->leasetime * 0.875);
- logger (LOG_INFO,
- "no rebind time supplied, assuming %d seconds",
- dhcp->rebindtime);
- }
- else
- logger (LOG_DEBUG, "rebind in %u seconds",
- dhcp->rebindtime);
-
- timeout = dhcp->renewaltime;
- }
-
- state = STATE_BOUND;
- xid = 0;
-
- if (configure (options, iface, dhcp) < 0 && ! daemonised)
- {
- retval = -1;
- goto eexit;
- }
-
- if (! daemonised && options->daemonise)
- {
- if ((daemonise (options->pidfile)) < 0 )
- {
- retval = -1;
- goto eexit;
- }
- daemonised = true;
- }
- }
- else if (type == DHCP_OFFER)
- logger (LOG_INFO, "got subsequent offer of %s, ignoring ",
- inet_ntoa (dhcp->address));
- else
- logger (LOG_ERR,
- "no idea what to do with DHCP type %d at this point",
- type);
- break;
- }
- }
- else if (retval == -1 && errno == EINTR)
- {
- /* The interupt will be handled above */
- }
- else
- {
- /* An error occured. As we heavily depend on select, we abort. */
- logger (LOG_ERR, "error on select: %s", strerror (errno));
- retval = -1;
- goto eexit;
- }
- }
+ interface_t *iface;
+ int mode = SOCKET_CLOSED;
+ int state = STATE_INIT;
+ struct timeval tv;
+ int xid = 0;
+ long timeout = 0;
+ fd_set rset;
+ int maxfd;
+ int retval;
+ dhcpmessage_t message;
+ dhcp_t *dhcp;
+ int type = DHCP_DISCOVER;
+ int last_type = DHCP_DISCOVER;
+ bool daemonised = false;
+ unsigned long start = 0;
+ unsigned long last_send = 0;
+ int sig;
+ unsigned char *buffer = NULL;
+ int buffer_len = 0;
+ int buffer_pos = 0;
+
+ if (! options || (iface = (read_interface (options->interface,
+ options->metric))) == NULL)
+ return -1;
+
+ /* 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. */
+ flush_addresses (iface->name);
+
+ dhcp = xmalloc (sizeof (dhcp_t));
+ memset (dhcp, 0, sizeof (dhcp_t));
+
+ if (options->requestaddress.s_addr != 0)
+ dhcp->address.s_addr = options->requestaddress.s_addr;
+
+ signal_setup ();
+
+ while (1) {
+ if (timeout > 0 || (options->timeout == 0 &&
+ (state != STATE_INIT || xid)))
+ {
+ if (options->timeout == 0 ||
+ (dhcp->leasetime == (unsigned) -1 && state == STATE_BOUND))
+ {
+ int retry = 0;
+ logger (LOG_DEBUG, "waiting on select for infinity");
+ retval = 0;
+ while (retval == 0) {
+ maxfd = signal_fd_set (&rset, iface->fd);
+ if (iface->fd == -1)
+ retval = select (maxfd + 1, &rset, NULL, NULL, NULL);
+ else {
+ /* Slow down our requests */
+ if (retry < TIMEOUT_MINI_INF)
+ retry += TIMEOUT_MINI;
+ else if (retry > TIMEOUT_MINI_INF)
+ retry = TIMEOUT_MINI_INF;
+
+ tv.tv_sec = retry;
+ tv.tv_usec = 0;
+ retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
+ if (retval == 0)
+ SEND_MESSAGE (last_type);
+ }
+ }
+ } else {
+ /* Resend our message if we're getting loads of packets
+ that aren't for us. This mainly happens on Linux as it
+ doesn't have a nice BPF filter. */
+ if (iface->fd > -1 && uptime () - last_send >= TIMEOUT_MINI)
+ SEND_MESSAGE (last_type);
+
+ logger (LOG_DEBUG, "waiting on select for %ld seconds",
+ timeout);
+ /* If we're waiting for a reply, then we re-send the last
+ DHCP request periodically in-case of a bad line */
+ retval = 0;
+ while (timeout > 0 && retval == 0) {
+ 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 ();
+ maxfd = signal_fd_set (&rset, iface->fd);
+ retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
+ timeout -= uptime () - start;
+ if (retval == 0 && iface->fd != -1 && timeout > 0)
+ SEND_MESSAGE (last_type);
+ }
+ }
+ } else
+ retval = 0;
+
+ /* We should always handle our signals first */
+ if (retval > 0 && (sig = signal_read (&rset))) {
+ switch (sig) {
+ case SIGINT:
+ logger (LOG_INFO, "received SIGINT, stopping");
+ retval = (! daemonised);
+ goto eexit;
+
+ case SIGTERM:
+ logger (LOG_INFO, "received SIGTERM, stopping");
+ retval = (! daemonised);
+ goto eexit;
+
+ case SIGALRM:
+
+ logger (LOG_INFO, "received SIGALRM, renewing lease");
+ switch (state) {
+ case STATE_BOUND:
+ case STATE_RENEWING:
+ case STATE_REBINDING:
+ state = STATE_RENEW_REQUESTED;
+ break;
+ case STATE_RENEW_REQUESTED:
+ case STATE_REQUESTING:
+ case STATE_RELEASED:
+ state = STATE_INIT;
+ break;
+ }
+
+ timeout = 0;
+ xid = 0;
+ break;
+
+ case SIGHUP:
+ if (state == STATE_BOUND || state == STATE_RENEWING
+ || state == STATE_REBINDING)
+ {
+ logger (LOG_INFO, "received SIGHUP, releasing lease");
+ SOCKET_MODE (SOCKET_OPEN);
+ xid = random_xid ();
+ if ((open_socket (iface, false)) >= 0)
+ SEND_MESSAGE (DHCP_RELEASE);
+ SOCKET_MODE (SOCKET_CLOSED);
+ unlink (iface->infofile);
+ }
+ else
+ logger (LOG_ERR,
+ "received SIGHUP, but no we have lease to release");
+ retval = 0;
+ goto eexit;
+
+ default:
+ logger (LOG_ERR,
+ "received signal %d, but don't know what to do with it",
+ sig);
+ }
+ } else if (retval == 0) {
+ /* timed out */
+ switch (state) {
+ case STATE_INIT:
+ if (iface->previous_address.s_addr != 0) {
+ logger (LOG_ERR, "lost lease");
+ xid = 0;
+ SOCKET_MODE (SOCKET_CLOSED);
+ if (! options->persistent)
+ DROP_CONFIG;
+ }
+
+ if (xid == 0)
+ xid = random_xid ();
+ else {
+ logger (LOG_ERR, "timed out");
+ if (! daemonised) {
+ retval = -1;
+ goto eexit;
+ }
+ }
+
+ SOCKET_MODE (SOCKET_OPEN);
+ timeout = options->timeout;
+ iface->start_uptime = uptime ();
+ if (dhcp->address.s_addr == 0) {
+ logger (LOG_INFO, "broadcasting for a lease");
+ SEND_MESSAGE (DHCP_DISCOVER);
+ } else {
+ logger (LOG_INFO, "broadcasting for a lease of %s",
+ inet_ntoa (dhcp->address));
+ SEND_MESSAGE (DHCP_REQUEST);
+ state = STATE_REQUESTING;
+ }
+
+ break;
+ case STATE_BOUND:
+ case STATE_RENEW_REQUESTED:
+ state = STATE_RENEWING;
+ xid = random_xid ();
+ case STATE_RENEWING:
+ iface->start_uptime = uptime ();
+ logger (LOG_INFO, "renewing lease of %s", inet_ntoa
+ (dhcp->address));
+ SOCKET_MODE (SOCKET_OPEN);
+ SEND_MESSAGE (DHCP_REQUEST);
+ timeout = dhcp->rebindtime - dhcp->renewaltime;
+ state = STATE_REBINDING;
+ break;
+ case STATE_REBINDING:
+ logger (LOG_ERR, "lost lease, attemping to rebind");
+ memset (&dhcp->address, 0, sizeof (struct in_addr));
+ SOCKET_MODE (SOCKET_OPEN);
+ SEND_MESSAGE (DHCP_REQUEST);
+ timeout = dhcp->leasetime - dhcp->rebindtime;
+ state = STATE_REQUESTING;
+ break;
+ case STATE_REQUESTING:
+ if (iface->previous_address.s_addr != 0)
+ logger (LOG_ERR, "lost lease");
+ else
+ logger (LOG_ERR, "timed out");
+ if (! daemonised && options->daemonise)
+ goto eexit;
+
+ state = STATE_INIT;
+ SOCKET_MODE (SOCKET_CLOSED);
+ timeout = 0;
+ xid = 0;
+ DROP_CONFIG;
+ break;
+
+ case STATE_RELEASED:
+ dhcp->leasetime = -1;
+ break;
+ }
+ } else if (retval > 0 &&
+ mode != SOCKET_CLOSED &&
+ FD_ISSET(iface->fd, &rset))
+ {
+ int valid = 0;
+ struct dhcp_t *new_dhcp;
+
+ /* Allocate our buffer space for BPF.
+ We cannot do this until we have opened our socket as we don't
+ know how much of a buffer we need until then. */
+ if (! buffer)
+ buffer = xmalloc (iface->buffer_length);
+ buffer_len = iface->buffer_length;
+ buffer_pos = -1;
+
+ /* We loop through until our buffer is empty.
+ The benefit is that if we get >1 DHCP packet in our buffer and
+ the first one fails for any reason, we can use the next. */
+
+ memset (&message, 0, sizeof (struct dhcpmessage_t));
+ new_dhcp = xmalloc (sizeof (dhcp_t));
+
+ while (buffer_pos != 0) {
+ if (get_packet (iface, (unsigned char *) &message, buffer,
+ &buffer_len, &buffer_pos) < 0)
+ break;
+
+ if (xid != message.xid) {
+ logger (LOG_ERR,
+ "ignoring packet with xid 0x%x as it's not ours (0x%x)",
+ message.xid, xid);
+ continue;
+ }
+
+ logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid);
+ memset (new_dhcp, 0, sizeof (dhcp_t));
+ if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0) {
+ logger (LOG_ERR, "failed to parse packet");
+ free_dhcp (new_dhcp);
+ continue;
+ }
+
+ /* If we got here then the DHCP packet is valid and appears to
+ be for us, so let's clear the buffer as we don't care about
+ any more DHCP packets at this point. */
+ valid = 1;
+ break;
+ }
+
+ /* No packets for us, so wait until we get one */
+ if (! valid) {
+ free (new_dhcp);
+ continue;
+ }
+
+ /* new_dhcp is now our master DHCP message */
+ free_dhcp (dhcp);
+ free (dhcp);
+ dhcp = new_dhcp;
+ new_dhcp = NULL;
+
+ /* 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;
+ DROP_CONFIG;
+ continue;
+ }
+
+ switch (state) {
+ case STATE_INIT:
+ if (type == DHCP_OFFER) {
+ char *addr = strdup (inet_ntoa (dhcp->address));
+ if (dhcp->servername[0])
+ logger (LOG_INFO, "offered %s from %s `%s'",
+ addr, inet_ntoa (dhcp->serveraddress),
+ dhcp->servername);
+ else
+ logger (LOG_INFO, "offered %s from %s",
+ addr, inet_ntoa (dhcp->serveraddress));
+ free (addr);
+
+ SEND_MESSAGE (DHCP_REQUEST);
+ state = STATE_REQUESTING;
+ }
+ break;
+
+ case STATE_RENEW_REQUESTED:
+ case STATE_REQUESTING:
+ case STATE_RENEWING:
+ case STATE_REBINDING:
+ if (type == DHCP_ACK) {
+ SOCKET_MODE (SOCKET_CLOSED);
+ if (options->doarp && iface->previous_address.s_addr !=
+ dhcp->address.s_addr)
+ {
+ if (arp_check (iface, dhcp->address)) {
+ SOCKET_MODE (SOCKET_OPEN);
+ SEND_MESSAGE (DHCP_DECLINE);
+ SOCKET_MODE (SOCKET_CLOSED);
+ DROP_CONFIG;
+
+ xid = 0;
+ timeout = 0;
+ state = STATE_INIT;
+ /* RFC 2131 says that we should wait for 10 seconds
+ before doing anything else */
+ logger (LOG_INFO, "sleeping for 10 seconds");
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ select (0, NULL, NULL, NULL, &tv);
+ continue;
+ }
+ }
+
+ if (dhcp->leasetime == (unsigned) -1) {
+ dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime;
+ timeout = 1; /* So we select on infinity */
+ logger (LOG_INFO, "leased %s for infinity",
+ inet_ntoa (dhcp->address));
+ } else {
+ if (! dhcp->leasetime) {
+ dhcp->leasetime = DEFAULT_LEASETIME;
+ logger(LOG_INFO,
+ "no lease time supplied, assuming %d seconds",
+ dhcp->leasetime);
+ }
+ logger (LOG_INFO, "leased %s for %u seconds",
+ inet_ntoa (dhcp->address), dhcp->leasetime);
+
+ if (dhcp->rebindtime >= dhcp->leasetime) {
+ dhcp->rebindtime = (dhcp->leasetime * 0.875);
+ logger (LOG_ERR, "rebind time greater than lease "
+ "time, forcing to %u seconds",
+ dhcp->rebindtime);
+ }
+
+ if (dhcp->renewaltime > dhcp->rebindtime) {
+ dhcp->renewaltime = (dhcp->leasetime * 0.5);
+ logger (LOG_ERR, "renewal time greater than rebind time, "
+ "forcing to %u seconds",
+ dhcp->renewaltime);
+ }
+
+ if (! dhcp->renewaltime) {
+ dhcp->renewaltime = (dhcp->leasetime * 0.5);
+ logger (LOG_INFO,
+ "no renewal time supplied, assuming %d seconds",
+ dhcp->renewaltime);
+ } else
+ logger (LOG_DEBUG, "renew in %u seconds",
+ dhcp->renewaltime);
+
+ if (! dhcp->rebindtime) {
+ dhcp->rebindtime = (dhcp->leasetime * 0.875);
+ logger (LOG_INFO,
+ "no rebind time supplied, assuming %d seconds",
+ dhcp->rebindtime);
+ } else
+ logger (LOG_DEBUG, "rebind in %u seconds",
+ dhcp->rebindtime);
+
+ timeout = dhcp->renewaltime;
+ }
+
+ state = STATE_BOUND;
+ xid = 0;
+
+ if (configure (options, iface, dhcp) < 0 && ! daemonised) {
+ retval = -1;
+ goto eexit;
+ }
+
+ if (! daemonised && options->daemonise) {
+ if ((daemonise (options->pidfile)) < 0 ) {
+ retval = -1;
+ goto eexit;
+ }
+ daemonised = true;
+ }
+ } else if (type == DHCP_OFFER)
+ logger (LOG_INFO, "got subsequent offer of %s, ignoring ",
+ inet_ntoa (dhcp->address));
+ else
+ logger (LOG_ERR,
+ "no idea what to do with DHCP type %d at this point",
+ type);
+ break;
+ }
+ } else if (retval == -1 && errno == EINTR) {
+ /* The interupt will be handled above */
+ } else {
+ /* An error occured. As we heavily depend on select, we abort. */
+ logger (LOG_ERR, "error on select: %s", strerror (errno));
+ retval = -1;
+ goto eexit;
+ }
+ }
eexit:
- SOCKET_MODE (SOCKET_CLOSED);
- DROP_CONFIG;
- free (dhcp);
+ SOCKET_MODE (SOCKET_CLOSED);
+ DROP_CONFIG;
+ free (dhcp);
- if (iface)
- {
- if (iface->previous_routes)
- free_route (iface->previous_routes);
- free (iface);
- }
+ if (iface) {
+ if (iface->previous_routes)
+ free_route (iface->previous_routes);
+ free (iface);
+ }
- if (buffer)
- free (buffer);
+ if (buffer)
+ free (buffer);
- logger (LOG_INFO, "exiting");
+ logger (LOG_INFO, "exiting");
- /* Unlink our pidfile */
- unlink (options->pidfile);
+ /* Unlink our pidfile */
+ unlink (options->pidfile);
- return retval;
+ return retval;
}
# if ! defined(__UCLIBC__) && ! defined (__dietlibc__)
size_t strlcpy (char *dst, const char *src, size_t size)
{
- const char *s = src;
- size_t n = size;
-
- if (n && --n)
- do
- {
- if (! (*dst++ = *src++))
- break;
- }
- while (--n);
-
- if (! n)
- {
- if (size)
- *dst = '\0';
- while (*src++)
- ;
- }
-
- return (src - s - 1);
+ const char *s = src;
+ size_t n = size;
+
+ if (n && --n)
+ do {
+ if (! (*dst++ = *src++))
+ break;
+ } while (--n);
+
+ if (! n) {
+ if (size)
+ *dst = '\0';
+ while (*src++)
+ ;
+ }
+
+ return (src - s - 1);
}
#endif
#endif
#include <sys/sysinfo.h>
long uptime (void)
{
- struct sysinfo info;
+ struct sysinfo info;
- sysinfo (&info);
- return info.uptime;
+ sysinfo (&info);
+ return info.uptime;
}
#elif __APPLE__
/* Darwin doesn't appear to have an uptime, so try and make one ourselves */
#include <sys/time.h>
long uptime (void)
{
- struct timeval tv;
- static long start = 0;
+ struct timeval tv;
+ static long start = 0;
- if (gettimeofday (&tv, NULL) == -1)
- {
- logger (LOG_ERR, "gettimeofday: %s", strerror (errno));
- return -1;
- }
+ if (gettimeofday (&tv, NULL) == -1) {
+ logger (LOG_ERR, "gettimeofday: %s", strerror (errno));
+ return -1;
+ }
- if (start == 0)
- start = tv.tv_sec;
+ if (start == 0)
+ start = tv.tv_sec;
- return tv.tv_sec - start;
+ return tv.tv_sec - start;
}
#else
#include <time.h>
long uptime (void)
{
- struct timespec tp;
+ struct timespec tp;
- if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1)
- {
- logger (LOG_ERR, "clock_gettime: %s", strerror (errno));
- return -1;
- }
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
+ logger (LOG_ERR, "clock_gettime: %s", strerror (errno));
+ return -1;
+ }
- return tp.tv_sec;
+ return tp.tv_sec;
}
#endif
void *xmalloc (size_t size)
{
- void *value = malloc (size);
+ void *value = malloc (size);
- if (value)
- return value;
+ if (value)
+ return value;
- logger (LOG_ERR, "memory exhausted");
- exit (1);
+ logger (LOG_ERR, "memory exhausted");
+ exit (1);
}
/* IMPORTANT: Ensure that the last parameter is NULL when calling */
static int exec_cmd (const char *cmd, const char *args, ...)
{
- va_list va;
- pid_t pid;
- char **argv;
- int n = 1;
-
- va_start (va, args);
- while (va_arg (va, char *) != NULL)
- n++;
- va_end (va);
- argv = alloca ((n + 1) * sizeof (*argv));
- if (argv == NULL)
- {
- errno = ENOMEM;
- return -1;
- }
-
- va_start (va, args);
- n = 2;
- argv[0] = (char *) cmd;
- argv[1] = (char *) args;
- while ((argv[n] = va_arg (va, char *)) != NULL)
- n++;
- va_end (va);
-
- if ((pid = fork ()) == 0)
- {
- if (execv (cmd, argv) && errno != ENOENT)
- logger (LOG_ERR, "error executing \"%s\": %s",
- cmd, strerror (errno));
- exit (0);
- }
- else if (pid == -1)
- logger (LOG_ERR, "fork: %s", strerror (errno));
-
- return 0;
+ va_list va;
+ pid_t pid;
+ char **argv;
+ int n = 1;
+
+ va_start (va, args);
+ while (va_arg (va, char *) != NULL)
+ n++;
+ va_end (va);
+ argv = alloca ((n + 1) * sizeof (*argv));
+ if (argv == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ va_start (va, args);
+ n = 2;
+ argv[0] = (char *) cmd;
+ argv[1] = (char *) args;
+ while ((argv[n] = va_arg (va, char *)) != NULL)
+ n++;
+ va_end (va);
+
+ if ((pid = fork ()) == 0) {
+ if (execv (cmd, argv) && errno != ENOENT)
+ logger (LOG_ERR, "error executing \"%s\": %s",
+ cmd, strerror (errno));
+ exit (0);
+ } else if (pid == -1)
+ logger (LOG_ERR, "fork: %s", strerror (errno));
+
+ return 0;
}
static void exec_script (const char *script, const char *infofile,
- const char *arg)
+ const char *arg)
{
- struct stat buf;
+ struct stat buf;
#ifdef ENABLE_INFO
- if (! script || ! infofile || ! arg)
- return;
+ if (! script || ! infofile || ! arg)
+ return;
#else
- if (! script || ! arg)
- return ;
+ if (! script || ! arg)
+ return ;
#endif
- if (stat (script, &buf) < 0)
- {
- if (strcmp (script, DEFAULT_SCRIPT) != 0)
- logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT));
- return;
- }
+ if (stat (script, &buf) < 0) {
+ if (strcmp (script, DEFAULT_SCRIPT) != 0)
+ logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT));
+ return;
+ }
#ifdef ENABLE_INFO
- logger (LOG_DEBUG, "exec \"%s %s %s\"", script, infofile, arg);
- exec_cmd (script, infofile, arg, (char *) NULL);
+ logger (LOG_DEBUG, "exec \"%s %s %s\"", script, infofile, arg);
+ exec_cmd (script, infofile, arg, (char *) NULL);
#else
- logger (LOG_DEBUG, "exec \"%s \"\" %s\"", script, infofile, arg);
- exec_cmd (script, infofile, "", arg, (char *) NULL);
+ logger (LOG_DEBUG, "exec \"%s \"\" %s\"", script, infofile, arg);
+ exec_cmd (script, infofile, "", arg, (char *) NULL);
#endif
}
static int make_resolv (const char *ifname, const dhcp_t *dhcp)
{
- FILE *f;
- struct stat buf;
- char resolvconf[PATH_MAX] = {0};
- address_t *address;
+ FILE *f;
+ struct stat buf;
+ char resolvconf[PATH_MAX] = {0};
+ address_t *address;
#ifdef RESOLVCONF
- if (stat (RESOLVCONF, &buf) == 0)
- {
- logger (LOG_DEBUG, "sending DNS information to resolvconf");
- snprintf (resolvconf, PATH_MAX, RESOLVCONF" -a %s", ifname);
- f = popen (resolvconf, "w");
-
- if (! f)
- logger (LOG_ERR, "popen: %s", strerror (errno));
- }
- else
+ if (stat (RESOLVCONF, &buf) == 0) {
+ logger (LOG_DEBUG, "sending DNS information to resolvconf");
+ snprintf (resolvconf, PATH_MAX, RESOLVCONF" -a %s", ifname);
+ f = popen (resolvconf, "w");
+
+ if (! f)
+ logger (LOG_ERR, "popen: %s", strerror (errno));
+ } else
#endif
- {
- logger (LOG_DEBUG, "writing "RESOLVFILE);
- if (! (f = fopen(RESOLVFILE, "w")))
- logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno));
- }
-
- if (f)
- {
- fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
- if (dhcp->dnssearch)
- fprintf (f, "search %s\n", dhcp->dnssearch);
- else if (dhcp->dnsdomain) {
- fprintf (f, "search %s\n", dhcp->dnsdomain);
- }
-
- for (address = dhcp->dnsservers; address; address = address->next)
- fprintf (f, "nameserver %s\n", inet_ntoa (address->address));
-
- if (*resolvconf)
- pclose (f);
- else
- fclose (f);
- }
- else
- return -1;
-
- /* Refresh the local resolver */
- res_init ();
- return 0;
+ {
+ logger (LOG_DEBUG, "writing "RESOLVFILE);
+ if (! (f = fopen(RESOLVFILE, "w")))
+ logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno));
+ }
+
+ if (f) {
+ fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
+ if (dhcp->dnssearch)
+ fprintf (f, "search %s\n", dhcp->dnssearch);
+ else if (dhcp->dnsdomain) {
+ fprintf (f, "search %s\n", dhcp->dnsdomain);
+ }
+
+ for (address = dhcp->dnsservers; address; address = address->next)
+ fprintf (f, "nameserver %s\n", inet_ntoa (address->address));
+
+ if (*resolvconf)
+ pclose (f);
+ else
+ fclose (f);
+ } else
+ return -1;
+
+ /* Refresh the local resolver */
+ res_init ();
+ return 0;
}
static void restore_resolv(const char *ifname)
{
#ifdef RESOLVCONF
- struct stat buf;
+ struct stat buf;
- if (stat (RESOLVCONF, &buf) < 0)
- return;
+ if (stat (RESOLVCONF, &buf) < 0)
+ return;
- logger (LOG_DEBUG, "removing information from resolvconf");
- exec_cmd (RESOLVCONF, "-d", ifname, (char *) NULL);
+ logger (LOG_DEBUG, "removing information from resolvconf");
+ exec_cmd (RESOLVCONF, "-d", ifname, (char *) NULL);
#endif
}
#ifdef ENABLE_NTP
static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp)
{
- FILE *f;
- address_t *address;
- char *a;
- char buffer[1024];
- int tomatch = 0;
- char *token;
- bool ntp = false;
-
- for (address = dhcp->ntpservers; address; address = address->next)
- tomatch++;
-
- /* Check that we really need to update the servers
- We do this because ntp has to be restarted to work with a changed config */
- if (! (f = fopen (file, "r")))
- {
- if (errno != ENOENT)
- {
- logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
- return -1;
- }
- }
- else
- {
- memset (buffer, 0, sizeof (buffer));
- while (fgets (buffer, sizeof (buffer), f))
- {
- a = buffer;
- token = strsep (&a, " ");
- if (! token || strcmp (token, "server") != 0)
- continue;
-
- if ((token = strsep (&a, " \n")) == NULL)
- continue;
-
- for (address = dhcp->ntpservers; address; address = address->next)
- if (strcmp (token, inet_ntoa (address->address)) == 0)
- {
- tomatch--;
- break;
- }
-
- if (tomatch == 0)
- break;
- }
- fclose (f);
-
- /* File has the same name servers that we do, so no need to restart ntp */
- if (tomatch == 0)
- {
- logger (LOG_DEBUG, "%s already configured, skipping", file);
- return 0;
- }
- }
-
- logger (LOG_DEBUG, "writing %s", file);
- if (! (f = fopen (file, "w")))
- {
- logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
- return -1;
- }
-
- fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
+ FILE *f;
+ address_t *address;
+ char *a;
+ char buffer[1024];
+ int tomatch = 0;
+ char *token;
+ bool ntp = false;
+
+ for (address = dhcp->ntpservers; address; address = address->next)
+ tomatch++;
+
+ /* Check that we really need to update the servers
+ We do this because ntp has to be restarted to work with a changed config */
+ if (! (f = fopen (file, "r"))) {
+ if (errno != ENOENT) {
+ logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
+ return -1;
+ }
+ } else {
+ memset (buffer, 0, sizeof (buffer));
+ while (fgets (buffer, sizeof (buffer), f)) {
+ a = buffer;
+ token = strsep (&a, " ");
+ if (! token || strcmp (token, "server") != 0)
+ continue;
+
+ if ((token = strsep (&a, " \n")) == NULL)
+ continue;
+
+ for (address = dhcp->ntpservers; address; address = address->next)
+ if (strcmp (token, inet_ntoa (address->address)) == 0) {
+ tomatch--;
+ break;
+ }
+
+ if (tomatch == 0)
+ break;
+ }
+ fclose (f);
+
+ /* File has the same name servers that we do, so no need to restart ntp */
+ if (tomatch == 0) {
+ logger (LOG_DEBUG, "%s already configured, skipping", file);
+ return 0;
+ }
+ }
+
+ logger (LOG_DEBUG, "writing %s", file);
+ if (! (f = fopen (file, "w"))) {
+ logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
+ return -1;
+ }
+
+ fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
#ifdef NTPFILE
- if (strcmp (file, NTPFILE) == 0)
- {
- ntp = true;
- fprintf (f, "restrict default noquery notrust nomodify\n");
- fprintf (f, "restrict 127.0.0.1\n");
- }
+ if (strcmp (file, NTPFILE) == 0) {
+ ntp = true;
+ fprintf (f, "restrict default noquery notrust nomodify\n");
+ fprintf (f, "restrict 127.0.0.1\n");
+ }
#endif
- for (address = dhcp->ntpservers; address; address = address->next)
- {
- a = inet_ntoa (address->address);
- if (ntp)
- fprintf (f, "restrict %s nomodify notrap noquery\n", a);
- fprintf (f, "server %s\n", a);
- }
-
- if (ntp)
- {
- fprintf (f, "driftfile " NTPDRIFTFILE "\n");
- fprintf (f, "logfile " NTPLOGFILE "\n");
- }
- fclose (f);
-
- return 1;
+ for (address = dhcp->ntpservers; address; address = address->next) {
+ a = inet_ntoa (address->address);
+ if (ntp)
+ fprintf (f, "restrict %s nomodify notrap noquery\n", a);
+ fprintf (f, "server %s\n", a);
+ }
+
+ if (ntp) {
+ fprintf (f, "driftfile " NTPDRIFTFILE "\n");
+ fprintf (f, "logfile " NTPLOGFILE "\n");
+ }
+ fclose (f);
+
+ return 1;
}
static int make_ntp (const char *ifname, const dhcp_t *dhcp)
{
- /* On some systems we have only have one ntp service, but we don't know
- which configuration file we're using. So we need to write to both and
- restart accordingly. */
+ /* On some systems we have only have one ntp service, but we don't know
+ which configuration file we're using. So we need to write to both and
+ restart accordingly. */
- bool restart_ntp = false;
- bool restart_openntp = false;
- int retval = 0;
+ bool restart_ntp = false;
+ bool restart_openntp = false;
+ int retval = 0;
#ifdef NTPFILE
- if (_make_ntp (NTPFILE, ifname, dhcp) > 0)
- restart_ntp = true;
+ if (_make_ntp (NTPFILE, ifname, dhcp) > 0)
+ restart_ntp = true;
#endif
#ifdef OPENNTPFILE
- if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0)
- restart_openntp = true;
+ if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0)
+ restart_openntp = true;
#endif
#ifdef NTPSERVICE
- if (restart_ntp)
- retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, (char *) NULL);
+ if (restart_ntp)
+ retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, (char *) NULL);
#endif
#if defined (NTPSERVICE) && defined (OPENNTPSERVICE)
- if (restart_openntp &&
- (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp))
- retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL);
+ if (restart_openntp &&
+ (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp))
+ retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL);
#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE)
- if (restart_openntp)
- retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL);
+ if (restart_openntp)
+ retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL);
#endif
- return retval;
+ return retval;
}
#endif
#ifdef ENABLE_NIS
static int make_nis (const char *ifname, const dhcp_t *dhcp)
{
- FILE *f;
- address_t *address;
- char prefix[256] = {0};
-
- logger (LOG_DEBUG, "writing "NISFILE);
- if (! (f = fopen(NISFILE, "w")))
- {
- logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno));
- return -1;
- }
-
- fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
- if (dhcp->nisdomain)
- {
- setdomainname (dhcp->nisdomain, strlen (dhcp->nisdomain));
-
- if (dhcp->nisservers)
- snprintf (prefix, sizeof (prefix), "domain %s server", dhcp->nisdomain);
- else
- fprintf (f, "domain %s broadcast\n", dhcp->nisdomain);
- }
- else
- snprintf (prefix, sizeof (prefix), "%s", "ypserver");
-
- for (address = dhcp->nisservers; address; address = address->next)
- fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address));
-
- fclose (f);
-
- exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL);
- return 0;
+ FILE *f;
+ address_t *address;
+ char prefix[256] = {0};
+
+ logger (LOG_DEBUG, "writing "NISFILE);
+ if (! (f = fopen(NISFILE, "w"))) {
+ logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno));
+ return -1;
+ }
+
+ fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
+ if (dhcp->nisdomain) {
+ setdomainname (dhcp->nisdomain, strlen (dhcp->nisdomain));
+
+ if (dhcp->nisservers)
+ snprintf (prefix, sizeof (prefix), "domain %s server", dhcp->nisdomain);
+ else
+ fprintf (f, "domain %s broadcast\n", dhcp->nisdomain);
+ }
+ else
+ snprintf (prefix, sizeof (prefix), "%s", "ypserver");
+
+ for (address = dhcp->nisservers; address; address = address->next)
+ fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address));
+
+ fclose (f);
+
+ exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL);
+ return 0;
}
#endif
#ifdef ENABLE_INFO
static char *cleanmetas (const char *cstr)
{
- /* The largest single element we can have is 256 bytes according to the RFC,
- so this buffer size should be safe even if it's all ' */
- static char buffer[1024];
- char *b = buffer;
-
- memset (buffer, 0, sizeof (buffer));
- if (cstr == NULL || strlen (cstr) == 0)
- return b;
-
- do
- if (*cstr == 39)
- {
- *b++ = '\'';
- *b++ = '\\';
- *b++ = '\'';
- *b++ = '\'';
- }
- else
- *b++ = *cstr;
- while (*cstr++);
-
- *b++ = 0;
- b = buffer;
-
- return b;
+ /* The largest single element we can have is 256 bytes according to the RFC,
+ so this buffer size should be safe even if it's all ' */
+ static char buffer[1024];
+ char *b = buffer;
+
+ memset (buffer, 0, sizeof (buffer));
+ if (cstr == NULL || strlen (cstr) == 0)
+ return b;
+
+ do
+ if (*cstr == 39) {
+ *b++ = '\'';
+ *b++ = '\\';
+ *b++ = '\'';
+ *b++ = '\'';
+ } else
+ *b++ = *cstr;
+ while (*cstr++);
+
+ *b++ = 0;
+ b = buffer;
+
+ return b;
}
static int write_info(const interface_t *iface, const dhcp_t *dhcp,
- const options_t *options)
+ const options_t *options)
{
- FILE *f;
- route_t *route;
- address_t *address;
-
- logger (LOG_DEBUG, "writing %s", iface->infofile);
- if ((f = fopen (iface->infofile, "w")) == NULL)
- {
- logger (LOG_ERR, "fopen `%s': %s", iface->infofile, strerror (errno));
- 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));
- if (dhcp->mtu > 0)
- fprintf (f, "MTU='%d'\n", dhcp->mtu);
-
- if (dhcp->routes)
- {
- fprintf (f, "ROUTES='");
- for (route = dhcp->routes; route; route = route->next)
- {
- fprintf (f, "%s", inet_ntoa (route->destination));
- fprintf (f, ",%s", inet_ntoa (route->netmask));
- fprintf (f, ",%s", inet_ntoa (route->gateway));
- if (route->next)
- fprintf (f, " ");
- }
- fprintf (f, "'\n");
- }
-
- if (dhcp->hostname)
- fprintf (f, "HOSTNAME='%s'\n", cleanmetas (dhcp->hostname));
-
- if (dhcp->dnsdomain)
- fprintf (f, "DNSDOMAIN='%s'\n", cleanmetas (dhcp->dnsdomain));
-
- if (dhcp->dnssearch)
- fprintf (f, "DNSSEARCH='%s'\n", cleanmetas (dhcp->dnssearch));
-
- if (dhcp->dnsservers)
- {
- fprintf (f, "DNSSERVERS='");
- for (address = dhcp->dnsservers; address; address = address->next)
- {
- fprintf (f, "%s", inet_ntoa (address->address));
- if (address->next)
- fprintf (f, " ");
- }
- fprintf (f, "'\n");
- }
-
- 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, "FQDNHOSTNAME='%s'\n", dhcp->fqdn->name);
- }
-
- if (dhcp->ntpservers)
- {
- fprintf (f, "NTPSERVERS='");
- for (address = dhcp->ntpservers; address; address = address->next)
- {
- fprintf (f, "%s", inet_ntoa (address->address));
- if (address->next)
- fprintf (f, " ");
- }
- fprintf (f, "'\n");
- }
-
- if (dhcp->nisdomain)
- fprintf (f, "NISDOMAIN='%s'\n", cleanmetas (dhcp->nisdomain));
-
- if (dhcp->nisservers)
- {
- fprintf (f, "NISSERVERS='");
- for (address = dhcp->nisservers; address; address = address->next)
- {
- fprintf (f, "%s", inet_ntoa (address->address));
- if (address->next)
- fprintf (f, " ");
- }
- fprintf (f, "'\n");
- }
-
- if (dhcp->rootpath)
- fprintf (f, "ROOTPATH='%s'\n", cleanmetas (dhcp->rootpath));
-
- fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress));
- 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, "INTERFACE='%s'\n", iface->name);
- fprintf (f, "CLASSID='%s'\n", cleanmetas (options->classid));
- if (options->clientid[0])
- fprintf (f, "CLIENTID='%s'\n", cleanmetas (options->clientid));
- else
- fprintf (f, "CLIENTID='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen));
- fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen));
- fclose (f);
- return 0;
+ FILE *f;
+ route_t *route;
+ address_t *address;
+
+ logger (LOG_DEBUG, "writing %s", iface->infofile);
+ if ((f = fopen (iface->infofile, "w")) == NULL) {
+ logger (LOG_ERR, "fopen `%s': %s", iface->infofile, strerror (errno));
+ 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));
+ if (dhcp->mtu > 0)
+ fprintf (f, "MTU='%d'\n", dhcp->mtu);
+
+ if (dhcp->routes) {
+ fprintf (f, "ROUTES='");
+ for (route = dhcp->routes; route; route = route->next) {
+ fprintf (f, "%s", inet_ntoa (route->destination));
+ fprintf (f, ",%s", inet_ntoa (route->netmask));
+ fprintf (f, ",%s", inet_ntoa (route->gateway));
+ if (route->next)
+ fprintf (f, " ");
+ }
+ fprintf (f, "'\n");
+ }
+
+ if (dhcp->hostname)
+ fprintf (f, "HOSTNAME='%s'\n", cleanmetas (dhcp->hostname));
+
+ if (dhcp->dnsdomain)
+ fprintf (f, "DNSDOMAIN='%s'\n", cleanmetas (dhcp->dnsdomain));
+
+ if (dhcp->dnssearch)
+ fprintf (f, "DNSSEARCH='%s'\n", cleanmetas (dhcp->dnssearch));
+
+ if (dhcp->dnsservers) {
+ fprintf (f, "DNSSERVERS='");
+ for (address = dhcp->dnsservers; address; address = address->next) {
+ fprintf (f, "%s", inet_ntoa (address->address));
+ if (address->next)
+ fprintf (f, " ");
+ }
+ fprintf (f, "'\n");
+ }
+
+ 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, "FQDNHOSTNAME='%s'\n", dhcp->fqdn->name);
+ }
+
+ if (dhcp->ntpservers) {
+ fprintf (f, "NTPSERVERS='");
+ for (address = dhcp->ntpservers; address; address = address->next) {
+ fprintf (f, "%s", inet_ntoa (address->address));
+ if (address->next)
+ fprintf (f, " ");
+ }
+ fprintf (f, "'\n");
+ }
+
+ if (dhcp->nisdomain)
+ fprintf (f, "NISDOMAIN='%s'\n", cleanmetas (dhcp->nisdomain));
+
+ if (dhcp->nisservers) {
+ fprintf (f, "NISSERVERS='");
+ for (address = dhcp->nisservers; address; address = address->next) {
+ fprintf (f, "%s", inet_ntoa (address->address));
+ if (address->next)
+ fprintf (f, " ");
+ }
+ fprintf (f, "'\n");
+ }
+
+ if (dhcp->rootpath)
+ fprintf (f, "ROOTPATH='%s'\n", cleanmetas (dhcp->rootpath));
+
+ fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress));
+ 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, "INTERFACE='%s'\n", iface->name);
+ fprintf (f, "CLASSID='%s'\n", cleanmetas (options->classid));
+ if (options->clientid[0])
+ fprintf (f, "CLIENTID='%s'\n", cleanmetas (options->clientid));
+ else
+ fprintf (f, "CLIENTID='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen));
+ fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen));
+ fclose (f);
+ return 0;
}
#endif
int configure (const options_t *options, interface_t *iface,
- const dhcp_t *dhcp)
+ const dhcp_t *dhcp)
{
- route_t *route = NULL;
- route_t *new_route = NULL;
- route_t *old_route = NULL;
- struct hostent *he = NULL;
- char newhostname[HOSTNAME_MAX_LEN] = {0};
- char curhostname[HOSTNAME_MAX_LEN] = {0};
- char *dname = NULL;
- int dnamel = 0;
-
- if (! options || ! iface || ! dhcp)
- return -1;
-
- /* Remove old routes
- Always do this as the interface may have >1 address not added by us
- so the routes we added may still exist */
- if (iface->previous_routes)
- {
- for (route = iface->previous_routes; route; route = route->next)
- if (route->destination.s_addr || options->dogateway)
- {
- int have = 0;
- if (dhcp->address.s_addr != 0)
- for (new_route = dhcp->routes; new_route; new_route = new_route->next)
- if (new_route->destination.s_addr == route->destination.s_addr
- && new_route->netmask.s_addr == route->netmask.s_addr
- && new_route->gateway.s_addr == route->gateway.s_addr)
- {
- have = 1;
- break;
- }
- if (! have)
- del_route (iface->name, route->destination, route->netmask,
- route->gateway, options->metric);
- }
- }
-
- /* If we don't have an address, then return */
- if (dhcp->address.s_addr == 0)
- {
- if (iface->previous_routes)
- {
- free_route (iface->previous_routes);
- iface->previous_routes = NULL;
- }
-
- /* Restore the original MTU value */
- if (iface->mtu && iface->previous_mtu != iface->mtu)
- {
- set_mtu (iface->name, iface->mtu);
- iface->previous_mtu = iface->mtu;
- }
-
- /* Only reset things if we had set them before */
- if (iface->previous_address.s_addr != 0)
- {
- del_address (iface->name, iface->previous_address,
- iface->previous_netmask);
- memset (&iface->previous_address, 0, sizeof (struct in_addr));
- memset (&iface->previous_netmask, 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");
- }
- return 0;
- }
-
- /* Set the MTU requested.
- If the DHCP server no longer sends one OR it's invalid then we restore
- the original MTU */
- if (options->domtu)
- {
- unsigned short mtu = iface->mtu;
- if (dhcp->mtu)
- mtu = dhcp->mtu;
-
- if (mtu != iface->previous_mtu)
- {
- if (set_mtu (iface->name, mtu) == 0)
- iface->previous_mtu = mtu;
- }
- }
-
- if (add_address (iface->name, dhcp->address, dhcp->netmask,
- dhcp->broadcast) < 0 && errno != EEXIST)
- return -1;
-
- /* Now delete the old address if different */
- if (iface->previous_address.s_addr != dhcp->address.s_addr
- && iface->previous_address.s_addr != 0)
- del_address (iface->name, iface->previous_address, iface->previous_netmask);
+ route_t *route = NULL;
+ route_t *new_route = NULL;
+ route_t *old_route = NULL;
+ struct hostent *he = NULL;
+ char newhostname[HOSTNAME_MAX_LEN] = {0};
+ char curhostname[HOSTNAME_MAX_LEN] = {0};
+ char *dname = NULL;
+ int dnamel = 0;
+
+ if (! options || ! iface || ! dhcp)
+ return -1;
+
+ /* Remove old routes
+ Always do this as the interface may have >1 address not added by us
+ so the routes we added may still exist */
+ if (iface->previous_routes) {
+ for (route = iface->previous_routes; route; route = route->next)
+ if (route->destination.s_addr || options->dogateway) {
+ int have = 0;
+ if (dhcp->address.s_addr != 0)
+ for (new_route = dhcp->routes; new_route; new_route = new_route->next)
+ if (new_route->destination.s_addr == route->destination.s_addr
+ && new_route->netmask.s_addr == route->netmask.s_addr
+ && new_route->gateway.s_addr == route->gateway.s_addr)
+ {
+ have = 1;
+ break;
+ }
+ if (! have)
+ del_route (iface->name, route->destination, route->netmask,
+ route->gateway, options->metric);
+ }
+ }
+
+ /* If we don't have an address, then return */
+ if (dhcp->address.s_addr == 0) {
+ if (iface->previous_routes) {
+ free_route (iface->previous_routes);
+ iface->previous_routes = NULL;
+ }
+
+ /* Restore the original MTU value */
+ if (iface->mtu && iface->previous_mtu != iface->mtu) {
+ set_mtu (iface->name, iface->mtu);
+ iface->previous_mtu = iface->mtu;
+ }
+
+ /* Only reset things if we had set them before */
+ if (iface->previous_address.s_addr != 0) {
+ del_address (iface->name, iface->previous_address,
+ iface->previous_netmask);
+ memset (&iface->previous_address, 0, sizeof (struct in_addr));
+ memset (&iface->previous_netmask, 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");
+ }
+ return 0;
+ }
+
+ /* Set the MTU requested.
+ If the DHCP server no longer sends one OR it's invalid then we restore
+ the original MTU */
+ if (options->domtu) {
+ unsigned short mtu = iface->mtu;
+ if (dhcp->mtu)
+ mtu = dhcp->mtu;
+
+ if (mtu != iface->previous_mtu) {
+ if (set_mtu (iface->name, mtu) == 0)
+ iface->previous_mtu = mtu;
+ }
+ }
+
+ if (add_address (iface->name, dhcp->address, dhcp->netmask,
+ dhcp->broadcast) < 0 && errno != EEXIST)
+ return -1;
+
+ /* Now delete the old address if different */
+ if (iface->previous_address.s_addr != dhcp->address.s_addr
+ && iface->previous_address.s_addr != 0)
+ del_address (iface->name, iface->previous_address, iface->previous_netmask);
#ifdef __linux__
- /* On linux, we need to change the subnet route to have our metric. */
- if (iface->previous_address.s_addr != dhcp->address.s_addr
- && options->metric > 0 && dhcp->netmask.s_addr != INADDR_BROADCAST)
- {
- struct in_addr td;
- struct in_addr tg;
- memset (&td, 0, sizeof (td));
- memset (&tg, 0, sizeof (tg));
- td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
- add_route (iface->name, td, dhcp->netmask, tg, options->metric);
- del_route (iface->name, td, dhcp->netmask, tg, 0);
- }
+ /* On linux, we need to change the subnet route to have our metric. */
+ if (iface->previous_address.s_addr != dhcp->address.s_addr
+ && options->metric > 0 && dhcp->netmask.s_addr != INADDR_BROADCAST)
+ {
+ struct in_addr td;
+ struct in_addr tg;
+ memset (&td, 0, sizeof (td));
+ memset (&tg, 0, sizeof (tg));
+ td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
+ add_route (iface->name, td, dhcp->netmask, tg, options->metric);
+ del_route (iface->name, td, dhcp->netmask, tg, 0);
+ }
#endif
- /* Remember added routes */
- if (dhcp->routes)
- {
- route_t *new_routes = NULL;
- int remember;
-
- 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;
-
- remember = add_route (iface->name, route->destination,
- route->netmask, route->gateway,
- options->metric);
- /* If we failed to add the route, we may have already added it
- ourselves. If so, remember it again. */
- if (remember < 0)
- for (old_route = iface->previous_routes; old_route;
- old_route = old_route->next)
- if (old_route->destination.s_addr == route->destination.s_addr
- && old_route->netmask.s_addr == route->netmask.s_addr
- && old_route->gateway.s_addr == route->gateway.s_addr)
- {
- remember = 1;
- break;
- }
-
- if (remember >= 0)
- {
- if (! new_routes)
- {
- new_routes = xmalloc (sizeof (route_t));
- memset (new_routes, 0, sizeof (route_t));
- new_route = new_routes;
- }
- else
- {
- new_route->next = xmalloc (sizeof (route_t));
- new_route = new_route->next;
- }
- memcpy (new_route, route, sizeof (route_t));
- new_route -> next = NULL;
- }
- }
-
- if (iface->previous_routes)
- free_route (iface->previous_routes);
-
- iface->previous_routes = new_routes;
- }
-
- if (options->dodns && dhcp->dnsservers)
- make_resolv(iface->name, dhcp);
- else
- logger (LOG_DEBUG, "no dns information to write");
+ /* Remember added routes */
+ if (dhcp->routes) {
+ route_t *new_routes = NULL;
+ int remember;
+
+ 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;
+
+ remember = add_route (iface->name, route->destination,
+ route->netmask, route->gateway,
+ options->metric);
+ /* If we failed to add the route, we may have already added it
+ ourselves. If so, remember it again. */
+ if (remember < 0)
+ for (old_route = iface->previous_routes; old_route;
+ old_route = old_route->next)
+ if (old_route->destination.s_addr == route->destination.s_addr
+ && old_route->netmask.s_addr == route->netmask.s_addr
+ && old_route->gateway.s_addr == route->gateway.s_addr)
+ {
+ remember = 1;
+ break;
+ }
+
+ if (remember >= 0) {
+ if (! new_routes) {
+ new_routes = xmalloc (sizeof (route_t));
+ memset (new_routes, 0, sizeof (route_t));
+ new_route = new_routes;
+ } else {
+ new_route->next = xmalloc (sizeof (route_t));
+ new_route = new_route->next;
+ }
+ memcpy (new_route, route, sizeof (route_t));
+ new_route -> next = NULL;
+ }
+ }
+
+ if (iface->previous_routes)
+ free_route (iface->previous_routes);
+
+ iface->previous_routes = new_routes;
+ }
+
+ if (options->dodns && dhcp->dnsservers)
+ make_resolv(iface->name, dhcp);
+ else
+ logger (LOG_DEBUG, "no dns information to write");
#ifdef ENABLE_NTP
- if (options->dontp && dhcp->ntpservers)
- make_ntp(iface->name, dhcp);
+ if (options->dontp && dhcp->ntpservers)
+ make_ntp(iface->name, dhcp);
#endif
#ifdef ENABLE_NIS
- if (options->donis && (dhcp->nisservers || dhcp->nisdomain))
- make_nis(iface->name, dhcp);
+ if (options->donis && (dhcp->nisservers || dhcp->nisdomain))
+ make_nis(iface->name, dhcp);
#endif
- /* Now we have made a resolv.conf we can obtain a hostname if we need one */
- if (options->dohostname && ! dhcp->hostname)
- {
- he = gethostbyaddr (inet_ntoa (dhcp->address),
- sizeof (struct in_addr), AF_INET);
- if (he)
- {
- dname = he->h_name;
- while (*dname > 32)
- dname++;
- dnamel = dname - he->h_name;
- memcpy (newhostname, he->h_name, dnamel);
- newhostname[dnamel] = 0;
- }
- }
-
- gethostname (curhostname, sizeof (curhostname));
-
- if (options->dohostname
- || strlen (curhostname) == 0
- || strcmp (curhostname, "(none)") == 0
- || strcmp (curhostname, "localhost") == 0)
- {
- if (dhcp->hostname)
- strlcpy (newhostname, dhcp->hostname, sizeof (newhostname));
-
- if (*newhostname)
- {
- logger (LOG_INFO, "setting hostname to `%s'", newhostname);
- sethostname (newhostname, strlen (newhostname));
- }
- }
+ /* Now we have made a resolv.conf we can obtain a hostname if we need one */
+ if (options->dohostname && ! dhcp->hostname) {
+ he = gethostbyaddr (inet_ntoa (dhcp->address),
+ sizeof (struct in_addr), AF_INET);
+ if (he) {
+ dname = he->h_name;
+ while (*dname > 32)
+ dname++;
+ dnamel = dname - he->h_name;
+ memcpy (newhostname, he->h_name, dnamel);
+ newhostname[dnamel] = 0;
+ }
+ }
+
+ gethostname (curhostname, sizeof (curhostname));
+
+ if (options->dohostname
+ || strlen (curhostname) == 0
+ || strcmp (curhostname, "(none)") == 0
+ || strcmp (curhostname, "localhost") == 0)
+ {
+ if (dhcp->hostname)
+ strlcpy (newhostname, dhcp->hostname, sizeof (newhostname));
+
+ if (*newhostname) {
+ logger (LOG_INFO, "setting hostname to `%s'", newhostname);
+ sethostname (newhostname, strlen (newhostname));
+ }
+ }
#ifdef ENABLE_INFO
- write_info (iface, dhcp, options);
+ write_info (iface, dhcp, options);
#endif
- if (iface->previous_address.s_addr != dhcp->address.s_addr ||
- iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
- {
- memcpy (&iface->previous_address,
- &dhcp->address, sizeof (struct in_addr));
- memcpy (&iface->previous_netmask,
- &dhcp->netmask, sizeof (struct in_addr));
- exec_script (options->script, iface->infofile, "new");
- }
- else
- exec_script (options->script, iface->infofile, "up");
-
- return 0;
+ if (iface->previous_address.s_addr != dhcp->address.s_addr ||
+ iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
+ {
+ memcpy (&iface->previous_address,
+ &dhcp->address, sizeof (struct in_addr));
+ memcpy (&iface->previous_netmask,
+ &dhcp->netmask, sizeof (struct in_addr));
+ exec_script (options->script, iface->infofile, "new");
+ } else
+ exec_script (options->script, iface->infofile, "up");
+
+ return 0;
}
/* If you disable all 3 options you can shrink the binary by around 5-10k
unstripped depending on platform and CFLAGS
-*/
+ */
#define ENABLE_NTP
#define ENABLE_NIS
#define ENABLE_INFO
#include "dhcp.h"
int configure (const options_t *options, interface_t *iface,
- const dhcp_t *dhcp);
+ const dhcp_t *dhcp);
#endif
#define BROADCAST_FLAG 0x8000
static const char *dhcp_message[] = {
- [DHCP_DISCOVER] = "DHCP_DISCOVER",
- [DHCP_OFFER] = "DHCP_OFFER",
- [DHCP_REQUEST] = "DHCP_REQUEST",
- [DHCP_DECLINE] = "DHCP_DECLINE",
- [DHCP_ACK] = "DHCP_ACK",
- [DHCP_NAK] = "DHCP_NAK",
- [DHCP_RELEASE] = "DHCP_RELEASE",
- [DHCP_INFORM] = "DHCP_INFORM",
- [DHCP_INFORM + 1] = NULL
+ [DHCP_DISCOVER] = "DHCP_DISCOVER",
+ [DHCP_OFFER] = "DHCP_OFFER",
+ [DHCP_REQUEST] = "DHCP_REQUEST",
+ [DHCP_DECLINE] = "DHCP_DECLINE",
+ [DHCP_ACK] = "DHCP_ACK",
+ [DHCP_NAK] = "DHCP_NAK",
+ [DHCP_RELEASE] = "DHCP_RELEASE",
+ [DHCP_INFORM] = "DHCP_INFORM",
+ [DHCP_INFORM + 1] = NULL
};
size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
- unsigned long xid, char type,
- const options_t *options)
+ unsigned long xid, char type,
+ const options_t *options)
{
- dhcpmessage_t message;
- struct udp_dhcp_packet packet;
- unsigned char *m = (unsigned char *) &message;
- unsigned char *p = (unsigned char *) &message.options;
- unsigned char *n_params = NULL;
- unsigned long l;
- struct in_addr from;
- struct in_addr to;
- long up = uptime() - iface->start_uptime;
- uint32_t ul;
- uint16_t sz;
- unsigned int message_length;
-
- if (!iface || !options || !dhcp)
- return -1;
-
- memset (&from, 0, sizeof (from));
- memset (&to, 0, sizeof (to));
-
- if (type == DHCP_RELEASE)
- to.s_addr = dhcp->serveraddress.s_addr;
-
- memset (&message, 0, sizeof (dhcpmessage_t));
-
- if (type == DHCP_INFORM ||
- type == DHCP_RELEASE ||
- type == DHCP_REQUEST)
- {
- message.ciaddr = iface->previous_address.s_addr;
- from.s_addr = iface->previous_address.s_addr;
- }
-
- message.op = DHCP_BOOTREQUEST;
- message.hwtype = iface->family;
- switch (iface->family)
- {
- case ARPHRD_ETHER:
- case ARPHRD_IEEE802:
- message.hwlen = ETHER_ADDR_LEN;
- memcpy (&message.chaddr, &iface->hwaddr, ETHER_ADDR_LEN);
- break;
- case ARPHRD_IEEE1394:
- case ARPHRD_INFINIBAND:
- if (message.ciaddr == 0)
- message.flags = htons (BROADCAST_FLAG);
- message.hwlen = 0;
- break;
- default:
- logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family);
- }
-
- if (up < 0 || up > UINT16_MAX)
- message.secs = htons ((short) UINT16_MAX);
- else
- message.secs = htons (up);
- message.xid = xid;
- message.cookie = htonl (MAGIC_COOKIE);
-
- *p++ = DHCP_MESSAGETYPE;
- *p++ = 1;
- *p++ = type;
-
- if (type == DHCP_REQUEST)
- {
- *p++ = DHCP_MAXMESSAGESIZE;
- *p++ = 2;
- sz = get_mtu (iface->name);
- if (sz < MTU_MIN)
- {
- if (set_mtu (iface->name, MTU_MIN) == 0)
- sz = MTU_MIN;
- }
- sz = htons (sz);
- memcpy (p, &sz, 2);
- p += 2;
- }
-
-#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 || type == DHCP_RELEASE))
- PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress);
+ dhcpmessage_t message;
+ struct udp_dhcp_packet packet;
+ unsigned char *m = (unsigned char *) &message;
+ unsigned char *p = (unsigned char *) &message.options;
+ unsigned char *n_params = NULL;
+ unsigned long l;
+ struct in_addr from;
+ struct in_addr to;
+ long up = uptime() - iface->start_uptime;
+ uint32_t ul;
+ uint16_t sz;
+ unsigned int message_length;
+
+ if (!iface || !options || !dhcp)
+ return -1;
+
+ memset (&from, 0, sizeof (from));
+ memset (&to, 0, sizeof (to));
+
+ if (type == DHCP_RELEASE)
+ to.s_addr = dhcp->serveraddress.s_addr;
+
+ memset (&message, 0, sizeof (dhcpmessage_t));
+
+ if (type == DHCP_INFORM ||
+ type == DHCP_RELEASE ||
+ type == DHCP_REQUEST)
+ {
+ message.ciaddr = iface->previous_address.s_addr;
+ from.s_addr = iface->previous_address.s_addr;
+ }
+
+ message.op = DHCP_BOOTREQUEST;
+ message.hwtype = iface->family;
+ switch (iface->family) {
+ case ARPHRD_ETHER:
+ case ARPHRD_IEEE802:
+ message.hwlen = ETHER_ADDR_LEN;
+ memcpy (&message.chaddr, &iface->hwaddr, ETHER_ADDR_LEN);
+ break;
+ case ARPHRD_IEEE1394:
+ case ARPHRD_INFINIBAND:
+ if (message.ciaddr == 0)
+ message.flags = htons (BROADCAST_FLAG);
+ message.hwlen = 0;
+ break;
+ default:
+ logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family);
+ }
+
+ if (up < 0 || up > UINT16_MAX)
+ message.secs = htons ((short) UINT16_MAX);
+ else
+ message.secs = htons (up);
+ message.xid = xid;
+ message.cookie = htonl (MAGIC_COOKIE);
+
+ *p++ = DHCP_MESSAGETYPE;
+ *p++ = 1;
+ *p++ = type;
+
+ if (type == DHCP_REQUEST) {
+ *p++ = DHCP_MAXMESSAGESIZE;
+ *p++ = 2;
+ sz = get_mtu (iface->name);
+ if (sz < MTU_MIN) {
+ if (set_mtu (iface->name, MTU_MIN) == 0)
+ sz = MTU_MIN;
+ }
+ sz = htons (sz);
+ memcpy (p, &sz, 2);
+ p += 2;
+ }
+
+#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 || type == DHCP_RELEASE))
+ PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress);
#undef PUTADDR
- if (type == DHCP_REQUEST || type == DHCP_DISCOVER)
- {
- if (options->leasetime != 0)
- {
- *p++ = DHCP_LEASETIME;
- *p++ = 4;
- ul = htonl (options->leasetime);
- memcpy (p, &ul, 4);
- p += 4;
- }
- }
-
- if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST)
- {
- *p++ = DHCP_PARAMETERREQUESTLIST;
- n_params = p;
- *p++ = 0;
-
- /* Only request DNSSERVER in discover to keep the packets small.
- RFC2131 Section 3.5 states that the REQUEST must include the list
- from the DISCOVER message, so I think we can safely do this. */
-
- 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_STATICROUTE;
- *p++ = DHCP_ROUTERS;
- *p++ = DHCP_HOSTNAME;
- *p++ = DHCP_DNSSEARCH;
- *p++ = DHCP_DNSDOMAIN;
- *p++ = DHCP_DNSSERVER;
- *p++ = DHCP_NISDOMAIN;
- *p++ = DHCP_NISSERVER;
- *p++ = DHCP_NTPSERVER;
- *p++ = DHCP_MTU;
- /* 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 (*options->hostname)
- {
- if (options->fqdn == FQDN_DISABLE)
- {
- *p++ = DHCP_HOSTNAME;
- *p++ = l = strlen (options->hostname);
- memcpy (p, options->hostname, l);
- p += l;
- }
- else
- {
- /* Draft IETF DHC-FQDN option (81) */
- *p++ = DHCP_FQDN;
- *p++ = (l = strlen (options->hostname)) + 3;
- /* Flags: 0000NEOS
- * S: 1 => Client requests Server to update A RR in DNS as well as PTR
- * O: 1 => Server indicates to client that DNS has been updated
- * E: 1 => Name data is DNS format
- * N: 1 => Client requests Server to not update DNS
- */
- *p++ = options->fqdn & 0x9;
- *p++ = 0; /* rcode1, response from DNS server for PTR RR */
- *p++ = 0; /* rcode2, response from DNS server for A RR if S=1 */
- memcpy (p, options->hostname, l);
- p += l;
- }
- }
- }
-
- if (type != DHCP_DECLINE && type != DHCP_RELEASE)
- {
- if (options->userclass_len > 0)
- {
- *p++ = DHCP_USERCLASS;
- *p++ = options->userclass_len;
- memcpy (p, &options->userclass, options->userclass_len);
- p += options->userclass_len;
- }
-
- *p++ = DHCP_CLASSID;
- *p++ = l = strlen (options->classid);
- memcpy (p, options->classid, l);
- p += l;
- }
-
- *p++ = DHCP_CLIENTID;
- if (options->clientid[0])
- {
- l = strlen (options->clientid);
- *p++ = l + 1;
- *p++ = 0; /* string */
- memcpy (p, options, l);
- p += l;
- }
- else
- {
- *p++ = iface->hwlen + 1;
- *p++ = iface->family;
- memcpy (p, &iface->hwaddr, iface->hwlen);
- p += iface->hwlen;
- }
-
- *p++ = DHCP_END;
-
- message_length = p - m;
-
- memset (&packet, 0, sizeof (struct udp_dhcp_packet));
- make_dhcp_packet (&packet, (unsigned char *) &message, message_length,
- from, to);
-
- logger (LOG_DEBUG, "sending %s with xid 0x%lx", dhcp_message[(int) type], xid);
- return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet,
- message_length + sizeof (struct ip) +
- sizeof (struct udphdr));
+ if (type == DHCP_REQUEST || type == DHCP_DISCOVER) {
+ if (options->leasetime != 0) {
+ *p++ = DHCP_LEASETIME;
+ *p++ = 4;
+ ul = htonl (options->leasetime);
+ memcpy (p, &ul, 4);
+ p += 4;
+ }
+ }
+
+ if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST) {
+ *p++ = DHCP_PARAMETERREQUESTLIST;
+ n_params = p;
+ *p++ = 0;
+
+ /* Only request DNSSERVER in discover to keep the packets small.
+ RFC2131 Section 3.5 states that the REQUEST must include the list
+ from the DISCOVER message, so I think we can safely do this. */
+
+ 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_STATICROUTE;
+ *p++ = DHCP_ROUTERS;
+ *p++ = DHCP_HOSTNAME;
+ *p++ = DHCP_DNSSEARCH;
+ *p++ = DHCP_DNSDOMAIN;
+ *p++ = DHCP_DNSSERVER;
+ *p++ = DHCP_NISDOMAIN;
+ *p++ = DHCP_NISSERVER;
+ *p++ = DHCP_NTPSERVER;
+ *p++ = DHCP_MTU;
+ /* 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 (*options->hostname) {
+ if (options->fqdn == FQDN_DISABLE) {
+ *p++ = DHCP_HOSTNAME;
+ *p++ = l = strlen (options->hostname);
+ memcpy (p, options->hostname, l);
+ p += l;
+ } else {
+ /* Draft IETF DHC-FQDN option (81) */
+ *p++ = DHCP_FQDN;
+ *p++ = (l = strlen (options->hostname)) + 3;
+ /* Flags: 0000NEOS
+ * S: 1 => Client requests Server to update A RR in DNS as well as PTR
+ * O: 1 => Server indicates to client that DNS has been updated
+ * E: 1 => Name data is DNS format
+ * N: 1 => Client requests Server to not update DNS
+ */
+ *p++ = options->fqdn & 0x9;
+ *p++ = 0; /* rcode1, response from DNS server for PTR RR */
+ *p++ = 0; /* rcode2, response from DNS server for A RR if S=1 */
+ memcpy (p, options->hostname, l);
+ p += l;
+ }
+ }
+ }
+
+ if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
+ if (options->userclass_len > 0) {
+ *p++ = DHCP_USERCLASS;
+ *p++ = options->userclass_len;
+ memcpy (p, &options->userclass, options->userclass_len);
+ p += options->userclass_len;
+ }
+
+ *p++ = DHCP_CLASSID;
+ *p++ = l = strlen (options->classid);
+ memcpy (p, options->classid, l);
+ p += l;
+ }
+
+ *p++ = DHCP_CLIENTID;
+ if (options->clientid[0]) {
+ l = strlen (options->clientid);
+ *p++ = l + 1;
+ *p++ = 0; /* string */
+ memcpy (p, options, l);
+ p += l;
+ } else {
+ *p++ = iface->hwlen + 1;
+ *p++ = iface->family;
+ memcpy (p, &iface->hwaddr, iface->hwlen);
+ p += iface->hwlen;
+ }
+
+ *p++ = DHCP_END;
+
+ message_length = p - m;
+
+ memset (&packet, 0, sizeof (struct udp_dhcp_packet));
+ make_dhcp_packet (&packet, (unsigned char *) &message, message_length,
+ from, to);
+
+ logger (LOG_DEBUG, "sending %s with xid 0x%lx", dhcp_message[(int) type], xid);
+ return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet,
+ message_length + sizeof (struct ip) +
+ sizeof (struct udphdr));
}
static unsigned long getnetmask (unsigned long ip_in)
{
- unsigned long t, p = ntohl (ip_in);
-
- if (IN_CLASSA (p))
- t = ~IN_CLASSA_NET;
- else
- {
- if (IN_CLASSB (p))
- t = ~IN_CLASSB_NET;
- else
- {
- if (IN_CLASSC (p))
- t = ~IN_CLASSC_NET;
- else
- t = 0;
- }
- }
- while (t & p) t >>= 1;
- return htonl (~t);
+ unsigned long t, p = ntohl (ip_in);
+
+ if (IN_CLASSA (p))
+ t = ~IN_CLASSA_NET;
+ else {
+ if (IN_CLASSB (p))
+ t = ~IN_CLASSB_NET;
+ else {
+ if (IN_CLASSC (p))
+ t = ~IN_CLASSC_NET;
+ else
+ t = 0;
+ }
+ }
+ while (t & p) t >>= 1;
+ return htonl (~t);
}
/* Decode an RFC3397 DNS search order option into a space
to just determine output length. */
static unsigned int decode_search (const unsigned char *p, int len, char *out)
{
- const unsigned char *r, *q = p;
- unsigned int count = 0, l, hops;
-
- while (q - p < len)
- {
- r = NULL;
- hops = 0;
- while ((l = *q++))
- {
- unsigned int label_type = l & 0xc0;
- if (label_type == 0x80 || label_type == 0x40)
- return 0;
- else if (label_type == 0xc0) /* pointer */
- {
- l = (l & 0x3f) << 8;
- l |= *q++;
-
- /* save source of first jump. */
- if (!r)
- r = q;
-
- hops++;
- if (hops > 255)
- return 0;
-
- q = p + l;
- if (q - p >= len)
- return 0;
- }
- else
- {
- /* straightforward name segment, add with '.' */
- count += l + 1;
- if (out)
- {
- memcpy (out, q, l);
- out += l;
- *out++ = '.';
- }
- q += l;
- }
- }
-
- /* change last dot to space */
- if (out)
- *(out - 1) = ' ';
-
- if (r)
- q = r;
- }
-
- /* change last space to zero terminator */
- if (out)
- *(out - 1) = 0;
-
- return count;
+ const unsigned char *r, *q = p;
+ unsigned int count = 0, l, hops;
+
+ while (q - p < len) {
+ r = NULL;
+ hops = 0;
+ while ((l = *q++)) {
+ unsigned int label_type = l & 0xc0;
+ if (label_type == 0x80 || label_type == 0x40)
+ return 0;
+ else if (label_type == 0xc0) { /* pointer */
+ l = (l & 0x3f) << 8;
+ l |= *q++;
+
+ /* save source of first jump. */
+ if (!r)
+ r = q;
+
+ hops++;
+ if (hops > 255)
+ return 0;
+
+ q = p + l;
+ if (q - p >= len)
+ return 0;
+ } else {
+ /* straightforward name segment, add with '.' */
+ count += l + 1;
+ if (out) {
+ memcpy (out, q, l);
+ out += l;
+ *out++ = '.';
+ }
+ q += l;
+ }
+ }
+
+ /* change last dot to space */
+ if (out)
+ *(out - 1) = ' ';
+
+ if (r)
+ q = r;
+ }
+
+ /* change last space to zero terminator */
+ if (out)
+ *(out - 1) = 0;
+
+ return count;
}
/* Add our classless static routes to the routes variable
* and return the last route set */
static route_t *decodeCSR(const unsigned char *p, int len)
{
- const unsigned char *q = p;
- int cidr;
- int ocets;
- route_t *first;
- route_t *route;
-
- /* Minimum is 5 -first is CIDR and a router length of 4 */
- if (len < 5)
- return NULL;
-
- first = xmalloc (sizeof (route_t));
- route = first;
-
- while (q - p < len)
- {
- memset (route, 0, sizeof (route_t));
-
- cidr = *q++;
- if (cidr == 0)
- ocets = 0;
- else if (cidr < 9)
- ocets = 1;
- else if (cidr < 17)
- ocets = 2;
- else if (cidr < 25)
- ocets = 3;
- else
- ocets = 4;
-
- if (ocets > 0)
- {
- memcpy (&route->destination.s_addr, q, ocets);
- q += ocets;
- }
-
- /* Now enter the netmask */
- if (ocets > 0)
- {
- memset (&route->netmask.s_addr, 255, ocets - 1);
- memset ((unsigned char *) &route->netmask.s_addr + (ocets - 1),
- (256 - (1 << (32 - cidr) % 8)), 1);
- }
-
- /* Finally, snag the router */
- memcpy (&route->gateway.s_addr, q, 4);
- q += 4;
-
- /* We have another route */
- if (q - p < len)
- {
- route->next = xmalloc (sizeof (route_t));
- route = route->next;
- }
- }
-
- return first;
+ const unsigned char *q = p;
+ int cidr;
+ int ocets;
+ route_t *first;
+ route_t *route;
+
+ /* Minimum is 5 -first is CIDR and a router length of 4 */
+ if (len < 5)
+ return NULL;
+
+ first = xmalloc (sizeof (route_t));
+ route = first;
+
+ while (q - p < len) {
+ memset (route, 0, sizeof (route_t));
+
+ cidr = *q++;
+ if (cidr == 0)
+ ocets = 0;
+ else if (cidr < 9)
+ ocets = 1;
+ else if (cidr < 17)
+ ocets = 2;
+ else if (cidr < 25)
+ ocets = 3;
+ else
+ ocets = 4;
+
+ if (ocets > 0) {
+ memcpy (&route->destination.s_addr, q, ocets);
+ q += ocets;
+ }
+
+ /* Now enter the netmask */
+ if (ocets > 0) {
+ memset (&route->netmask.s_addr, 255, ocets - 1);
+ memset ((unsigned char *) &route->netmask.s_addr + (ocets - 1),
+ (256 - (1 << (32 - cidr) % 8)), 1);
+ }
+
+ /* Finally, snag the router */
+ memcpy (&route->gateway.s_addr, q, 4);
+ q += 4;
+
+ /* We have another route */
+ if (q - p < len) {
+ route->next = xmalloc (sizeof (route_t));
+ route = route->next;
+ }
+ }
+
+ return first;
}
void free_dhcp (dhcp_t *dhcp)
{
- if (! dhcp)
- return;
-
- if (dhcp->routes)
- free_route (dhcp->routes);
-
- if (dhcp->hostname)
- free (dhcp->hostname);
-
- if (dhcp->dnsservers)
- free_address (dhcp->dnsservers);
- if (dhcp->dnsdomain)
- free (dhcp->dnsdomain);
- if (dhcp->dnssearch)
- free (dhcp->dnssearch);
-
- if (dhcp->ntpservers)
- free_address (dhcp->ntpservers);
-
- if (dhcp->nisdomain)
- free (dhcp->nisdomain);
- if (dhcp->nisservers)
- free_address (dhcp->nisservers);
-
- if (dhcp->rootpath)
- free (dhcp->rootpath);
-
- if (dhcp->fqdn)
- {
- if (dhcp->fqdn->name)
- free (dhcp->fqdn->name);
- free (dhcp->fqdn);
- }
+ if (! dhcp)
+ return;
+
+ if (dhcp->routes)
+ free_route (dhcp->routes);
+
+ if (dhcp->hostname)
+ free (dhcp->hostname);
+
+ if (dhcp->dnsservers)
+ free_address (dhcp->dnsservers);
+ if (dhcp->dnsdomain)
+ free (dhcp->dnsdomain);
+ if (dhcp->dnssearch)
+ free (dhcp->dnssearch);
+
+ if (dhcp->ntpservers)
+ free_address (dhcp->ntpservers);
+
+ if (dhcp->nisdomain)
+ free (dhcp->nisdomain);
+ if (dhcp->nisservers)
+ free_address (dhcp->nisservers);
+
+ if (dhcp->rootpath)
+ free (dhcp->rootpath);
+
+ if (dhcp->fqdn) {
+ if (dhcp->fqdn->name)
+ free (dhcp->fqdn->name);
+ free (dhcp->fqdn);
+ }
}
static bool dhcp_add_address(address_t **address, const unsigned char *data, int length)
{
- int i;
- address_t *p = *address;
-
- for (i = 0; i < length; i += 4)
- {
- if (*address == NULL)
- {
- *address = xmalloc (sizeof (address_t));
- p = *address;
- }
- else
- {
- p->next = xmalloc (sizeof (address_t));
- p = p->next;
- }
- memset (p, 0, sizeof (address_t));
-
- /* Sanity check */
- if (i + 4 > length)
- {
- logger (LOG_ERR, "invalid address length");
- return (false);
- }
-
- memcpy (&p->address.s_addr, data + i, 4);
- }
-
- return (true);
+ int i;
+ address_t *p = *address;
+
+ for (i = 0; i < length; i += 4) {
+ if (*address == NULL) {
+ *address = xmalloc (sizeof (address_t));
+ p = *address;
+ } else {
+ p->next = xmalloc (sizeof (address_t));
+ p = p->next;
+ }
+ memset (p, 0, sizeof (address_t));
+
+ /* Sanity check */
+ if (i + 4 > length) {
+ logger (LOG_ERR, "invalid address length");
+ return (false);
+ }
+
+ memcpy (&p->address.s_addr, data + i, 4);
+ }
+
+ return (true);
}
int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message)
{
- const unsigned char *p = message->options;
- const unsigned char *end = p; /* Add size later for gcc-3 issue */
- unsigned char option;
- unsigned char length;
- unsigned int len = 0;
- int i;
- int retval = -1;
- route_t *first_route = xmalloc (sizeof (route_t));
- route_t *route = first_route;
- route_t *last_route = NULL;
- route_t *csr = NULL;
-
- end += sizeof (message->options);
-
- memset (first_route, 0, sizeof (route_t));
-
- dhcp->address.s_addr = message->yiaddr;
- strlcpy (dhcp->servername, message->servername,
- sizeof (dhcp->servername));
-
-#define LEN_ERR \
- { \
- logger (LOG_ERR, "invalid length %d for option %d", length, option); \
- p += length; \
- continue; \
- }
-
- while (p < end)
- {
- option = *p++;
- if (!option)
- continue;
-
- length = *p++;
-
- if (p + length >= end)
- {
- logger (LOG_ERR, "dhcp option exceeds message length");
- retval = -1;
- goto eexit;
- }
-
- switch (option)
- {
- case DHCP_END:
- goto eexit;
-
- case DHCP_MESSAGETYPE:
- retval = (int) *p;
- p += length;
- continue;
-
- default:
- if (length == 0)
- {
- logger (LOG_DEBUG, "option %d has zero length, skipping",
- option);
- continue;
- }
- }
+ const unsigned char *p = message->options;
+ const unsigned char *end = p; /* Add size later for gcc-3 issue */
+ unsigned char option;
+ unsigned char length;
+ unsigned int len = 0;
+ int i;
+ int retval = -1;
+ route_t *first_route = xmalloc (sizeof (route_t));
+ route_t *route = first_route;
+ route_t *last_route = NULL;
+ route_t *csr = NULL;
+
+ end += sizeof (message->options);
+
+ memset (first_route, 0, sizeof (route_t));
+
+ dhcp->address.s_addr = message->yiaddr;
+ strlcpy (dhcp->servername, message->servername,
+ sizeof (dhcp->servername));
+
+#define LEN_ERR { \
+ logger (LOG_ERR, "invalid length %d for option %d", length, option); \
+ p += length; \
+ continue; \
+ }
+
+ while (p < end) {
+ option = *p++;
+ if (!option)
+ continue;
+
+ length = *p++;
+
+ if (p + length >= end) {
+ logger (LOG_ERR, "dhcp option exceeds message length");
+ retval = -1;
+ goto eexit;
+ }
+
+ switch (option) {
+ case DHCP_END:
+ goto eexit;
+
+ case DHCP_MESSAGETYPE:
+ retval = (int) *p;
+ p += length;
+ continue;
+
+ default:
+ if (length == 0) {
+ logger (LOG_DEBUG, "option %d has zero length, skipping",
+ option);
+ continue;
+ }
+ }
#define LENGTH(_length) \
- if (length != _length) \
- LEN_ERR;
+ if (length != _length) \
+ LEN_ERR;
#define MIN_LENGTH(_length) \
- if (length < _length) \
- LEN_ERR;
+ if (length < _length) \
+ LEN_ERR;
#define MULT_LENGTH(_mult) \
- if (length % _mult != 0) \
- LEN_ERR;
+ if (length % _mult != 0) \
+ LEN_ERR;
#define GET_UINT8(_val) \
- LENGTH (sizeof (uint8_t)); \
- memcpy (&_val, p, sizeof (uint8_t));
+ LENGTH (sizeof (uint8_t)); \
+ memcpy (&_val, p, sizeof (uint8_t));
#define GET_UINT16(_val) \
- LENGTH (sizeof (uint16_t)); \
- memcpy (&_val, p, sizeof (uint16_t));
+ LENGTH (sizeof (uint16_t)); \
+ memcpy (&_val, p, sizeof (uint16_t));
#define GET_UINT32(_val) \
- LENGTH (sizeof (uint32_t)); \
- memcpy (&_val, p, sizeof (uint32_t));
+ LENGTH (sizeof (uint32_t)); \
+ memcpy (&_val, p, sizeof (uint32_t));
#define GET_UINT16_H(_val) \
- GET_UINT16 (_val); \
- _val = ntohs (_val);
+ GET_UINT16 (_val); \
+ _val = ntohs (_val);
#define GET_UINT32_H(_val) \
- GET_UINT32 (_val); \
- _val = ntohl (_val);
-
- switch (option)
- {
- case DHCP_ADDRESS:
- GET_UINT32 (dhcp->address.s_addr);
- break;
- case DHCP_NETMASK:
- GET_UINT32 (dhcp->netmask.s_addr);
- break;
- case DHCP_BROADCAST:
- GET_UINT32 (dhcp->broadcast.s_addr);
- break;
- case DHCP_SERVERIDENTIFIER:
- GET_UINT32 (dhcp->serveraddress.s_addr);
- break;
- case DHCP_LEASETIME:
- GET_UINT32_H (dhcp->leasetime);
- break;
- case DHCP_RENEWALTIME:
- GET_UINT32_H (dhcp->renewaltime);
- break;
- case DHCP_REBINDTIME:
- GET_UINT32_H (dhcp->rebindtime);
- break;
- case DHCP_MTU:
- GET_UINT16_H (dhcp->mtu);
- /* Minimum legal mtu is 68 accoridng to RFC 2132.
- In practise it's 576 (minimum maximum message size) */
- if (dhcp->mtu < MTU_MIN)
- {
- logger (LOG_DEBUG, "MTU %d is too low, minium is %d; ignoring", dhcp->mtu, MTU_MIN);
- dhcp->mtu = 0;
- }
- break;
+ GET_UINT32 (_val); \
+ _val = ntohl (_val);
+
+ switch (option) {
+ case DHCP_ADDRESS:
+ GET_UINT32 (dhcp->address.s_addr);
+ break;
+ case DHCP_NETMASK:
+ GET_UINT32 (dhcp->netmask.s_addr);
+ break;
+ case DHCP_BROADCAST:
+ GET_UINT32 (dhcp->broadcast.s_addr);
+ break;
+ case DHCP_SERVERIDENTIFIER:
+ GET_UINT32 (dhcp->serveraddress.s_addr);
+ break;
+ case DHCP_LEASETIME:
+ GET_UINT32_H (dhcp->leasetime);
+ break;
+ case DHCP_RENEWALTIME:
+ GET_UINT32_H (dhcp->renewaltime);
+ break;
+ case DHCP_REBINDTIME:
+ GET_UINT32_H (dhcp->rebindtime);
+ break;
+ case DHCP_MTU:
+ GET_UINT16_H (dhcp->mtu);
+ /* Minimum legal mtu is 68 accoridng to RFC 2132.
+ In practise it's 576 (minimum maximum message size) */
+ if (dhcp->mtu < MTU_MIN) {
+ logger (LOG_DEBUG, "MTU %d is too low, minium is %d; ignoring", dhcp->mtu, MTU_MIN);
+ dhcp->mtu = 0;
+ }
+ break;
#undef GET_UINT32_H
#undef GET_UINT32
#undef GET_UINT8
#define GETSTR(_var) \
- MIN_LENGTH (sizeof (char)); \
- if (_var) free (_var); \
- _var = xmalloc (length + 1); \
- memcpy (_var, p, length); \
- memset (_var + length, 0, 1);
- case DHCP_HOSTNAME:
- GETSTR (dhcp->hostname);
- break;
- case DHCP_DNSDOMAIN:
- GETSTR (dhcp->dnsdomain);
- break;
- case DHCP_MESSAGE:
- GETSTR (dhcp->message);
- break;
- case DHCP_ROOTPATH:
- GETSTR (dhcp->rootpath);
- break;
- case DHCP_NISDOMAIN:
- GETSTR (dhcp->nisdomain);
- break;
+ MIN_LENGTH (sizeof (char)); \
+ if (_var) free (_var); \
+ _var = xmalloc (length + 1); \
+ memcpy (_var, p, length); \
+ memset (_var + length, 0, 1);
+ case DHCP_HOSTNAME:
+ GETSTR (dhcp->hostname);
+ break;
+ case DHCP_DNSDOMAIN:
+ GETSTR (dhcp->dnsdomain);
+ break;
+ case DHCP_MESSAGE:
+ GETSTR (dhcp->message);
+ break;
+ case DHCP_ROOTPATH:
+ GETSTR (dhcp->rootpath);
+ break;
+ case DHCP_NISDOMAIN:
+ GETSTR (dhcp->nisdomain);
+ break;
#undef GETSTR
#define GETADDR(_var) \
- MULT_LENGTH (4); \
- if (! dhcp_add_address (&_var, p, length)) \
- { \
- retval = -1; \
- goto eexit; \
- }
- case DHCP_DNSSERVER:
- GETADDR (dhcp->dnsservers);
- break;
- case DHCP_NTPSERVER:
- GETADDR (dhcp->ntpservers);
- break;
- case DHCP_NISSERVER:
- GETADDR (dhcp->nisservers);
- break;
+ MULT_LENGTH (4); \
+ if (! dhcp_add_address (&_var, p, length)) \
+ { \
+ retval = -1; \
+ goto eexit; \
+ }
+ case DHCP_DNSSERVER:
+ GETADDR (dhcp->dnsservers);
+ break;
+ case DHCP_NTPSERVER:
+ GETADDR (dhcp->ntpservers);
+ break;
+ case DHCP_NISSERVER:
+ GETADDR (dhcp->nisservers);
+ break;
#undef GETADDR
- case DHCP_DNSSEARCH:
- MIN_LENGTH (1);
- if (dhcp->dnssearch)
- free (dhcp->dnssearch);
- if ((len = decode_search (p, length, NULL)) > 0)
- {
- dhcp->dnssearch = xmalloc (len);
- decode_search (p, length, dhcp->dnssearch);
- }
- break;
-
- case DHCP_CSR:
- MIN_LENGTH (5);
- if (csr)
- free_route (csr);
- csr = decodeCSR (p, length);
- break;
-
- case DHCP_STATICROUTE:
- MULT_LENGTH (8);
- for (i = 0; i < length; i += 8)
- {
- memcpy (&route->destination.s_addr, p + i, 4);
- memcpy (&route->gateway.s_addr, p + i + 4, 4);
- route->netmask.s_addr = getnetmask (route->destination.s_addr);
- last_route = route;
- route->next = xmalloc (sizeof (route_t));
- route = route->next;
- memset (route, 0, sizeof (route_t));
- }
- break;
-
- case DHCP_ROUTERS:
- MULT_LENGTH (4);
- for (i = 0; i < length; i += 4)
- {
- memcpy (&route->gateway.s_addr, p + i, 4);
- last_route = route;
- route->next = xmalloc (sizeof (route_t));
- route = route->next;
- memset (route, 0, sizeof (route_t));
- }
- break;
+ case DHCP_DNSSEARCH:
+ MIN_LENGTH (1);
+ if (dhcp->dnssearch)
+ free (dhcp->dnssearch);
+ if ((len = decode_search (p, length, NULL)) > 0) {
+ dhcp->dnssearch = xmalloc (len);
+ decode_search (p, length, dhcp->dnssearch);
+ }
+ break;
+
+ case DHCP_CSR:
+ MIN_LENGTH (5);
+ if (csr)
+ free_route (csr);
+ csr = decodeCSR (p, length);
+ break;
+
+ case DHCP_STATICROUTE:
+ MULT_LENGTH (8);
+ for (i = 0; i < length; i += 8) {
+ memcpy (&route->destination.s_addr, p + i, 4);
+ memcpy (&route->gateway.s_addr, p + i + 4, 4);
+ route->netmask.s_addr = getnetmask (route->destination.s_addr);
+ last_route = route;
+ route->next = xmalloc (sizeof (route_t));
+ route = route->next;
+ memset (route, 0, sizeof (route_t));
+ }
+ break;
+
+ case DHCP_ROUTERS:
+ MULT_LENGTH (4);
+ for (i = 0; i < length; i += 4)
+ {
+ memcpy (&route->gateway.s_addr, p + i, 4);
+ last_route = route;
+ route->next = xmalloc (sizeof (route_t));
+ route = route->next;
+ memset (route, 0, sizeof (route_t));
+ }
+ break;
#undef LENGTH
#undef MIN_LENGTH
#undef MULT_LENGTH
- default:
- logger (LOG_DEBUG, "no facility to parse DHCP code %u", option);
- break;
- }
+ default:
+ logger (LOG_DEBUG, "no facility to parse DHCP code %u", option);
+ break;
+ }
- p += length;
- }
+ p += length;
+ }
eexit:
- /* Fill in any missing fields */
- if (! dhcp->netmask.s_addr)
- dhcp->netmask.s_addr = getnetmask (dhcp->address.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
- static routes and routers according to RFC 3442 */
- if (csr)
- {
- dhcp->routes = csr;
- free_route (first_route);
- }
- else
- {
- dhcp->routes = first_route;
- if (last_route)
- {
- free (last_route->next);
- last_route->next = NULL;
- }
- else
- {
- free_route (dhcp->routes);
- dhcp->routes = NULL;
- }
- }
-
- return retval;
+ /* Fill in any missing fields */
+ if (! dhcp->netmask.s_addr)
+ dhcp->netmask.s_addr = getnetmask (dhcp->address.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
+ static routes and routers according to RFC 3442 */
+ if (csr) {
+ dhcp->routes = csr;
+ free_route (first_route);
+ } else {
+ dhcp->routes = first_route;
+ if (last_route) {
+ free (last_route->next);
+ last_route->next = NULL;
+ } else {
+ free_route (dhcp->routes);
+ dhcp->routes = NULL;
+ }
+ }
+
+ return retval;
}
/* DHCP options */
enum DHCP_OPTIONS
{
- DHCP_PAD = 0,
- DHCP_NETMASK = 1,
- DHCP_TIMEROFFSET = 2,
- DHCP_ROUTERS = 3,
- DHCP_TIMESERVER = 4,
- DHCP_NAMESERVER = 5,
- DHCP_DNSSERVER = 6,
- DHCP_LOGSERVER = 7,
- DHCP_COOKIESERVER = 8,
- DHCP_HOSTNAME = 12,
- DHCP_DNSDOMAIN = 15,
- DHCP_ROOTPATH = 17,
- DHCP_DEFAULTIPTTL = 23,
- DHCP_MTU = 26,
- DHCP_BROADCAST = 28,
- DHCP_MASKDISCOVERY = 29,
- DHCP_ROUTERDISCOVERY = 31,
- DHCP_STATICROUTE = 33,
- DHCP_NISDOMAIN = 40,
- DHCP_NISSERVER = 41,
- DHCP_NTPSERVER = 42,
- DHCP_ADDRESS = 50,
- DHCP_LEASETIME = 51,
- DHCP_MESSAGETYPE = 53,
- DHCP_SERVERIDENTIFIER = 54,
- DHCP_PARAMETERREQUESTLIST = 55,
- DHCP_MESSAGE = 56,
- DHCP_MAXMESSAGESIZE = 57,
- DHCP_RENEWALTIME = 58,
- DHCP_REBINDTIME = 59,
- DHCP_CLASSID = 60,
- DHCP_CLIENTID = 61,
- DHCP_USERCLASS = 77, /* RFC 3004 */
- DHCP_FQDN = 81,
- DHCP_DNSSEARCH = 119, /* RFC 3397 */
- DHCP_CSR = 121, /* RFC 3442 */
- DHCP_END = 255
+ DHCP_PAD = 0,
+ DHCP_NETMASK = 1,
+ DHCP_TIMEROFFSET = 2,
+ DHCP_ROUTERS = 3,
+ DHCP_TIMESERVER = 4,
+ DHCP_NAMESERVER = 5,
+ DHCP_DNSSERVER = 6,
+ DHCP_LOGSERVER = 7,
+ DHCP_COOKIESERVER = 8,
+ DHCP_HOSTNAME = 12,
+ DHCP_DNSDOMAIN = 15,
+ DHCP_ROOTPATH = 17,
+ DHCP_DEFAULTIPTTL = 23,
+ DHCP_MTU = 26,
+ DHCP_BROADCAST = 28,
+ DHCP_MASKDISCOVERY = 29,
+ DHCP_ROUTERDISCOVERY = 31,
+ DHCP_STATICROUTE = 33,
+ DHCP_NISDOMAIN = 40,
+ DHCP_NISSERVER = 41,
+ DHCP_NTPSERVER = 42,
+ DHCP_ADDRESS = 50,
+ DHCP_LEASETIME = 51,
+ DHCP_MESSAGETYPE = 53,
+ DHCP_SERVERIDENTIFIER = 54,
+ DHCP_PARAMETERREQUESTLIST = 55,
+ DHCP_MESSAGE = 56,
+ DHCP_MAXMESSAGESIZE = 57,
+ DHCP_RENEWALTIME = 58,
+ DHCP_REBINDTIME = 59,
+ DHCP_CLASSID = 60,
+ DHCP_CLIENTID = 61,
+ DHCP_USERCLASS = 77, /* RFC 3004 */
+ DHCP_FQDN = 81,
+ DHCP_DNSSEARCH = 119, /* RFC 3397 */
+ DHCP_CSR = 121, /* RFC 3442 */
+ DHCP_END = 255
};
/* SetFQDNHostName values - lsnybble used in flags
* and to allow 0x00 to mean disable
*/
enum FQQN {
- FQDN_DISABLE = 0x00,
- FQDN_NONE = 0x18,
- FQDN_PTR = 0x20,
- FQDN_BOTH = 0x31
+ FQDN_DISABLE = 0x00,
+ FQDN_NONE = 0x18,
+ FQDN_PTR = 0x20,
+ FQDN_BOTH = 0x31
};
typedef struct fqdn_t
{
- uint8_t flags;
- uint8_t r1;
- uint8_t r2;
- char *name;
+ uint8_t flags;
+ uint8_t r1;
+ uint8_t r2;
+ char *name;
} fqdn_t;
typedef struct dhcp_t
{
- char version[11];
-
- struct in_addr serveraddress;
- char serverhw[IF_NAMESIZE];
- char servername[64];
-
- struct in_addr address;
- struct in_addr netmask;
- struct in_addr broadcast;
- unsigned short mtu;
-
- unsigned int leasetime;
- unsigned int renewaltime;
- unsigned int rebindtime;
-
- route_t *routes;
-
- char *hostname;
- fqdn_t *fqdn;
-
- address_t *dnsservers;
- char *dnsdomain;
- char *dnssearch;
-
- address_t *ntpservers;
-
- address_t *nisservers;
- char *nisdomain;
-
- char *message;
- char *rootpath;
+ char version[11];
+
+ struct in_addr serveraddress;
+ char serverhw[IF_NAMESIZE];
+ char servername[64];
+
+ struct in_addr address;
+ struct in_addr netmask;
+ struct in_addr broadcast;
+ unsigned short mtu;
+
+ unsigned int leasetime;
+ unsigned int renewaltime;
+ unsigned int rebindtime;
+
+ route_t *routes;
+
+ char *hostname;
+ fqdn_t *fqdn;
+
+ address_t *dnsservers;
+ char *dnsdomain;
+ char *dnssearch;
+
+ address_t *ntpservers;
+
+ address_t *nisservers;
+ char *nisdomain;
+
+ char *message;
+ char *rootpath;
} dhcp_t;
/* Sizes for DHCP options */
#define DHCP_BASE_LEN (4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4)
#define DHCP_RESERVE_LEN (4 + 4 + 4 + 4 + 2)
#define DHCP_FIXED_LEN (DHCP_BASE_LEN + DHCP_CHADDR_LEN + \
- + SERVERNAME_LEN + BOOTFILE_LEN)
+ + SERVERNAME_LEN + BOOTFILE_LEN)
#define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \
- - DHCP_RESERVE_LEN)
+ - DHCP_RESERVE_LEN)
typedef struct dhcpmessage_t
{
- unsigned char op; /* message type */
- unsigned char hwtype; /* hardware address type */
- unsigned char hwlen; /* hardware address length */
- unsigned char hwopcount; /* should be zero in client's message */
- int32_t xid; /* transaction id */
- int16_t secs; /* elapsed time in sec. from trying to boot */
- int16_t flags;
- int32_t ciaddr; /* (previously allocated) client IP address */
- int32_t yiaddr; /* 'your' client IP address */
- int32_t siaddr; /* should be zero in client's messages */
- int32_t giaddr; /* should be zero in client's messages */
- unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */
- char servername[SERVERNAME_LEN]; /* server host name, null terminated string */
- char bootfile[BOOTFILE_LEN]; /* boot file name, null terminated string */
- uint32_t cookie;
- unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */
+ unsigned char op; /* message type */
+ unsigned char hwtype; /* hardware address type */
+ unsigned char hwlen; /* hardware address length */
+ unsigned char hwopcount; /* should be zero in client's message */
+ int32_t xid; /* transaction id */
+ int16_t secs; /* elapsed time in sec. from trying to boot */
+ int16_t flags;
+ int32_t ciaddr; /* (previously allocated) client IP address */
+ int32_t yiaddr; /* 'your' client IP address */
+ int32_t siaddr; /* should be zero in client's messages */
+ int32_t giaddr; /* should be zero in client's messages */
+ unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */
+ char servername[SERVERNAME_LEN]; /* server host name, null terminated string */
+ char bootfile[BOOTFILE_LEN]; /* boot file name, null terminated string */
+ uint32_t cookie;
+ unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */
} dhcpmessage_t;
struct udp_dhcp_packet
{
- struct ip ip;
- struct udphdr udp;
- dhcpmessage_t dhcp;
+ struct ip ip;
+ struct udphdr udp;
+ dhcpmessage_t dhcp;
};
size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
- unsigned long xid, char type,
- const options_t *options);
+ unsigned long xid, char type,
+ const options_t *options);
void free_dhcp (dhcp_t *dhcp);
int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message);
#define PACKAGE "dhcpcd"
#define STRINGINT(_string, _int) { \
- char *_tmp; \
- long _number = strtol (_string, &_tmp, 0); \
- errno = 0; \
- if ((errno != 0 && _number == 0) || _string == _tmp || \
- (errno == ERANGE && (_number == LONG_MAX || _number == LONG_MIN))) \
- { \
- logger (LOG_ERR, "`%s' out of range", _string);; \
- exit (EXIT_FAILURE); \
- } \
- else \
- _int = (int) _number; \
+ char *_tmp; \
+ long _number = strtol (_string, &_tmp, 0); \
+ errno = 0; \
+ if ((errno != 0 && _number == 0) || _string == _tmp || \
+ (errno == ERANGE && (_number == LONG_MAX || _number == LONG_MIN))) \
+ { \
+ logger (LOG_ERR, "`%s' out of range", _string);; \
+ exit (EXIT_FAILURE); \
+ } \
+ else \
+ _int = (int) _number; \
}
static pid_t read_pid(const char *pidfile)
{
- FILE *fp;
- pid_t pid;
+ FILE *fp;
+ pid_t pid;
- if ((fp = fopen (pidfile, "r")) == NULL)
- {
- errno = ENOENT;
- return 0;
- }
+ if ((fp = fopen (pidfile, "r")) == NULL) {
+ errno = ENOENT;
+ return 0;
+ }
- fscanf (fp, "%d", &pid);
- fclose (fp);
+ fscanf (fp, "%d", &pid);
+ fclose (fp);
- return pid;
+ return pid;
}
void make_pid (const char *pidfile)
{
- FILE *fp;
+ FILE *fp;
- if ((fp = fopen (pidfile, "w")) == NULL)
- {
- logger (LOG_ERR, "fopen `%s': %s", pidfile, strerror (errno));
- return;
- }
+ if ((fp = fopen (pidfile, "w")) == NULL) {
+ logger (LOG_ERR, "fopen `%s': %s", pidfile, strerror (errno));
+ return;
+ }
- fprintf (fp, "%u\n", getpid ());
- fclose (fp);
+ fprintf (fp, "%u\n", getpid ());
+ fclose (fp);
}
static void usage ()
{
- printf ("usage: "PACKAGE" [-adknpGHMNRY] [-c script] [-h hostame] [-i classID]\n"
- " [-l leasetime] [-m metric] [-s ipaddress] [-t timeout]\n"
- " [-u userclass] [-F [none | ptr | both]] [-I clientID]\n");
+ printf ("usage: "PACKAGE" [-adknpGHMNRY] [-c script] [-h hostame] [-i classID]\n"
+ " [-l leasetime] [-m metric] [-s ipaddress] [-t timeout]\n"
+ " [-u userclass] [-F [none | ptr | both]] [-I clientID]\n");
}
int main(int argc, char **argv)
{
- options_t options;
- int doversion = 0;
- int dohelp = 0;
- int userclasses = 0;
- int ch;
- int option_index = 0;
- char prefix[IF_NAMESIZE + 3];
- pid_t pid;
- int debug = 0;
-
- const struct option longopts[] =
- {
- {"arp", no_argument, NULL, 'a'},
- {"script",required_argument, NULL, 'c'},
- {"debug", no_argument, NULL, 'd'},
- {"hostname", required_argument, NULL, 'h'},
- {"classid", required_argument, NULL, 'i'},
- {"release", no_argument, NULL, 'k'},
- {"leasetime", required_argument, NULL, 'l'},
- {"metric", required_argument, NULL, 'm'},
- {"renew", no_argument, NULL, 'n'},
- {"persistent", no_argument, NULL, 'p'},
- {"request", required_argument, NULL, 's'},
- {"timeout", required_argument, NULL, 't'},
- {"userclass", required_argument, NULL, 'u'},
- {"fqdn", optional_argument, NULL, 'F'},
- {"nogateway", no_argument, NULL, 'G'},
- {"sethostname", no_argument, NULL, 'H'},
- {"clientid", required_argument, NULL, 'I'},
- {"nomtu", no_argument, NULL, 'M'},
- {"nontp", no_argument, NULL, 'N'},
- {"nodns", no_argument, NULL, 'R'},
- {"nonis", no_argument, NULL, 'Y'},
- {"help", no_argument, &dohelp, 1},
- {"version", no_argument, &doversion, 1},
- {NULL, 0, NULL, 0}
- };
-
- /* Sanitize our fd's */
- int zero;
- if ((zero = open (_PATH_DEVNULL, O_RDWR, 0)) >= 0)
- {
- while (zero < 3)
- zero = dup (zero);
- close(zero);
- }
-
- openlog (PACKAGE, LOG_PID, LOG_LOCAL0);
-
- memset (&options, 0, sizeof (options_t));
- options.script = (char *) DEFAULT_SCRIPT;
- snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION);
-
- options.doarp = false;
- options.dodns = true;
- options.domtu = true;
- options.donis = true;
- options.dontp = true;
- options.dogateway = true;
- options.daemonise = true;
- gethostname (options.hostname, sizeof (options.hostname));
- if (strcmp (options.hostname, "(none)") == 0 ||
- strcmp (options.hostname, "localhost") == 0)
- memset (options.hostname, 0, sizeof (options.hostname));
- options.timeout = DEFAULT_TIMEOUT;
-
- while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:F:GHI:MNRY", longopts,
- &option_index)) != -1)
- switch (ch)
- {
- case 0:
- if (longopts[option_index].flag)
- break;
- logger (LOG_ERR, "option `%s' should set a flag",
- longopts[option_index].name);
- exit (EXIT_FAILURE);
- break;
-
- case 'a':
- options.doarp = true;
- break;
- case 'c':
- options.script = optarg;
- break;
- case 'd':
- debug++;
- switch (debug)
- {
- case 1:
- setloglevel(LOG_DEBUG);
- break;
- case 2:
- options.daemonise = false;
- break;
- }
- break;
- case 'h':
- if (strlen (optarg) > HOSTNAME_MAX_LEN)
- {
- logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
- optarg, HOSTNAME_MAX_LEN);
- exit (EXIT_FAILURE);
- }
- else
- strlcpy (options.hostname, optarg, sizeof (options.hostname));
- break;
- case 'i':
- if (strlen (optarg) > CLASS_ID_MAX_LEN)
- {
- logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
- optarg, CLASS_ID_MAX_LEN);
- exit (EXIT_FAILURE);
- }
- else
- strlcpy (options.classid, optarg, sizeof (options.classid));
- break;
- case 'k':
- options.signal = SIGHUP;
- break;
- case 'l':
- STRINGINT (optarg, options.leasetime);
- if (options.leasetime <= 0)
- {
- logger (LOG_ERR, "leasetime must be a positive value");
- exit (EXIT_FAILURE);
- }
- break;
- case 'm':
- STRINGINT (optarg, options.metric);
- break;
- case 'n':
- options.signal = SIGALRM;
- break;
- case 'p':
- options.persistent = true;
- break;
- case 's':
- if (! inet_aton (optarg, &options.requestaddress))
- {
- logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
- exit (EXIT_FAILURE);
- }
- break;
- case 't':
- STRINGINT (optarg, options.timeout);
- if (options.timeout < 0)
- {
- logger (LOG_ERR, "timeout must be a positive value");
- exit (EXIT_FAILURE);
- }
- break;
- case 'u':
- {
- int i;
- int offset = 0;
- for (i = 0; i < userclasses; i++)
- offset += (int) options.userclass[offset] + 1;
- if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN)
- {
- logger (LOG_ERR, "userclass overrun, max is %d",
- USERCLASS_MAX_LEN);
- exit (EXIT_FAILURE);
- }
- userclasses++;
- memcpy (options.userclass + offset + 1 , optarg, strlen (optarg));
- options.userclass[offset] = strlen (optarg);
- options.userclass_len += (strlen (optarg)) + 1;
- }
- break;
- case 'F':
- if (strcmp (optarg, "none") == 0)
- options.fqdn = FQDN_NONE;
- else if (strcmp (optarg, "ptr") == 0)
- options.fqdn = FQDN_PTR;
- else if (strcmp (optarg, "both") == 0)
- options.fqdn = FQDN_BOTH;
- else
- {
- logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
- exit (EXIT_FAILURE);
- }
- break;
- case 'G':
- options.dogateway = false;
- break;
- case 'H':
- options.dohostname = true;
- break;
- case 'I':
- if (strlen (optarg) > CLIENT_ID_MAX_LEN)
- {
- logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
- optarg, CLIENT_ID_MAX_LEN);
- exit (EXIT_FAILURE);
- }
- else
- strlcpy (options.clientid, optarg, sizeof (options.clientid));
- break;
- case 'M':
- options.domtu = false;
- break;
- case 'N':
- options.dontp = false;
- break;
- case 'R':
- options.dodns = false;
- break;
- case 'Y':
- options.donis = false;
- break;
- case '?':
- usage ();
- exit (EXIT_FAILURE);
- default:
- usage ();
- exit (EXIT_FAILURE);
- }
-
- if (doversion)
- printf (""PACKAGE" "VERSION"\n");
-
- if (dohelp)
- usage ();
-
- if (optind < argc)
- {
- if (strlen (argv[optind]) > IF_NAMESIZE)
- {
- logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
- argv[optind], IF_NAMESIZE);
- exit (EXIT_FAILURE);
- }
- strlcpy (options.interface, argv[optind],
- sizeof (options.interface));
- }
- else
- {
- /* If only version was requested then exit now */
- if (doversion || dohelp)
- exit (EXIT_SUCCESS);
-
- logger (LOG_ERR, "no interface specified");
- exit (EXIT_FAILURE);
- }
-
- if (geteuid ())
- {
- logger (LOG_ERR, "you need to be root to run "PACKAGE);
- exit (EXIT_FAILURE);
- }
-
- snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface);
- setlogprefix (prefix);
- snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE,
- options.interface);
-
- if (options.signal != 0)
- {
- int killed = -1;
- pid = read_pid (options.pidfile);
- if (pid != 0)
- logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid);
-
- 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): %s\n", CONFIGDIR, strerror (errno));
- exit (EXIT_FAILURE);
- }
-
- if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
- | S_IROTH | S_IXOTH) && errno != EEXIST )
- {
- logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
- exit (EXIT_FAILURE);
- }
-
- if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0)
- {
- 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))
- {
- unlink (options.pidfile);
- exit (EXIT_FAILURE);
- }
-
- exit (EXIT_SUCCESS);
+ options_t options;
+ int doversion = 0;
+ int dohelp = 0;
+ int userclasses = 0;
+ int ch;
+ int option_index = 0;
+ char prefix[IF_NAMESIZE + 3];
+ pid_t pid;
+ int debug = 0;
+
+ const struct option longopts[] = {
+ {"arp", no_argument, NULL, 'a'},
+ {"script",required_argument, NULL, 'c'},
+ {"debug", no_argument, NULL, 'd'},
+ {"hostname", required_argument, NULL, 'h'},
+ {"classid", required_argument, NULL, 'i'},
+ {"release", no_argument, NULL, 'k'},
+ {"leasetime", required_argument, NULL, 'l'},
+ {"metric", required_argument, NULL, 'm'},
+ {"renew", no_argument, NULL, 'n'},
+ {"persistent", no_argument, NULL, 'p'},
+ {"request", required_argument, NULL, 's'},
+ {"timeout", required_argument, NULL, 't'},
+ {"userclass", required_argument, NULL, 'u'},
+ {"fqdn", optional_argument, NULL, 'F'},
+ {"nogateway", no_argument, NULL, 'G'},
+ {"sethostname", no_argument, NULL, 'H'},
+ {"clientid", required_argument, NULL, 'I'},
+ {"nomtu", no_argument, NULL, 'M'},
+ {"nontp", no_argument, NULL, 'N'},
+ {"nodns", no_argument, NULL, 'R'},
+ {"nonis", no_argument, NULL, 'Y'},
+ {"help", no_argument, &dohelp, 1},
+ {"version", no_argument, &doversion, 1},
+ {NULL, 0, NULL, 0}
+ };
+
+ /* Sanitize our fd's */
+ int zero;
+ if ((zero = open (_PATH_DEVNULL, O_RDWR, 0)) >= 0) {
+ while (zero < 3)
+ zero = dup (zero);
+ close(zero);
+ }
+
+ openlog (PACKAGE, LOG_PID, LOG_LOCAL0);
+
+ memset (&options, 0, sizeof (options_t));
+ options.script = (char *) DEFAULT_SCRIPT;
+ snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION);
+
+ options.doarp = false;
+ options.dodns = true;
+ options.domtu = true;
+ options.donis = true;
+ options.dontp = true;
+ options.dogateway = true;
+ options.daemonise = true;
+ gethostname (options.hostname, sizeof (options.hostname));
+ if (strcmp (options.hostname, "(none)") == 0 ||
+ strcmp (options.hostname, "localhost") == 0)
+ memset (options.hostname, 0, sizeof (options.hostname));
+ options.timeout = DEFAULT_TIMEOUT;
+
+ while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:F:GHI:MNRY", longopts,
+ &option_index)) != -1)
+ switch (ch) {
+ case 0:
+ if (longopts[option_index].flag)
+ break;
+ logger (LOG_ERR, "option `%s' should set a flag",
+ longopts[option_index].name);
+ exit (EXIT_FAILURE);
+ break;
+
+ case 'a':
+ options.doarp = true;
+ break;
+ case 'c':
+ options.script = optarg;
+ break;
+ case 'd':
+ debug++;
+ switch (debug) {
+ case 1:
+ setloglevel (LOG_DEBUG);
+ break;
+ case 2:
+ options.daemonise = false;
+ break;
+ }
+ break;
+ case 'h':
+ if (strlen (optarg) > HOSTNAME_MAX_LEN) {
+ logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
+ optarg, HOSTNAME_MAX_LEN);
+ exit (EXIT_FAILURE);
+ } else
+ strlcpy (options.hostname, optarg, sizeof (options.hostname));
+ break;
+ case 'i':
+ if (strlen (optarg) > CLASS_ID_MAX_LEN) {
+ logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
+ optarg, CLASS_ID_MAX_LEN);
+ exit (EXIT_FAILURE);
+ } else
+ strlcpy (options.classid, optarg, sizeof (options.classid));
+ break;
+ case 'k':
+ options.signal = SIGHUP;
+ break;
+ case 'l':
+ STRINGINT (optarg, options.leasetime);
+ if (options.leasetime <= 0) {
+ logger (LOG_ERR, "leasetime must be a positive value");
+ exit (EXIT_FAILURE);
+ }
+ break;
+ case 'm':
+ STRINGINT (optarg, options.metric);
+ break;
+ case 'n':
+ options.signal = SIGALRM;
+ break;
+ case 'p':
+ options.persistent = true;
+ break;
+ case 's':
+ if (! inet_aton (optarg, &options.requestaddress)) {
+ logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
+ exit (EXIT_FAILURE);
+ }
+ break;
+ case 't':
+ STRINGINT (optarg, options.timeout);
+ if (options.timeout < 0) {
+ logger (LOG_ERR, "timeout must be a positive value");
+ exit (EXIT_FAILURE);
+ }
+ break;
+ case 'u':
+ {
+ int i;
+ int offset = 0;
+ for (i = 0; i < userclasses; i++)
+ offset += (int) options.userclass[offset] + 1;
+ if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) {
+ logger (LOG_ERR, "userclass overrun, max is %d",
+ USERCLASS_MAX_LEN);
+ exit (EXIT_FAILURE);
+ }
+ userclasses++;
+ memcpy (options.userclass + offset + 1 , optarg, strlen (optarg));
+ options.userclass[offset] = strlen (optarg);
+ options.userclass_len += (strlen (optarg)) + 1;
+ }
+ break;
+ case 'F':
+ if (strcmp (optarg, "none") == 0)
+ options.fqdn = FQDN_NONE;
+ else if (strcmp (optarg, "ptr") == 0)
+ options.fqdn = FQDN_PTR;
+ else if (strcmp (optarg, "both") == 0)
+ options.fqdn = FQDN_BOTH;
+ else {
+ logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
+ exit (EXIT_FAILURE);
+ }
+ break;
+ case 'G':
+ options.dogateway = false;
+ break;
+ case 'H':
+ options.dohostname = true;
+ break;
+ case 'I':
+ if (strlen (optarg) > CLIENT_ID_MAX_LEN) {
+ logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
+ optarg, CLIENT_ID_MAX_LEN);
+ exit (EXIT_FAILURE);
+ } else
+ strlcpy (options.clientid, optarg, sizeof (options.clientid));
+ break;
+ case 'M':
+ options.domtu = false;
+ break;
+ case 'N':
+ options.dontp = false;
+ break;
+ case 'R':
+ options.dodns = false;
+ break;
+ case 'Y':
+ options.donis = false;
+ break;
+ case '?':
+ usage ();
+ exit (EXIT_FAILURE);
+ default:
+ usage ();
+ exit (EXIT_FAILURE);
+ }
+
+ if (doversion)
+ printf (""PACKAGE" "VERSION"\n");
+
+ if (dohelp)
+ usage ();
+
+ if (optind < argc) {
+ if (strlen (argv[optind]) > IF_NAMESIZE) {
+ logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
+ argv[optind], IF_NAMESIZE);
+ exit (EXIT_FAILURE);
+ }
+ strlcpy (options.interface, argv[optind],
+ sizeof (options.interface));
+ } else {
+ /* If only version was requested then exit now */
+ if (doversion || dohelp)
+ exit (EXIT_SUCCESS);
+
+ logger (LOG_ERR, "no interface specified");
+ exit (EXIT_FAILURE);
+ }
+
+ if (geteuid ()) {
+ logger (LOG_ERR, "you need to be root to run "PACKAGE);
+ exit (EXIT_FAILURE);
+ }
+
+ snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface);
+ setlogprefix (prefix);
+ snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE,
+ options.interface);
+
+ if (options.signal != 0) {
+ int killed = -1;
+ pid = read_pid (options.pidfile);
+ if (pid != 0)
+ logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid);
+
+ 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): %s\n", CONFIGDIR, strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
+ | S_IROTH | S_IXOTH) && errno != EEXIST )
+ {
+ logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) {
+ 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)) {
+ unlink (options.pidfile);
+ exit (EXIT_FAILURE);
+ }
+
+ exit (EXIT_SUCCESS);
}
#define USERCLASS_MAX_LEN 255
typedef struct options_t {
- char interface[IF_NAMESIZE];
- char hostname[HOSTNAME_MAX_LEN];
- int fqdn;
- char classid[CLASS_ID_MAX_LEN];
- char clientid[CLIENT_ID_MAX_LEN];
- char userclass[USERCLASS_MAX_LEN];
- int userclass_len;
- unsigned leasetime;
- time_t timeout;
- int metric;
- struct in_addr requestaddress;
+ char interface[IF_NAMESIZE];
+ char hostname[HOSTNAME_MAX_LEN];
+ int fqdn;
+ char classid[CLASS_ID_MAX_LEN];
+ char clientid[CLIENT_ID_MAX_LEN];
+ char userclass[USERCLASS_MAX_LEN];
+ int userclass_len;
+ unsigned leasetime;
+ time_t timeout;
+ int metric;
+ struct in_addr requestaddress;
- bool doarp;
- bool dodns;
- bool dodomainname;
- bool dogateway;
- bool dohostname;
- bool domtu;
- bool donis;
- bool dontp;
-
- int signal;
- bool persistent;
- bool daemonise;
+ bool doarp;
+ bool dodns;
+ bool dodomainname;
+ bool dogateway;
+ bool dohostname;
+ bool domtu;
+ bool donis;
+ bool dontp;
- char *script;
- char pidfile[PATH_MAX];
+ int signal;
+ bool persistent;
+ bool daemonise;
+
+ char *script;
+ char pidfile[PATH_MAX];
} options_t;
void make_pid (const char *pidfile);
#endif
#else
#include <net/if_arp.h> /*dietlibc requires this - normally from
- netinet/ether.h */
+ netinet/ether.h */
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
void free_address (address_t *addresses)
{
- address_t *p = addresses;
- address_t *n = NULL;
-
- if (! addresses)
- return;
-
- while (p)
- {
- n = p->next;
- free (p);
- p = n;
- }
+ address_t *p = addresses;
+ address_t *n = NULL;
+
+ if (! addresses)
+ return;
+
+ while (p) {
+ n = p->next;
+ free (p);
+ p = n;
+ }
}
void free_route (route_t *routes)
{
- route_t *p = routes;
- route_t *n = NULL;
-
- if (!routes)
- return;
-
- while (p)
- {
- n = p->next;
- free (p);
- p = n;
- }
+ route_t *p = routes;
+ route_t *n = NULL;
+
+ if (!routes)
+ return;
+
+ while (p) {
+ n = p->next;
+ free (p);
+ p = n;
+ }
}
int inet_ntocidr (struct in_addr address)
{
- int cidr = 0;
- uint32_t mask = htonl (address.s_addr);
+ int cidr = 0;
+ uint32_t mask = htonl (address.s_addr);
- while (mask)
- {
- cidr++;
- mask <<= 1;
- }
+ while (mask) {
+ cidr++;
+ mask <<= 1;
+ }
- return (cidr);
+ return (cidr);
}
char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen)
{
- static char buffer[128];
- char *p = buffer;
- int i;
-
- for (i = 0; i < hwlen && i < 125; i++)
- {
- if (i > 0)
- *p ++= ':';
- p += snprintf (p, 3, "%.2x", hwaddr[i]);
- }
- *p ++= '\0';
-
- return (buffer);
+ static char buffer[128];
+ char *p = buffer;
+ int i;
+
+ for (i = 0; i < hwlen && i < 125; i++) {
+ if (i > 0)
+ *p ++= ':';
+ p += snprintf (p, 3, "%.2x", hwaddr[i]);
+ }
+ *p ++= '\0';
+
+ return (buffer);
}
interface_t *read_interface (const char *ifname, int metric)
{
- int s;
- struct ifreq ifr;
- interface_t *iface;
- unsigned char hwaddr[16];
- int hwlen = 0;
- sa_family_t family = 0;
- unsigned short mtu;
+ int s;
+ struct ifreq ifr;
+ interface_t *iface;
+ unsigned char hwaddr[16];
+ int hwlen = 0;
+ sa_family_t family = 0;
+ unsigned short mtu;
#ifndef __linux__
- struct ifaddrs *ifap;
- struct ifaddrs *p;
+ struct ifaddrs *ifap;
+ struct ifaddrs *p;
#endif
- if (! ifname)
- return NULL;
+ if (! ifname)
+ return NULL;
- memset (hwaddr, sizeof (hwaddr), 0);
+ memset (hwaddr, sizeof (hwaddr), 0);
#ifndef __linux__
- if (getifaddrs (&ifap) != 0)
- return NULL;
-
- for (p = ifap; p; p = p->ifa_next)
- {
- union
- {
- struct sockaddr *sa;
- struct sockaddr_dl *sdl;
- } us;
-
- if (strcmp (p->ifa_name, ifname) != 0)
- continue;
-
- us.sa = p->ifa_addr;
-
- if (p->ifa_addr->sa_family != AF_LINK
- || (us.sdl->sdl_type != IFT_ETHER))
- /*
- && us.sdl->sdl_type != IFT_ISO88025))
- */
- {
- logger (LOG_ERR, "interface is not Ethernet");
- freeifaddrs (ifap);
- return NULL;
- }
-
- memcpy (hwaddr, us.sdl->sdl_data + us.sdl->sdl_nlen, ETHER_ADDR_LEN);
- family = ARPHRD_ETHER;
- hwlen = ETHER_ADDR_LEN;
- break;
- }
- freeifaddrs (ifap);
-
- if (!p)
- {
- logger (LOG_ERR, "could not find interface %s", ifname);
- return NULL;
- }
+ if (getifaddrs (&ifap) != 0)
+ return NULL;
+
+ for (p = ifap; p; p = p->ifa_next) {
+ union {
+ struct sockaddr *sa;
+ struct sockaddr_dl *sdl;
+ } us;
+
+ if (strcmp (p->ifa_name, ifname) != 0)
+ continue;
+
+ us.sa = p->ifa_addr;
+
+ if (p->ifa_addr->sa_family != AF_LINK
+ || (us.sdl->sdl_type != IFT_ETHER))
+ /*
+ && us.sdl->sdl_type != IFT_ISO88025))
+ */
+ {
+ logger (LOG_ERR, "interface is not Ethernet");
+ freeifaddrs (ifap);
+ return NULL;
+ }
+
+ memcpy (hwaddr, us.sdl->sdl_data + us.sdl->sdl_nlen, ETHER_ADDR_LEN);
+ family = ARPHRD_ETHER;
+ hwlen = ETHER_ADDR_LEN;
+ break;
+ }
+ freeifaddrs (ifap);
+
+ if (! p) {
+ logger (LOG_ERR, "could not find interface %s", ifname);
+ return NULL;
+ }
#endif
- memset (&ifr, 0, sizeof (struct ifreq));
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return NULL;
- }
+ memset (&ifr, 0, sizeof (struct ifreq));
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return NULL;
+ }
#ifdef __linux__
- /* Do something with the metric parameter to satisfy the compiler warning */
- metric = 0;
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- if (ioctl (s, SIOCGIFHWADDR, &ifr) <0)
- {
- logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno));
- close (s);
- return NULL;
- }
- switch (ifr.ifr_hwaddr.sa_family)
- {
- case ARPHRD_ETHER:
- case ARPHRD_IEEE802:
- hwlen = ETHER_ADDR_LEN;
- break;
- case ARPHRD_IEEE1394:
- hwlen = EUI64_ADDR_LEN;
- case ARPHRD_INFINIBAND:
- hwlen = INFINIBAND_ADDR_LEN;
- break;
- default:
- logger (LOG_ERR, "interface is not Ethernet, FireWire, InfiniBand or Token Ring");
- close (s);
- return NULL;
- }
- memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen);
- family = ifr.ifr_hwaddr.sa_family;
+ /* Do something with the metric parameter to satisfy the compiler warning */
+ metric = 0;
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl (s, SIOCGIFHWADDR, &ifr) <0) {
+ logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno));
+ close (s);
+ return NULL;
+ }
+
+ switch (ifr.ifr_hwaddr.sa_family) {
+ case ARPHRD_ETHER:
+ case ARPHRD_IEEE802:
+ hwlen = ETHER_ADDR_LEN;
+ break;
+ case ARPHRD_IEEE1394:
+ hwlen = EUI64_ADDR_LEN;
+ case ARPHRD_INFINIBAND:
+ hwlen = INFINIBAND_ADDR_LEN;
+ break;
+ default:
+ logger (LOG_ERR, "interface is not Ethernet, FireWire, InfiniBand or Token Ring");
+ close (s);
+ return NULL;
+ }
+
+ memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen);
+ family = ifr.ifr_hwaddr.sa_family;
#else
- ifr.ifr_metric = metric;
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- if (ioctl (s, SIOCSIFMETRIC, &ifr) < 0)
- {
- logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno));
- close (s);
- return NULL;
- }
+ ifr.ifr_metric = metric;
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl (s, SIOCSIFMETRIC, &ifr) < 0) {
+ logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno));
+ close (s);
+ return NULL;
+ }
#endif
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- if (ioctl(s, SIOCGIFMTU, &ifr) < 0)
- {
- logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
- close (s);
- return NULL;
- }
- if (ifr.ifr_mtu < MTU_MIN)
- {
- logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", ifr.ifr_mtu, MTU_MIN);
- ifr.ifr_mtu = MTU_MIN;
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- if (ioctl(s, SIOCSIFMTU, &ifr) < 0)
- {
- logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", strerror (errno));
- close (s);
- return NULL;
- }
- }
- mtu = ifr.ifr_mtu;
-
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
- {
- logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
- close (s);
- return NULL;
- }
-
- ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
- {
- logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno));
- close (s);
- return NULL;
- }
-
- close (s);
-
- iface = xmalloc (sizeof (interface_t));
- memset (iface, 0, sizeof (interface_t));
- strlcpy (iface->name, ifname, IF_NAMESIZE);
- snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname);
- memcpy (&iface->hwaddr, hwaddr, hwlen);
- iface->hwlen = hwlen;
-
- iface->family = family;
- iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK));
- iface->mtu = iface->previous_mtu = mtu;
-
- logger (LOG_INFO, "hardware address = %s",
- hwaddr_ntoa (iface->hwaddr, iface->hwlen));
-
- /* 0 is a valid fd, so init to -1 */
- iface->fd = -1;
-
- return iface;
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
+ logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
+ close (s);
+ return NULL;
+ }
+
+ if (ifr.ifr_mtu < MTU_MIN) {
+ logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", ifr.ifr_mtu, MTU_MIN);
+ ifr.ifr_mtu = MTU_MIN;
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
+ logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", strerror (errno));
+ close (s);
+ return NULL;
+ }
+ }
+ mtu = ifr.ifr_mtu;
+
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+ logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno));
+ close (s);
+ return NULL;
+ }
+
+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
+ logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno));
+ close (s);
+ return NULL;
+ }
+
+ close (s);
+
+ iface = xmalloc (sizeof (interface_t));
+ memset (iface, 0, sizeof (interface_t));
+ strlcpy (iface->name, ifname, IF_NAMESIZE);
+ snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname);
+ memcpy (&iface->hwaddr, hwaddr, hwlen);
+ iface->hwlen = hwlen;
+
+ iface->family = family;
+ iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK));
+ iface->mtu = iface->previous_mtu = mtu;
+
+ logger (LOG_INFO, "hardware address = %s",
+ hwaddr_ntoa (iface->hwaddr, iface->hwlen));
+
+ /* 0 is a valid fd, so init to -1 */
+ iface->fd = -1;
+
+ return iface;
}
int get_mtu (const char *ifname)
{
- struct ifreq ifr;
- int r;
- int s;
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return (-1);
- }
-
- memset (&ifr, 0, sizeof (struct ifreq));
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- r = ioctl (s, SIOCGIFMTU, &ifr);
- close (s);
-
- if (r < 0)
- {
- logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
- return (-1);
- }
-
- return (ifr.ifr_mtu);
+ struct ifreq ifr;
+ int r;
+ int s;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return (-1);
+ }
+
+ memset (&ifr, 0, sizeof (struct ifreq));
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ r = ioctl (s, SIOCGIFMTU, &ifr);
+ close (s);
+
+ if (r < 0) {
+ logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno));
+ return (-1);
+ }
+
+ return (ifr.ifr_mtu);
}
int set_mtu (const char *ifname, short int mtu)
{
- struct ifreq ifr;
- int r;
- int s;
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return (-1);
- }
-
- memset (&ifr, 0, sizeof (struct ifreq));
- logger (LOG_DEBUG, "setting MTU to %d", mtu);
- strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
- ifr.ifr_mtu = mtu;
- r = ioctl (s, SIOCSIFMTU, &ifr);
- close (s);
-
- if (r < 0)
- logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno));
-
- return (r == 0 ? 0 : -1);
+ struct ifreq ifr;
+ int r;
+ int s;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return (-1);
+ }
+
+ memset (&ifr, 0, sizeof (struct ifreq));
+ logger (LOG_DEBUG, "setting MTU to %d", mtu);
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ r = ioctl (s, SIOCSIFMTU, &ifr);
+ close (s);
+
+ if (r < 0)
+ logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno));
+
+ return (r == 0 ? 0 : -1);
}
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) \
|| defined(__APPLE__)
static int do_address (const char *ifname, struct in_addr address,
- struct in_addr netmask, struct in_addr broadcast, int del)
+ struct in_addr netmask, struct in_addr broadcast, int del)
{
- int s;
- struct ifaliasreq ifa;
+ int s;
+ struct ifaliasreq ifa;
- if (! ifname)
- return -1;
+ if (! ifname)
+ return -1;
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return -1;
- }
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
- memset (&ifa, 0, sizeof (ifa));
- strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name));
+ memset (&ifa, 0, sizeof (ifa));
+ strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name));
-#define ADDADDR(_var, _addr) \
- { \
- union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \
- _s.sa = &_var; \
- _s.sin->sin_family = AF_INET; \
- _s.sin->sin_len = sizeof (struct sockaddr_in); \
- memcpy (&_s.sin->sin_addr, &_addr, sizeof (struct in_addr)); \
- }
-
- ADDADDR (ifa.ifra_addr, address);
- ADDADDR (ifa.ifra_mask, netmask);
- if (! del)
- {
- ADDADDR (ifa.ifra_broadaddr, broadcast);
- }
+#define ADDADDR(_var, _addr) { \
+ union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \
+ _s.sa = &_var; \
+ _s.sin->sin_family = AF_INET; \
+ _s.sin->sin_len = sizeof (struct sockaddr_in); \
+ memcpy (&_s.sin->sin_addr, &_addr, sizeof (struct in_addr)); \
+ }
+
+ ADDADDR (ifa.ifra_addr, address);
+ ADDADDR (ifa.ifra_mask, netmask);
+ if (! del)
+ ADDADDR (ifa.ifra_broadaddr, broadcast);
#undef ADDADDR
- if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1)
- {
- logger (LOG_ERR, "ioctl %s: %s", del ? "SIOCDIFADDR" : "SIOCAIFADDR",
- strerror (errno));
- close (s);
- return -1;
- }
+ if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) {
+ logger (LOG_ERR, "ioctl %s: %s", del ? "SIOCDIFADDR" : "SIOCAIFADDR",
+ strerror (errno));
+ close (s);
+ return -1;
+ }
- close (s);
- return 0;
+ close (s);
+ return 0;
}
static int do_route (const char *ifname,
- struct in_addr destination,
- struct in_addr netmask,
- struct in_addr gateway,
- int metric,
- int change, int del)
+ struct in_addr destination,
+ struct in_addr netmask,
+ struct in_addr gateway,
+ int metric,
+ int change, int del)
{
- int s;
- char *dstd;
- struct rtm
- {
- struct rt_msghdr hdr;
- struct sockaddr_in destination;
- union
- {
- struct sockaddr sa;
- struct sockaddr_in sin;
- struct sockaddr_dl sdl;
- struct sockaddr_storage sss; /* added to avoid memory overrun */
- } gateway;
- struct sockaddr_in netmask;
- } rtm;
- static int seq;
-
- if (! ifname)
- return -1;
-
- /* Do something with metric to satisfy compiler warnings */
- metric = 0;
-
- dstd = strdup (inet_ntoa (destination));
- if (gateway.s_addr == destination.s_addr)
- logger (LOG_INFO, "%s route to %s/%d",
- change ? "changing" : del ? "removing" : "adding",
- dstd, inet_ntocidr (netmask));
- else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY)
- logger (LOG_INFO, "%s default route via %s",
- change ? "changing" : del ? "removing" : "adding",
- inet_ntoa (gateway));
- else
- logger (LOG_INFO, "%s route to %s/%d via %s",
- change ? "changing" : del ? "removing" : "adding",
- dstd, inet_ntocidr (netmask), inet_ntoa (gateway));
- if (dstd)
- free (dstd);
-
- if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return -1;
- }
-
- memset (&rtm, 0, sizeof (struct rtm));
-
- rtm.hdr.rtm_version = RTM_VERSION;
- rtm.hdr.rtm_seq = ++seq;
- rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD;
-
- rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
- if (netmask.s_addr == INADDR_BROADCAST)
- rtm.hdr.rtm_flags |= RTF_HOST;
- else
- rtm.hdr.rtm_flags |= RTF_GATEWAY;
-
- rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+ int s;
+ char *dstd;
+ struct rtm
+ {
+ struct rt_msghdr hdr;
+ struct sockaddr_in destination;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_dl sdl;
+ struct sockaddr_storage sss; /* added to avoid memory overrun */
+ } gateway;
+ struct sockaddr_in netmask;
+ } rtm;
+ static int seq;
+
+ if (! ifname)
+ return -1;
+
+ /* Do something with metric to satisfy compiler warnings */
+ metric = 0;
+
+ dstd = strdup (inet_ntoa (destination));
+ if (gateway.s_addr == destination.s_addr)
+ logger (LOG_INFO, "%s route to %s/%d",
+ change ? "changing" : del ? "removing" : "adding",
+ dstd, inet_ntocidr (netmask));
+ else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY)
+ logger (LOG_INFO, "%s default route via %s",
+ change ? "changing" : del ? "removing" : "adding",
+ inet_ntoa (gateway));
+ else
+ logger (LOG_INFO, "%s route to %s/%d via %s",
+ change ? "changing" : del ? "removing" : "adding",
+ dstd, inet_ntocidr (netmask), inet_ntoa (gateway));
+ if (dstd)
+ free (dstd);
+
+ if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ memset (&rtm, 0, sizeof (struct rtm));
+
+ rtm.hdr.rtm_version = RTM_VERSION;
+ rtm.hdr.rtm_seq = ++seq;
+ rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD;
+
+ rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
+ if (netmask.s_addr == INADDR_BROADCAST)
+ rtm.hdr.rtm_flags |= RTF_HOST;
+ else
+ rtm.hdr.rtm_flags |= RTF_GATEWAY;
+
+ rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
#define ADDADDR(_var, _addr) \
- _var.sin_family = AF_INET; \
- _var.sin_len = sizeof (struct sockaddr_in); \
- memcpy (&_var.sin_addr, &_addr, sizeof (struct in_addr));
-
- ADDADDR (rtm.destination, destination);
- if (netmask.s_addr == INADDR_BROADCAST)
- {
- struct ifaddrs *ifap, *ifa;
- union
- {
- struct sockaddr *sa;
- struct sockaddr_dl *sdl;
- } us;
-
- if (getifaddrs (&ifap))
- {
- logger (LOG_ERR, "getifaddrs: %s", strerror (errno));
- return -1;
- }
-
- for (ifa = ifap; ifa; ifa = ifa->ifa_next)
- {
- if (ifa->ifa_addr->sa_family != AF_LINK)
- continue;
-
- if (strcmp (ifname, ifa->ifa_name))
- continue;
-
- us.sa = ifa->ifa_addr;
- memcpy (&rtm.gateway.sdl, us.sdl, us.sdl->sdl_len);
- break;
- }
- freeifaddrs (ifap);
- }
- else
- {
- ADDADDR (rtm.gateway.sin, gateway);
- }
-
- ADDADDR (rtm.netmask, netmask);
+ _var.sin_family = AF_INET; \
+ _var.sin_len = sizeof (struct sockaddr_in); \
+ memcpy (&_var.sin_addr, &_addr, sizeof (struct in_addr));
+
+ ADDADDR (rtm.destination, destination);
+ if (netmask.s_addr == INADDR_BROADCAST) {
+ struct ifaddrs *ifap, *ifa;
+ union
+ {
+ struct sockaddr *sa;
+ struct sockaddr_dl *sdl;
+ } us;
+
+ if (getifaddrs (&ifap)) {
+ logger (LOG_ERR, "getifaddrs: %s", strerror (errno));
+ return -1;
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ if (strcmp (ifname, ifa->ifa_name))
+ continue;
+
+ us.sa = ifa->ifa_addr;
+ memcpy (&rtm.gateway.sdl, us.sdl, us.sdl->sdl_len);
+ break;
+ }
+ freeifaddrs (ifap);
+ } else {
+ ADDADDR (rtm.gateway.sin, gateway);
+ }
+
+ ADDADDR (rtm.netmask, netmask);
#undef ADDADDR
- rtm.hdr.rtm_msglen = sizeof (rtm);
+ rtm.hdr.rtm_msglen = sizeof (rtm);
- if (write(s, &rtm, sizeof (rtm)) < 0)
- {
- /* Don't report error about routes already existing */
- if (errno != EEXIST)
- logger (LOG_ERR, "write: %s", strerror (errno));
- close (s);
- return -1;
- }
+ if (write(s, &rtm, sizeof (rtm)) < 0) {
+ /* Don't report error about routes already existing */
+ if (errno != EEXIST)
+ logger (LOG_ERR, "write: %s", strerror (errno));
+ close (s);
+ return -1;
+ }
- close (s);
- return 0;
+ close (s);
+ return 0;
}
#elif __linux__
*/
static int send_netlink(struct nlmsghdr *hdr)
{
- int s;
- pid_t mypid = getpid ();
- struct sockaddr_nl nl;
- struct iovec iov;
- struct msghdr msg;
- static unsigned int seq;
- char buffer[256];
- int bytes;
- union
- {
- char *buffer;
- struct nlmsghdr *nlm;
- } h;
-
- if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return -1;
- }
-
- memset (&nl, 0, sizeof (struct sockaddr_nl));
- nl.nl_family = AF_NETLINK;
- if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) < 0)
- {
- logger (LOG_ERR, "bind: %s", strerror (errno));
- close (s);
- return -1;
- }
-
- memset (&iov, 0, sizeof (struct iovec));
- iov.iov_base = hdr;
- iov.iov_len = hdr->nlmsg_len;
-
- memset (&msg, 0, sizeof (struct msghdr));
- msg.msg_name = &nl;
- msg.msg_namelen = sizeof (nl);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- /* Request a reply */
- hdr->nlmsg_flags |= NLM_F_ACK;
- hdr->nlmsg_seq = ++seq;
-
- if (sendmsg (s, &msg, 0) < 0)
- {
- logger (LOG_ERR, "write: %s", strerror (errno));
- close (s);
- return -1;
- }
-
- memset (buffer, 0, sizeof (buffer));
- iov.iov_base = buffer;
-
- while (1)
- {
- iov.iov_len = sizeof (buffer);
- bytes = recvmsg(s, &msg, 0);
-
- if (bytes < 0)
- {
- if (errno != EINTR)
- logger (LOG_ERR, "netlink: overrun");
- continue;
- }
-
- if (bytes == 0)
- {
- logger (LOG_ERR, "netlink: EOF");
- goto eexit;
- }
-
- if (msg.msg_namelen != sizeof (nl))
- {
- logger (LOG_ERR, "netlink: sender address length mismatch");
- goto eexit;
- }
-
- for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); )
- {
- int len = h.nlm->nlmsg_len;
- int l = len - sizeof (*h.nlm);
-
- if (l < 0 || len > bytes)
- {
- if (msg.msg_flags & MSG_TRUNC)
- logger (LOG_ERR, "netlink: truncated message");
- else
- logger (LOG_ERR, "netlink: malformed message");
- goto eexit;
- }
-
- if (nl.nl_pid != 0 ||
- (pid_t) h.nlm->nlmsg_pid != mypid ||
- h.nlm->nlmsg_seq != seq)
- /* Message isn't for us, so skip it */
- goto next;
-
- /* We get an NLMSG_ERROR back with a code of zero for success */
- if (h.nlm->nlmsg_type == NLMSG_ERROR)
- {
- struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm);
- if ((unsigned) l < sizeof (struct nlmsgerr))
- logger (LOG_ERR, "netlink: truncated error message");
- else
- {
- errno = -err->error;
- if (errno == 0)
- {
- close (s);
- return 0;
- }
-
- /* Don't report on something already existing */
- if (errno != EEXIST)
- logger (LOG_ERR, "netlink: %s", strerror (errno));
- }
- goto eexit;
- }
-
- logger (LOG_ERR, "netlink: unexpected reply");
+ int s;
+ pid_t mypid = getpid ();
+ struct sockaddr_nl nl;
+ struct iovec iov;
+ struct msghdr msg;
+ static unsigned int seq;
+ char buffer[256];
+ int bytes;
+ union
+ {
+ char *buffer;
+ struct nlmsghdr *nlm;
+ } h;
+
+ if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ memset (&nl, 0, sizeof (struct sockaddr_nl));
+ nl.nl_family = AF_NETLINK;
+ if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) < 0) {
+ logger (LOG_ERR, "bind: %s", strerror (errno));
+ close (s);
+ return -1;
+ }
+
+ memset (&iov, 0, sizeof (struct iovec));
+ iov.iov_base = hdr;
+ iov.iov_len = hdr->nlmsg_len;
+
+ memset (&msg, 0, sizeof (struct msghdr));
+ msg.msg_name = &nl;
+ msg.msg_namelen = sizeof (nl);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ /* Request a reply */
+ hdr->nlmsg_flags |= NLM_F_ACK;
+ hdr->nlmsg_seq = ++seq;
+
+ if (sendmsg (s, &msg, 0) < 0) {
+ logger (LOG_ERR, "write: %s", strerror (errno));
+ close (s);
+ return -1;
+ }
+
+ memset (buffer, 0, sizeof (buffer));
+ iov.iov_base = buffer;
+
+ while (1) {
+ iov.iov_len = sizeof (buffer);
+ bytes = recvmsg(s, &msg, 0);
+
+ if (bytes < 0) {
+ if (errno != EINTR)
+ logger (LOG_ERR, "netlink: overrun");
+ continue;
+ }
+
+ if (bytes == 0) {
+ logger (LOG_ERR, "netlink: EOF");
+ goto eexit;
+ }
+
+ if (msg.msg_namelen != sizeof (nl)) {
+ logger (LOG_ERR, "netlink: sender address length mismatch");
+ goto eexit;
+ }
+
+ for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) {
+ int len = h.nlm->nlmsg_len;
+ int l = len - sizeof (*h.nlm);
+
+ if (l < 0 || len > bytes) {
+ if (msg.msg_flags & MSG_TRUNC)
+ logger (LOG_ERR, "netlink: truncated message");
+ else
+ logger (LOG_ERR, "netlink: malformed message");
+ goto eexit;
+ }
+
+ if (nl.nl_pid != 0 ||
+ (pid_t) h.nlm->nlmsg_pid != mypid ||
+ h.nlm->nlmsg_seq != seq)
+ /* Message isn't for us, so skip it */
+ goto next;
+
+ /* We get an NLMSG_ERROR back with a code of zero for success */
+ if (h.nlm->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm);
+ if ((unsigned) l < sizeof (struct nlmsgerr))
+ logger (LOG_ERR, "netlink: truncated error message");
+ else {
+ errno = -err->error;
+ if (errno == 0) {
+ close (s);
+ return 0;
+ }
+
+ /* Don't report on something already existing */
+ if (errno != EEXIST)
+ logger (LOG_ERR, "netlink: %s", strerror (errno));
+ }
+ goto eexit;
+ }
+
+ logger (LOG_ERR, "netlink: unexpected reply");
next:
- bytes -= NLMSG_ALIGN (len);
- h.buffer += NLMSG_ALIGN (len);
- }
-
- if (msg.msg_flags & MSG_TRUNC)
- {
- logger (LOG_ERR, "netlink: truncated message");
- continue;
- }
-
- if (bytes)
- {
- logger (LOG_ERR, "netlink: remnant of size %d", bytes);
- goto eexit;
- }
- }
+ bytes -= NLMSG_ALIGN (len);
+ h.buffer += NLMSG_ALIGN (len);
+ }
+
+ if (msg.msg_flags & MSG_TRUNC) {
+ logger (LOG_ERR, "netlink: truncated message");
+ continue;
+ }
+
+ if (bytes) {
+ logger (LOG_ERR, "netlink: remnant of size %d", bytes);
+ goto eexit;
+ }
+ }
eexit:
- close (s);
- return -1;
+ close (s);
+ return -1;
}
#define NLMSG_TAIL(nmsg) \
- ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len)))
+ ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len)))
static int add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
- const void *data, int alen)
+ const void *data, int alen)
{
- int len = RTA_LENGTH(alen);
- struct rtattr *rta;
-
- if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen)
- {
- logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", maxlen);
- return -1;
- }
-
- rta = NLMSG_TAIL (n);
- rta->rta_type = type;
- rta->rta_len = len;
- memcpy (RTA_DATA (rta), data, alen);
- n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
-
- return 0;
+ int len = RTA_LENGTH(alen);
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) {
+ logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", maxlen);
+ return -1;
+ }
+
+ rta = NLMSG_TAIL (n);
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy (RTA_DATA (rta), data, alen);
+ n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
+
+ return 0;
}
static int add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type,
- uint32_t data)
+ uint32_t data)
{
- int len = RTA_LENGTH (sizeof (uint32_t));
- struct rtattr *rta;
-
- if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
- {
- logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", maxlen);
- return -1;
- }
-
- rta = NLMSG_TAIL (n);
- rta->rta_type = type;
- rta->rta_len = len;
- memcpy (RTA_DATA (rta), &data, sizeof (uint32_t));
- n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
-
- return 0;
+ int len = RTA_LENGTH (sizeof (uint32_t));
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) {
+ logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", maxlen);
+ return -1;
+ }
+
+ rta = NLMSG_TAIL (n);
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy (RTA_DATA (rta), &data, sizeof (uint32_t));
+ n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
+
+ return 0;
}
static int do_address(const char *ifname,
- struct in_addr address, struct in_addr netmask,
- struct in_addr broadcast, int del)
+ struct in_addr address, struct in_addr netmask,
+ struct in_addr broadcast, int del)
{
- struct
- {
- struct nlmsghdr hdr;
- struct ifaddrmsg ifa;
- char buffer[64];
- }
- nlm;
-
- if (!ifname)
- return -1;
-
- memset (&nlm, 0, sizeof (nlm));
-
- nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
- nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
- if (! del)
- nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
- nlm.hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR;
- if (! (nlm.ifa.ifa_index = if_nametoindex (ifname)))
- {
- logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
- ifname);
- return -1;
- }
- nlm.ifa.ifa_family = AF_INET;
-
- nlm.ifa.ifa_prefixlen = inet_ntocidr (netmask);
- add_attr_l (&nlm.hdr, sizeof (nlm), IFA_LOCAL, &address.s_addr,
- sizeof (address.s_addr));
- if (! del)
- add_attr_l (&nlm.hdr, sizeof (nlm), IFA_BROADCAST, &broadcast.s_addr,
- sizeof (broadcast.s_addr));
-
- return send_netlink (&nlm.hdr);
+ struct
+ {
+ struct nlmsghdr hdr;
+ struct ifaddrmsg ifa;
+ char buffer[64];
+ }
+ nlm;
+
+ if (!ifname)
+ return -1;
+
+ memset (&nlm, 0, sizeof (nlm));
+
+ nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
+ nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
+ if (! del)
+ nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+ nlm.hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR;
+ if (! (nlm.ifa.ifa_index = if_nametoindex (ifname))) {
+ logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
+ ifname);
+ return -1;
+ }
+ nlm.ifa.ifa_family = AF_INET;
+
+ nlm.ifa.ifa_prefixlen = inet_ntocidr (netmask);
+ add_attr_l (&nlm.hdr, sizeof (nlm), IFA_LOCAL, &address.s_addr,
+ sizeof (address.s_addr));
+ if (! del)
+ add_attr_l (&nlm.hdr, sizeof (nlm), IFA_BROADCAST, &broadcast.s_addr,
+ sizeof (broadcast.s_addr));
+
+ return send_netlink (&nlm.hdr);
}
static int do_route (const char *ifname,
- struct in_addr destination,
- struct in_addr netmask,
- struct in_addr gateway,
- int metric, int change, int del)
+ struct in_addr destination,
+ struct in_addr netmask,
+ struct in_addr gateway,
+ int metric, int change, int del)
{
- char *dstd;
- char *gend;
- unsigned int ifindex;
- struct
- {
- struct nlmsghdr hdr;
- struct rtmsg rt;
- char buffer[256];
- }
- nlm;
-
- if (! ifname)
- return -1;
-
- dstd = strdup (inet_ntoa (destination));
- gend = strdup (inet_ntoa (netmask));
- if (gateway.s_addr == destination.s_addr)
- logger (LOG_INFO, "%s route to %s (%s) metric %d",
- change ? "changing" : del ? "removing" : "adding",
- dstd, gend, metric);
- else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY)
- logger (LOG_INFO, "%s default route via %s metric %d",
- change ? "changing" : del ? "removing" : "adding",
- inet_ntoa (gateway), metric);
- else
- logger (LOG_INFO, "%s route to %s (%s) via %s metric %d",
- change ? "changing" : del ? "removing" : "adding",
- dstd, gend, inet_ntoa (gateway), metric);
- if (dstd)
- free (dstd);
- if (gend)
- free (gend);
-
- memset (&nlm, 0, sizeof (nlm));
-
- nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
- if (change)
- nlm.hdr.nlmsg_flags = NLM_F_REPLACE;
- else if (! del)
- nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
- nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
- nlm.hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE;
- nlm.rt.rtm_family = AF_INET;
- nlm.rt.rtm_table = RT_TABLE_MAIN;
-
- if (del)
- nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
- else
- {
- nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
- nlm.rt.rtm_protocol = RTPROT_BOOT;
- if (gateway.s_addr == INADDR_ANY ||
- netmask.s_addr == INADDR_BROADCAST)
- nlm.rt.rtm_scope = RT_SCOPE_LINK;
- else
- nlm.rt.rtm_scope = RT_SCOPE_UNIVERSE;
- nlm.rt.rtm_type = RTN_UNICAST;
- }
-
- nlm.rt.rtm_dst_len = inet_ntocidr (netmask);
- add_attr_l (&nlm.hdr, sizeof (nlm), RTA_DST, &destination.s_addr,
- sizeof (destination.s_addr));
- if (gateway.s_addr != INADDR_ANY && gateway.s_addr != destination.s_addr)
- add_attr_l (&nlm.hdr, sizeof (nlm), RTA_GATEWAY, &gateway.s_addr,
- sizeof (gateway.s_addr));
-
-
- if (! (ifindex = if_nametoindex (ifname)))
- {
- logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
- ifname);
- return -1;
- }
-
- add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_OIF, ifindex);
- add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_PRIORITY, metric);
-
- return send_netlink (&nlm.hdr);
+ char *dstd;
+ char *gend;
+ unsigned int ifindex;
+ struct
+ {
+ struct nlmsghdr hdr;
+ struct rtmsg rt;
+ char buffer[256];
+ }
+ nlm;
+
+ if (! ifname)
+ return -1;
+
+ dstd = strdup (inet_ntoa (destination));
+ gend = strdup (inet_ntoa (netmask));
+ if (gateway.s_addr == destination.s_addr)
+ logger (LOG_INFO, "%s route to %s (%s) metric %d",
+ change ? "changing" : del ? "removing" : "adding",
+ dstd, gend, metric);
+ else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY)
+ logger (LOG_INFO, "%s default route via %s metric %d",
+ change ? "changing" : del ? "removing" : "adding",
+ inet_ntoa (gateway), metric);
+ else
+ logger (LOG_INFO, "%s route to %s (%s) via %s metric %d",
+ change ? "changing" : del ? "removing" : "adding",
+ dstd, gend, inet_ntoa (gateway), metric);
+ if (dstd)
+ free (dstd);
+ if (gend)
+ free (gend);
+
+ memset (&nlm, 0, sizeof (nlm));
+
+ nlm.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
+ if (change)
+ nlm.hdr.nlmsg_flags = NLM_F_REPLACE;
+ else if (! del)
+ nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
+ nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
+ nlm.hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE;
+ nlm.rt.rtm_family = AF_INET;
+ nlm.rt.rtm_table = RT_TABLE_MAIN;
+
+ if (del)
+ nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
+ else {
+ nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+ nlm.rt.rtm_protocol = RTPROT_BOOT;
+ if (gateway.s_addr == INADDR_ANY ||
+ netmask.s_addr == INADDR_BROADCAST)
+ nlm.rt.rtm_scope = RT_SCOPE_LINK;
+ else
+ nlm.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+ nlm.rt.rtm_type = RTN_UNICAST;
+ }
+
+ nlm.rt.rtm_dst_len = inet_ntocidr (netmask);
+ add_attr_l (&nlm.hdr, sizeof (nlm), RTA_DST, &destination.s_addr,
+ sizeof (destination.s_addr));
+ if (gateway.s_addr != INADDR_ANY && gateway.s_addr != destination.s_addr)
+ add_attr_l (&nlm.hdr, sizeof (nlm), RTA_GATEWAY, &gateway.s_addr,
+ sizeof (gateway.s_addr));
+
+
+ if (! (ifindex = if_nametoindex (ifname))) {
+ logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
+ ifname);
+ return -1;
+ }
+
+ add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_OIF, ifindex);
+ add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_PRIORITY, metric);
+
+ return send_netlink (&nlm.hdr);
}
#else
int add_address (const char *ifname, struct in_addr address,
- struct in_addr netmask, struct in_addr broadcast)
+ struct in_addr netmask, struct in_addr broadcast)
{
- logger (LOG_INFO, "adding IP address %s/%d",
- inet_ntoa (address), inet_ntocidr (netmask));
+ logger (LOG_INFO, "adding IP address %s/%d",
+ inet_ntoa (address), inet_ntocidr (netmask));
- return (do_address (ifname, address, netmask, broadcast, 0));
+ return (do_address (ifname, address, netmask, broadcast, 0));
}
int del_address (const char *ifname,
- struct in_addr address, struct in_addr netmask)
+ struct in_addr address, struct in_addr netmask)
{
- struct in_addr t;
+ struct in_addr t;
- logger (LOG_INFO, "deleting IP address %s/%d",
- inet_ntoa (address), inet_ntocidr (netmask));
+ logger (LOG_INFO, "deleting IP address %s/%d",
+ inet_ntoa (address), inet_ntocidr (netmask));
- memset (&t, 0, sizeof (t));
- return (do_address (ifname, address, netmask, t, 1));
+ memset (&t, 0, sizeof (t));
+ return (do_address (ifname, address, netmask, t, 1));
}
int add_route (const char *ifname, struct in_addr destination,
- struct in_addr netmask, struct in_addr gateway, int metric)
+ struct in_addr netmask, struct in_addr gateway, int metric)
{
- return (do_route (ifname, destination, netmask, gateway, metric, 0, 0));
+ return (do_route (ifname, destination, netmask, gateway, metric, 0, 0));
}
int change_route (const char *ifname, struct in_addr destination,
- struct in_addr netmask, struct in_addr gateway, int metric)
+ struct in_addr netmask, struct in_addr gateway, int metric)
{
- return (do_route (ifname, destination, netmask, gateway, metric, 1, 0));
+ return (do_route (ifname, destination, netmask, gateway, metric, 1, 0));
}
int del_route (const char *ifname, struct in_addr destination,
- struct in_addr netmask, struct in_addr gateway, int metric)
+ struct in_addr netmask, struct in_addr gateway, int metric)
{
- return (do_route (ifname, destination, netmask, gateway, metric, 0, 1));
+ return (do_route (ifname, destination, netmask, gateway, metric, 0, 1));
}
#ifdef HAVE_IFADDRS_H
int flush_addresses (const char *ifname)
{
- struct ifaddrs *ifap;
- struct ifaddrs *p;
- int retval = 0;
-
- if (! ifname)
- return -1;
- if (getifaddrs (&ifap) != 0)
- return -1;
-
- for (p = ifap; p; p = p->ifa_next)
- {
- union
- {
- struct sockaddr *sa;
- struct sockaddr_in *sin;
- } us_a, us_m;
-
- if (strcmp (p->ifa_name, ifname) != 0)
- continue;
-
- us_a.sa = p->ifa_addr;
- us_m.sa = p->ifa_netmask;
-
- if (us_a.sin->sin_family == AF_INET)
- if (del_address (ifname, us_a.sin->sin_addr, us_m.sin->sin_addr) < 0)
- retval = -1;
- }
- freeifaddrs (ifap);
-
- return retval;
+ struct ifaddrs *ifap;
+ struct ifaddrs *p;
+ int retval = 0;
+
+ if (! ifname)
+ return -1;
+ if (getifaddrs (&ifap) != 0)
+ return -1;
+
+ for (p = ifap; p; p = p->ifa_next) {
+ union
+ {
+ struct sockaddr *sa;
+ struct sockaddr_in *sin;
+ } us_a, us_m;
+
+ if (strcmp (p->ifa_name, ifname) != 0)
+ continue;
+
+ us_a.sa = p->ifa_addr;
+ us_m.sa = p->ifa_netmask;
+
+ if (us_a.sin->sin_family == AF_INET)
+ if (del_address (ifname, us_a.sin->sin_addr, us_m.sin->sin_addr) < 0)
+ retval = -1;
+ }
+ freeifaddrs (ifap);
+
+ return retval;
}
#else
int flush_addresses (const char *ifname)
{
- int s;
- struct ifconf ifc;
- int retval = 0;
- int i;
- void *ifrs;
- int nifs;
- struct ifreq *ifr;
-
- if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return -1;
- }
-
- memset (&ifc, 0, sizeof (struct ifconf));
- ifc.ifc_buf = NULL;
- if (ioctl (s, SIOCGIFCONF, &ifc) < 0)
- {
- logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno));
- close (s);
- }
-
- ifrs = xmalloc (ifc.ifc_len);
- ifc.ifc_buf = ifrs;
- if (ioctl (s, SIOCGIFCONF, &ifc) < 0)
- {
- logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno));
- close (s);
- free (ifrs);
- return -1;
- }
-
- close (s);
-
- nifs = ifc.ifc_len / sizeof (struct ifreq);
- ifr = ifrs;
- for (i = 0; i < nifs; i++)
- {
- struct sockaddr_in *addr = (struct sockaddr_in *) &ifr->ifr_addr;
- struct sockaddr_in *netm = (struct sockaddr_in *) &ifr->ifr_netmask;
-
- if (ifr->ifr_addr.sa_family == AF_INET
- && strcmp (ifname, ifr->ifr_name) == 0)
- if (del_address (ifname, addr->sin_addr, netm->sin_addr) < 0)
- retval = -1;
- ifr++;
- }
-
- free (ifrs);
- return retval;
+ int s;
+ struct ifconf ifc;
+ int retval = 0;
+ int i;
+ void *ifrs;
+ int nifs;
+ struct ifreq *ifr;
+
+ if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ memset (&ifc, 0, sizeof (struct ifconf));
+ ifc.ifc_buf = NULL;
+ if (ioctl (s, SIOCGIFCONF, &ifc) < 0) {
+ logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno));
+ close (s);
+ }
+
+ ifrs = xmalloc (ifc.ifc_len);
+ ifc.ifc_buf = ifrs;
+ if (ioctl (s, SIOCGIFCONF, &ifc) < 0) {
+ logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno));
+ close (s);
+ free (ifrs);
+ return -1;
+ }
+
+ close (s);
+
+ nifs = ifc.ifc_len / sizeof (struct ifreq);
+ ifr = ifrs;
+ for (i = 0; i < nifs; i++) {
+ struct sockaddr_in *addr = (struct sockaddr_in *) &ifr->ifr_addr;
+ struct sockaddr_in *netm = (struct sockaddr_in *) &ifr->ifr_netmask;
+
+ if (ifr->ifr_addr.sa_family == AF_INET
+ && strcmp (ifname, ifr->ifr_name) == 0)
+ if (del_address (ifname, addr->sin_addr, netm->sin_addr) < 0)
+ retval = -1;
+ ifr++;
+ }
+
+ free (ifrs);
+ return retval;
}
#endif
typedef struct route_t
{
- struct in_addr destination;
- struct in_addr netmask;
- struct in_addr gateway;
- struct route_t *next;
+ struct in_addr destination;
+ struct in_addr netmask;
+ struct in_addr gateway;
+ struct route_t *next;
} route_t;
typedef struct address_t
{
- struct in_addr address;
- struct address_t *next;
+ struct in_addr address;
+ struct address_t *next;
} address_t;
typedef struct interface_t
{
- char name[IF_NAMESIZE];
- sa_family_t family;
- unsigned char hwaddr[20];
- int hwlen;
- bool arpable;
- unsigned short mtu;
+ char name[IF_NAMESIZE];
+ sa_family_t family;
+ unsigned char hwaddr[20];
+ int hwlen;
+ bool arpable;
+ unsigned short mtu;
- int fd;
- int buffer_length;
+ int fd;
+ int buffer_length;
#ifdef __linux__
- int socket_protocol;
+ int socket_protocol;
#endif
- char infofile[PATH_MAX];
+ char infofile[PATH_MAX];
- unsigned short previous_mtu;
- struct in_addr previous_address;
- struct in_addr previous_netmask;
- route_t *previous_routes;
-
- long start_uptime;
+ unsigned short previous_mtu;
+ struct in_addr previous_address;
+ struct in_addr previous_netmask;
+ route_t *previous_routes;
+
+ long start_uptime;
} interface_t;
void free_address (address_t *addresses);
int set_mtu (const char *ifname, short int mtu);
int add_address (const char *ifname, struct in_addr address,
- struct in_addr netmask, struct in_addr broadcast);
+ struct in_addr netmask, struct in_addr broadcast);
int del_address (const char *ifname, struct in_addr address,
- struct in_addr netmask);
+ struct in_addr netmask);
int flush_addresses (const char *ifname);
int add_route (const char *ifname, struct in_addr destination,
- struct in_addr netmask, struct in_addr gateway, int metric);
+ struct in_addr netmask, struct in_addr gateway, int metric);
int change_route (const char *ifname, struct in_addr destination,
- struct in_addr netmask, struct in_addr gateway, int metric);
+ struct in_addr netmask, struct in_addr gateway, int metric);
int del_route (const char *ifname, struct in_addr destination,
- struct in_addr netmask, struct in_addr gateway, int metric);
+ struct in_addr netmask, struct in_addr gateway, int metric);
int inet_ntocidr (struct in_addr address);
char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen);
static char logprefix[12] = {0};
static const char *syslog_level_msg[] = {
- [LOG_EMERG] = "EMERGENCY!",
- [LOG_ALERT] = "ALERT!",
- [LOG_CRIT] = "Critical!",
- [LOG_WARNING] = "Warning",
- [LOG_ERR] = "Error",
- [LOG_INFO] = "Info",
- [LOG_DEBUG] = "Debug",
- [LOG_DEBUG + 1] = NULL
+ [LOG_EMERG] = "EMERGENCY!",
+ [LOG_ALERT] = "ALERT!",
+ [LOG_CRIT] = "Critical!",
+ [LOG_WARNING] = "Warning",
+ [LOG_ERR] = "Error",
+ [LOG_INFO] = "Info",
+ [LOG_DEBUG] = "Debug",
+ [LOG_DEBUG + 1] = NULL
};
static const char *syslog_level[] = {
- [LOG_EMERG] = "LOG_EMERG",
- [LOG_ALERT] = "LOG_ALERT",
- [LOG_CRIT] = "LOG_CRIT",
- [LOG_ERR] = "LOG_ERR",
- [LOG_WARNING] = "LOG_WARNING",
- [LOG_NOTICE] = "LOG_NOTICE",
- [LOG_INFO] = "LOG_INFO",
- [LOG_DEBUG] = "LOG_DEBUG",
- [LOG_DEBUG + 1] = NULL
+ [LOG_EMERG] = "LOG_EMERG",
+ [LOG_ALERT] = "LOG_ALERT",
+ [LOG_CRIT] = "LOG_CRIT",
+ [LOG_ERR] = "LOG_ERR",
+ [LOG_WARNING] = "LOG_WARNING",
+ [LOG_NOTICE] = "LOG_NOTICE",
+ [LOG_INFO] = "LOG_INFO",
+ [LOG_DEBUG] = "LOG_DEBUG",
+ [LOG_DEBUG + 1] = NULL
};
int logtolevel (const char *priority)
{
- int i = 0;
+ int i = 0;
- while (syslog_level[i])
- {
- if (!strcmp (priority, syslog_level[i]))
- return i;
- i++;
- }
- return -1;
+ while (syslog_level[i])
+ {
+ if (!strcmp (priority, syslog_level[i]))
+ return i;
+ i++;
+ }
+ return -1;
}
void setloglevel (int level)
{
- loglevel = level;
+ loglevel = level;
}
void setlogprefix (const char *prefix)
{
- snprintf (logprefix, sizeof (logprefix), "%s", prefix);
+ snprintf (logprefix, sizeof (logprefix), "%s", prefix);
}
void logger(int level, const char *fmt, ...)
{
- va_list p;
- va_list p2;
- FILE *f = stderr;
+ va_list p;
+ va_list p2;
+ FILE *f = stderr;
- va_start (p, fmt);
- va_copy (p2, p);
+ va_start (p, fmt);
+ va_copy (p2, p);
- if (level <= LOG_ERR || level <= loglevel)
- {
- if (level == LOG_DEBUG || level == LOG_INFO)
- f = stdout;
- fprintf (f, "%s, %s", syslog_level_msg[level], logprefix);
- vfprintf (f, fmt, p);
- fputc ('\n', f);
- }
+ if (level <= LOG_ERR || level <= loglevel) {
+ if (level == LOG_DEBUG || level == LOG_INFO)
+ f = stdout;
+ fprintf (f, "%s, %s", syslog_level_msg[level], logprefix);
+ vfprintf (f, fmt, p);
+ fputc ('\n', f);
+ }
- if (level < LOG_DEBUG || level <= loglevel)
- {
- int len = strlen (logprefix);
- int fmt2len = strlen (fmt) + len + 1;
- char *fmt2 = xmalloc (sizeof (char *) * fmt2len);
- char *pf = fmt2;
- memcpy (pf, logprefix, len);
- pf += len;
- strlcpy (pf, fmt, fmt2len - len);
- vsyslog (level, fmt2, p2);
- free (fmt2);
- }
+ if (level < LOG_DEBUG || level <= loglevel) {
+ int len = strlen (logprefix);
+ int fmt2len = strlen (fmt) + len + 1;
+ char *fmt2 = xmalloc (sizeof (char *) * fmt2len);
+ char *pf = fmt2;
+ memcpy (pf, logprefix, len);
+ pf += len;
+ strlcpy (pf, fmt, fmt2len - len);
+ vsyslog (level, fmt2, p2);
+ free (fmt2);
+ }
- va_end (p2);
- va_end (p);
+ va_end (p2);
+ va_end (p);
}
static void signal_handler (int sig)
{
- /* Silently ignore this signal and wait for it. This stops zombies.
- We do this here instead of client.c so that we don't spam the log file
- with "waiting on select messages" */
- if (sig == SIGCHLD)
- {
- wait (0);
- return;
- }
+ /* Silently ignore this signal and wait for it. This stops zombies.
+ We do this here instead of client.c so that we don't spam the log file
+ with "waiting on select messages" */
+ if (sig == SIGCHLD) {
+ wait (0);
+ return;
+ }
- if (send (signal_pipe[1], &sig, sizeof (sig), MSG_DONTWAIT) < 0)
- logger (LOG_ERR, "Could not send signal: %s", strerror (errno));
+ if (send (signal_pipe[1], &sig, sizeof (sig), MSG_DONTWAIT) < 0)
+ logger (LOG_ERR, "Could not send signal: %s", strerror (errno));
}
/* Call this before doing anything else. Sets up the socket pair
* and installs the signal handler */
void signal_setup(void)
{
- int i;
- int flags;
+ int i;
+ int flags;
- socketpair (AF_UNIX, SOCK_STREAM, 0, signal_pipe);
+ socketpair (AF_UNIX, SOCK_STREAM, 0, signal_pipe);
- /* Stop any scripts from inheriting us */
- for (i = 0; i < 2; i++)
- if ((flags = fcntl (signal_pipe[i], F_GETFD, 0)) < 0 ||
- fcntl (signal_pipe[i], F_SETFD, flags | FD_CLOEXEC) < 0)
- logger (LOG_ERR ,"fcntl: %s", strerror (errno));
+ /* Stop any scripts from inheriting us */
+ for (i = 0; i < 2; i++)
+ if ((flags = fcntl (signal_pipe[i], F_GETFD, 0)) < 0 ||
+ fcntl (signal_pipe[i], F_SETFD, flags | FD_CLOEXEC) < 0)
+ logger (LOG_ERR ,"fcntl: %s", strerror (errno));
- signal (SIGHUP, signal_handler);
- signal (SIGALRM, signal_handler);
- signal (SIGTERM, signal_handler);
- signal (SIGINT, signal_handler);
- signal (SIGCHLD, signal_handler);
+ signal (SIGHUP, signal_handler);
+ signal (SIGALRM, signal_handler);
+ signal (SIGTERM, signal_handler);
+ signal (SIGINT, signal_handler);
+ signal (SIGCHLD, signal_handler);
}
/* Quick little function to setup the rfds. Will return the
* one extra fd */
int signal_fd_set (fd_set *rfds, int extra_fd)
{
- FD_ZERO (rfds);
- FD_SET (signal_pipe[0], rfds);
- if (extra_fd >= 0)
- FD_SET (extra_fd, rfds);
- return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd;
+ FD_ZERO (rfds);
+ FD_SET (signal_pipe[0], rfds);
+ if (extra_fd >= 0)
+ FD_SET (extra_fd, rfds);
+ return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd;
}
/* Read a signal from the signal pipe. Returns 0 if there is
* your signal on success */
int signal_read (const fd_set *rfds)
{
- int sig;
+ int sig;
- if (! FD_ISSET (signal_pipe[0], rfds))
- return 0;
+ if (! FD_ISSET (signal_pipe[0], rfds))
+ return 0;
- if (read (signal_pipe[0], &sig, sizeof (sig)) < 0)
- return -1;
+ if (read (signal_pipe[0], &sig, sizeof (sig)) < 0)
+ return -1;
- return sig;
+ return sig;
}
static uint16_t checksum (unsigned char *addr, uint16_t len)
{
- uint32_t sum = 0;
- union
- {
- unsigned char *addr;
- uint16_t *i;
- } p;
- uint16_t nleft = len;
-
- p.addr = addr;
- while (nleft > 1)
- {
- sum += *p.i++;
- nleft -= 2;
- }
-
-
- if (nleft == 1)
- {
- uint8_t a = 0;
- memcpy (&a, p.i, 1);
- sum += ntohs (a) << 8;
- }
-
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
-
- return ~sum;
+ uint32_t sum = 0;
+ union
+ {
+ unsigned char *addr;
+ uint16_t *i;
+ } p;
+ uint16_t nleft = len;
+
+ p.addr = addr;
+ while (nleft > 1) {
+ sum += *p.i++;
+ nleft -= 2;
+ }
+
+
+ if (nleft == 1) {
+ uint8_t a = 0;
+ memcpy (&a, p.i, 1);
+ sum += ntohs (a) << 8;
+ }
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ return ~sum;
}
void make_dhcp_packet(struct udp_dhcp_packet *packet,
- const unsigned char *data, int length,
- struct in_addr source, struct in_addr dest)
+ const unsigned char *data, int length,
+ struct in_addr source, struct in_addr dest)
{
- struct ip *ip = &packet->ip;
- struct udphdr *udp = &packet->udp;
-
- /* OK, this is important :)
- We copy the data to our packet and then create a small part of the
- ip structure and an invalid ip_len (basically udp length).
- We then fill the udp structure and put the checksum
- of the whole packet into the udp checksum.
- Finally we complete the ip structure and ip checksum.
- If we don't do the ordering like so then the udp checksum will be
- broken, so find another way of doing it! */
-
- memcpy (&packet->dhcp, data, length);
-
- ip->ip_p = IPPROTO_UDP;
- ip->ip_src.s_addr = source.s_addr;
- if (dest.s_addr == 0)
- ip->ip_dst.s_addr = INADDR_BROADCAST;
- else
- ip->ip_dst.s_addr = dest.s_addr;
-
- udp->uh_sport = htons (DHCP_CLIENT_PORT);
- udp->uh_dport = htons (DHCP_SERVER_PORT);
- udp->uh_ulen = htons (sizeof (struct udphdr) + length);
- ip->ip_len = udp->uh_ulen;
- udp->uh_sum = checksum ((unsigned char *) packet,
- sizeof (struct udp_dhcp_packet));
-
- ip->ip_v = IPVERSION;
- ip->ip_hl = 5;
- ip->ip_id = 0;
- ip->ip_tos = IPTOS_LOWDELAY;
- ip->ip_len = htons (sizeof (struct ip) + sizeof (struct udphdr) +
- length);
- ip->ip_id = 0;
- ip->ip_off = 0;
- ip->ip_ttl = IPDEFTTL;
-
- ip->ip_sum = checksum ((unsigned char *) ip, sizeof (struct ip));
+ struct ip *ip = &packet->ip;
+ struct udphdr *udp = &packet->udp;
+
+ /* OK, this is important :)
+ We copy the data to our packet and then create a small part of the
+ ip structure and an invalid ip_len (basically udp length).
+ We then fill the udp structure and put the checksum
+ of the whole packet into the udp checksum.
+ Finally we complete the ip structure and ip checksum.
+ If we don't do the ordering like so then the udp checksum will be
+ broken, so find another way of doing it! */
+
+ memcpy (&packet->dhcp, data, length);
+
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_src.s_addr = source.s_addr;
+ if (dest.s_addr == 0)
+ ip->ip_dst.s_addr = INADDR_BROADCAST;
+ else
+ ip->ip_dst.s_addr = dest.s_addr;
+
+ udp->uh_sport = htons (DHCP_CLIENT_PORT);
+ udp->uh_dport = htons (DHCP_SERVER_PORT);
+ udp->uh_ulen = htons (sizeof (struct udphdr) + length);
+ ip->ip_len = udp->uh_ulen;
+ udp->uh_sum = checksum ((unsigned char *) packet,
+ sizeof (struct udp_dhcp_packet));
+
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = 5;
+ ip->ip_id = 0;
+ ip->ip_tos = IPTOS_LOWDELAY;
+ ip->ip_len = htons (sizeof (struct ip) + sizeof (struct udphdr) +
+ length);
+ ip->ip_id = 0;
+ ip->ip_off = 0;
+ ip->ip_ttl = IPDEFTTL;
+
+ ip->ip_sum = checksum ((unsigned char *) ip, sizeof (struct ip));
}
static int valid_dhcp_packet (unsigned char *data)
{
- union
- {
- unsigned char *data;
- struct udp_dhcp_packet *packet;
- } d;
- uint16_t bytes;
- uint16_t ipsum;
- uint16_t iplen;
- uint16_t udpsum;
- struct in_addr source;
- struct in_addr dest;
- int retval = 0;
-
- d.data = data;
- bytes = ntohs (d.packet->ip.ip_len);
- ipsum = d.packet->ip.ip_sum;
- iplen = d.packet->ip.ip_len;
- udpsum = d.packet->udp.uh_sum;
-
- d.data = data;
- d.packet->ip.ip_sum = 0;
- if (ipsum != checksum ((unsigned char *) &d.packet->ip, sizeof (struct ip)))
- {
- logger (LOG_DEBUG, "bad IP header checksum, ignoring");
- retval = -1;
- goto eexit;
- }
-
- memcpy (&source, &d.packet->ip.ip_src, sizeof (struct in_addr));
- memcpy (&dest, &d.packet->ip.ip_dst, sizeof (struct in_addr));
- memset (&d.packet->ip, 0, sizeof (struct ip));
- d.packet->udp.uh_sum = 0;
-
- d.packet->ip.ip_p = IPPROTO_UDP;
- memcpy (&d.packet->ip.ip_src, &source, sizeof (struct in_addr));
- memcpy (&d.packet->ip.ip_dst, &dest, sizeof (struct in_addr));
- d.packet->ip.ip_len = d.packet->udp.uh_ulen;
- if (udpsum && udpsum != checksum (d.data, bytes))
- {
- logger (LOG_ERR, "bad UDP checksum, ignoring");
- retval = -1;
- }
+ union
+ {
+ unsigned char *data;
+ struct udp_dhcp_packet *packet;
+ } d;
+ uint16_t bytes;
+ uint16_t ipsum;
+ uint16_t iplen;
+ uint16_t udpsum;
+ struct in_addr source;
+ struct in_addr dest;
+ int retval = 0;
+
+ d.data = data;
+ bytes = ntohs (d.packet->ip.ip_len);
+ ipsum = d.packet->ip.ip_sum;
+ iplen = d.packet->ip.ip_len;
+ udpsum = d.packet->udp.uh_sum;
+
+ d.data = data;
+ d.packet->ip.ip_sum = 0;
+ if (ipsum != checksum ((unsigned char *) &d.packet->ip,
+ sizeof (struct ip)))
+ {
+ logger (LOG_DEBUG, "bad IP header checksum, ignoring");
+ retval = -1;
+ goto eexit;
+ }
+
+ memcpy (&source, &d.packet->ip.ip_src, sizeof (struct in_addr));
+ memcpy (&dest, &d.packet->ip.ip_dst, sizeof (struct in_addr));
+ memset (&d.packet->ip, 0, sizeof (struct ip));
+ d.packet->udp.uh_sum = 0;
+
+ d.packet->ip.ip_p = IPPROTO_UDP;
+ memcpy (&d.packet->ip.ip_src, &source, sizeof (struct in_addr));
+ memcpy (&d.packet->ip.ip_dst, &dest, sizeof (struct in_addr));
+ d.packet->ip.ip_len = d.packet->udp.uh_ulen;
+ if (udpsum && udpsum != checksum (d.data, bytes)) {
+ logger (LOG_ERR, "bad UDP checksum, ignoring");
+ retval = -1;
+ }
eexit:
- d.packet->ip.ip_sum = ipsum;
- d.packet->ip.ip_len = iplen;
- d.packet->udp.uh_sum = udpsum;
+ d.packet->ip.ip_sum = ipsum;
+ d.packet->ip.ip_len = iplen;
+ d.packet->udp.uh_sum = udpsum;
- return retval;
+ return retval;
}
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) \
- || defined(__APPLE__)
+ || defined(__APPLE__)
/* Credit where credit is due :)
The below BPF filter is taken from ISC DHCP */
# include <net/bpf.h>
static struct bpf_insn dhcp_bpf_filter [] = {
- /* Make sure this is an IP packet... */
- BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
- BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
+ /* Make sure this is an IP packet... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
- /* Make sure it's a UDP packet... */
- BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
- BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
+ /* Make sure it's a UDP packet... */
+ BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
- /* Make sure this isn't a fragment... */
- BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20),
- BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
+ /* Make sure this isn't a fragment... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
- /* Get the IP header length... */
- BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
+ /* Get the IP header length... */
+ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
- /* Make sure it's to the right port... */
- BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
- BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1),
+ /* Make sure it's to the right port... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1),
- /* If we passed all the tests, ask for the whole packet. */
- BPF_STMT (BPF_RET+BPF_K, (u_int) - 1),
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT (BPF_RET+BPF_K, (u_int) - 1),
- /* Otherwise, drop it. */
- BPF_STMT (BPF_RET+BPF_K, 0),
+ /* Otherwise, drop it. */
+ BPF_STMT (BPF_RET+BPF_K, 0),
};
static struct bpf_insn arp_bpf_filter [] = {
- /* Make sure this is an ARP packet... */
- BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
- BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3),
+ /* Make sure this is an ARP packet... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3),
- /* Make sure this is an ARP REPLY... */
- BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20),
- BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1),
+ /* Make sure this is an ARP REPLY... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1),
- /* If we passed all the tests, ask for the whole packet. */
- BPF_STMT (BPF_RET+BPF_K, (u_int) - 1),
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT (BPF_RET+BPF_K, (u_int) - 1),
- /* Otherwise, drop it. */
- BPF_STMT (BPF_RET+BPF_K, 0),
+ /* Otherwise, drop it. */
+ BPF_STMT (BPF_RET+BPF_K, 0),
};
int open_socket (interface_t *iface, bool arp)
{
- int n = 0;
- int fd = -1;
- char device[PATH_MAX];
- int flags;
- struct ifreq ifr;
- int buf = 0;
- struct bpf_program p;
-
- do
- {
- snprintf (device, PATH_MAX, "/dev/bpf%d", n++);
- fd = open (device, O_RDWR);
- } while (fd < 0 && errno == EBUSY);
-
- if (fd < 0)
- {
- logger (LOG_ERR, "unable to open a BPF device");
- return -1;
- }
-
- if ((flags = fcntl (fd, F_GETFD, 0)) < 0
- || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0)
- {
- logger (LOG_ERR, "fcntl: %s", strerror (errno));
- close (fd);
- return -1;
- }
-
- memset (&ifr, 0, sizeof (struct ifreq));
- strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name));
- if (ioctl (fd, BIOCSETIF, &ifr) < 0)
- {
- logger (LOG_ERR, "cannot attach interface `%s' to bpf device `%s': %s",
- iface->name, device, strerror (errno));
- close (fd);
- return -1;
- }
-
- /* Get the required BPF buffer length from the kernel. */
- if (ioctl (fd, BIOCGBLEN, &buf) < 0)
- {
- logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno));
- close (fd);
- return -1;
- }
- iface->buffer_length = buf;
-
- flags = 1;
- if (ioctl (fd, BIOCIMMEDIATE, &flags) < 0)
- {
- logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno));
- close (fd);
- return -1;
- }
-
- /* Install the DHCP filter */
- if (arp)
- {
- p.bf_insns = arp_bpf_filter;
- p.bf_len = sizeof (arp_bpf_filter) / sizeof (struct bpf_insn);
- }
- else
- {
- p.bf_insns = dhcp_bpf_filter;
- p.bf_len = sizeof (dhcp_bpf_filter) / sizeof (struct bpf_insn);
- }
- if (ioctl (fd, BIOCSETF, &p) < 0)
- {
- logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno));
- close (fd);
- return -1;
- }
-
- if (iface->fd > -1)
- close (iface->fd);
- iface->fd = fd;
-
- return fd;
+ int n = 0;
+ int fd = -1;
+ char device[PATH_MAX];
+ int flags;
+ struct ifreq ifr;
+ int buf = 0;
+ struct bpf_program p;
+
+ do {
+ snprintf (device, PATH_MAX, "/dev/bpf%d", n++);
+ fd = open (device, O_RDWR);
+ } while (fd < 0 && errno == EBUSY);
+
+ if (fd < 0) {
+ logger (LOG_ERR, "unable to open a BPF device");
+ return -1;
+ }
+
+ if ((flags = fcntl (fd, F_GETFD, 0)) < 0
+ || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0)
+ {
+ logger (LOG_ERR, "fcntl: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ memset (&ifr, 0, sizeof (struct ifreq));
+ strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name));
+ if (ioctl (fd, BIOCSETIF, &ifr) < 0) {
+ logger (LOG_ERR, "cannot attach interface `%s' to bpf device `%s': %s",
+ iface->name, device, strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ /* Get the required BPF buffer length from the kernel. */
+ if (ioctl (fd, BIOCGBLEN, &buf) < 0) {
+ logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+ iface->buffer_length = buf;
+
+ flags = 1;
+ if (ioctl (fd, BIOCIMMEDIATE, &flags) < 0) {
+ logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ /* Install the DHCP filter */
+ if (arp) {
+ p.bf_insns = arp_bpf_filter;
+ p.bf_len = sizeof (arp_bpf_filter) / sizeof (struct bpf_insn);
+ } else {
+ p.bf_insns = dhcp_bpf_filter;
+ p.bf_len = sizeof (dhcp_bpf_filter) / sizeof (struct bpf_insn);
+ }
+ if (ioctl (fd, BIOCSETF, &p) < 0) {
+ logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ if (iface->fd > -1)
+ close (iface->fd);
+ iface->fd = fd;
+
+ return fd;
}
int send_packet (const interface_t *iface, int type,
- const unsigned char *data, int len)
+ const unsigned char *data, int len)
{
- int retval = -1;
- struct iovec iov[2];
-
- if (iface->family == ARPHRD_ETHER)
- {
- struct ether_header hw;
- memset (&hw, 0, sizeof (struct ether_header));
- memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
- hw.ether_type = htons (type);
-
- iov[0].iov_base = &hw;
- iov[0].iov_len = sizeof (struct ether_header);
- }
- else
- {
- logger (LOG_ERR, "unsupported interace type %d", iface->family);
- return -1;
- }
- iov[1].iov_base = (unsigned char *) data;
- iov[1].iov_len = len;
-
- if ((retval = writev(iface->fd, iov, 2)) == -1)
- logger (LOG_ERR, "writev: %s", strerror (errno));
-
- return retval;
+ int retval = -1;
+ struct iovec iov[2];
+
+ if (iface->family == ARPHRD_ETHER) {
+ struct ether_header hw;
+ memset (&hw, 0, sizeof (struct ether_header));
+ memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
+ hw.ether_type = htons (type);
+
+ iov[0].iov_base = &hw;
+ iov[0].iov_len = sizeof (struct ether_header);
+ } else {
+ logger (LOG_ERR, "unsupported interace type %d", iface->family);
+ return -1;
+ }
+ iov[1].iov_base = (unsigned char *) data;
+ iov[1].iov_len = len;
+
+ if ((retval = writev(iface->fd, iov, 2)) == -1)
+ logger (LOG_ERR, "writev: %s", strerror (errno));
+
+ return retval;
}
/* BPF requires that we read the entire buffer.
So we pass the buffer in the API so we can loop on >1 dhcp packet. */
int get_packet (const interface_t *iface, unsigned char *data,
- unsigned char *buffer, int *buffer_len, int *buffer_pos)
+ unsigned char *buffer, int *buffer_len, int *buffer_pos)
{
- union
- {
- unsigned char *buffer;
- struct bpf_hdr *packet;
- } bpf;
-
- bpf.buffer = buffer;
-
- if (*buffer_pos < 1)
- {
- memset (bpf.buffer, 0, iface->buffer_length);
- *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length);
- *buffer_pos = 0;
- if (*buffer_len < 1)
- {
- struct timeval tv;
- logger (LOG_ERR, "read: %s", strerror (errno));
- tv.tv_sec = 3;
- tv.tv_usec = 0;
- select (0, NULL, NULL, NULL, &tv);
- return -1;
- }
- }
- else
- bpf.buffer += *buffer_pos;
-
- while (bpf.packet)
- {
- int len = -1;
- union
- {
- unsigned char *buffer;
- struct ether_header *hw;
- } hdr;
- unsigned char *payload;
-
- /* Ensure that the entire packet is in our buffer */
- if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen
- > (unsigned) *buffer_len)
- break;
-
- hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen;
- payload = hdr.buffer + sizeof (struct ether_header);
-
- /* If it's an ARP reply, then just send it back */
- if (hdr.hw->ether_type == htons (ETHERTYPE_ARP))
- {
- len = bpf.packet->bh_caplen - sizeof (struct ether_header);
- memcpy (data, payload, len);
- }
- else
- {
- if (valid_dhcp_packet (payload) >= 0)
- {
- union
- {
- unsigned char *buffer;
- struct udp_dhcp_packet *packet;
- } pay;
- pay.buffer = payload;
- len = ntohs (pay.packet->ip.ip_len) - sizeof (struct ip) -
- sizeof (struct udphdr);
- memcpy (data, &pay.packet->dhcp, len);
- }
- }
-
- /* Update the buffer_pos pointer */
- bpf.buffer +=
- BPF_WORDALIGN (bpf.packet->bh_hdrlen + bpf.packet->bh_caplen);
- if (bpf.buffer - buffer < *buffer_len)
- *buffer_pos = bpf.buffer - buffer;
- else
- *buffer_pos = 0;
-
- if (len != -1)
- return len;
-
- if (*buffer_pos == 0)
- break;
- }
-
- /* No valid packets left, so return */
- *buffer_pos = 0;
- return -1;
+ union
+ {
+ unsigned char *buffer;
+ struct bpf_hdr *packet;
+ } bpf;
+
+ bpf.buffer = buffer;
+
+ if (*buffer_pos < 1) {
+ memset (bpf.buffer, 0, iface->buffer_length);
+ *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length);
+ *buffer_pos = 0;
+ if (*buffer_len < 1) {
+ struct timeval tv;
+ logger (LOG_ERR, "read: %s", strerror (errno));
+ tv.tv_sec = 3;
+ tv.tv_usec = 0;
+ select (0, NULL, NULL, NULL, &tv);
+ return -1;
+ }
+ } else
+ bpf.buffer += *buffer_pos;
+
+ while (bpf.packet) {
+ int len = -1;
+ union
+ {
+ unsigned char *buffer;
+ struct ether_header *hw;
+ } hdr;
+ unsigned char *payload;
+
+ /* Ensure that the entire packet is in our buffer */
+ if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen
+ > (unsigned) *buffer_len)
+ break;
+
+ hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen;
+ payload = hdr.buffer + sizeof (struct ether_header);
+
+ /* If it's an ARP reply, then just send it back */
+ if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) {
+ len = bpf.packet->bh_caplen - sizeof (struct ether_header);
+ memcpy (data, payload, len);
+ } else {
+ if (valid_dhcp_packet (payload) >= 0) {
+ union
+ {
+ unsigned char *buffer;
+ struct udp_dhcp_packet *packet;
+ } pay;
+ pay.buffer = payload;
+ len = ntohs (pay.packet->ip.ip_len) - sizeof (struct ip) -
+ sizeof (struct udphdr);
+ memcpy (data, &pay.packet->dhcp, len);
+ }
+ }
+
+ /* Update the buffer_pos pointer */
+ bpf.buffer +=
+ BPF_WORDALIGN (bpf.packet->bh_hdrlen + bpf.packet->bh_caplen);
+ if (bpf.buffer - buffer < *buffer_len)
+ *buffer_pos = bpf.buffer - buffer;
+ else
+ *buffer_pos = 0;
+
+ if (len != -1)
+ return len;
+
+ if (*buffer_pos == 0)
+ break;
+ }
+
+ /* No valid packets left, so return */
+ *buffer_pos = 0;
+ return -1;
}
#elif __linux__
int open_socket (interface_t *iface, bool arp)
{
- int fd;
- int flags;
- struct sockaddr_ll sll;
-
- if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP))) < 0)
- {
- logger (LOG_ERR, "socket: %s", strerror (errno));
- return -1;
- }
-
- if ((flags = fcntl (fd, F_GETFD, 0)) < 0
- || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0)
- {
- logger (LOG_ERR, "fcntl: %s", strerror (errno));
- close (fd);
- return -1;
- }
-
- memset (&sll, 0, sizeof (struct sockaddr_ll));
- sll.sll_family = AF_PACKET;
- if (arp)
- sll.sll_protocol = htons (ETH_P_ARP);
- else
- sll.sll_protocol = htons (ETH_P_IP);
- if (! (sll.sll_ifindex = if_nametoindex (iface->name)))
- {
- logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
- iface->name);
- close (fd);
- return -1;
- }
-
- if (bind(fd, (struct sockaddr *) &sll, sizeof (struct sockaddr_ll)) == -1)
- {
- logger (LOG_ERR, "bind: %s", strerror (errno));
- close (fd);
- return -1;
- }
-
- if (iface->fd > -1)
- close (iface->fd);
- iface->fd = fd;
- iface->socket_protocol = ntohs (sll.sll_protocol);
-
- iface->buffer_length = BUFFER_LENGTH;
-
- return fd;
+ int fd;
+ int flags;
+ struct sockaddr_ll sll;
+
+ if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP))) < 0) {
+ logger (LOG_ERR, "socket: %s", strerror (errno));
+ return -1;
+ }
+
+ if ((flags = fcntl (fd, F_GETFD, 0)) < 0
+ || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0)
+ {
+ logger (LOG_ERR, "fcntl: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ memset (&sll, 0, sizeof (struct sockaddr_ll));
+ sll.sll_family = AF_PACKET;
+ if (arp)
+ sll.sll_protocol = htons (ETH_P_ARP);
+ else
+ sll.sll_protocol = htons (ETH_P_IP);
+ if (! (sll.sll_ifindex = if_nametoindex (iface->name))) {
+ logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
+ iface->name);
+ close (fd);
+ return -1;
+ }
+
+ if (bind (fd, (struct sockaddr *) &sll,
+ sizeof (struct sockaddr_ll)) == -1)
+ {
+ logger (LOG_ERR, "bind: %s", strerror (errno));
+ close (fd);
+ return -1;
+ }
+
+ if (iface->fd > -1)
+ close (iface->fd);
+ iface->fd = fd;
+ iface->socket_protocol = ntohs (sll.sll_protocol);
+
+ iface->buffer_length = BUFFER_LENGTH;
+
+ return fd;
}
int send_packet (const interface_t *iface, const int type,
- const unsigned char *data, const int len)
+ const unsigned char *data, const int len)
{
- struct sockaddr_ll sll;
- int retval;
-
- if (! iface)
- return -1;
-
- memset (&sll, 0, sizeof (struct sockaddr_ll));
- sll.sll_family = AF_PACKET;
- sll.sll_protocol = htons (type);
- if (! (sll.sll_ifindex = if_nametoindex (iface->name)))
- {
- logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
- iface->name);
- return -1;
- }
- sll.sll_halen = ETHER_ADDR_LEN;
- memset(sll.sll_addr, 0xff, sizeof (sll.sll_addr));
-
- if ((retval = sendto (iface->fd, data, len, 0, (struct sockaddr *) &sll,
- sizeof (struct sockaddr_ll))) < 0)
-
- logger (LOG_ERR, "sendto: %s", strerror (errno));
- return retval;
+ struct sockaddr_ll sll;
+ int retval;
+
+ if (! iface)
+ return -1;
+
+ memset (&sll, 0, sizeof (struct sockaddr_ll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = htons (type);
+ if (! (sll.sll_ifindex = if_nametoindex (iface->name))) {
+ logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'",
+ iface->name);
+ return -1;
+ }
+ sll.sll_halen = ETHER_ADDR_LEN;
+ memset(sll.sll_addr, 0xff, sizeof (sll.sll_addr));
+
+ if ((retval = sendto (iface->fd, data, len, 0, (struct sockaddr *) &sll,
+ sizeof (struct sockaddr_ll))) < 0)
+
+ logger (LOG_ERR, "sendto: %s", strerror (errno));
+ return retval;
}
/* Linux has no need for the buffer as we can read as much as we want.
We only have the buffer listed to keep the same API. */
int get_packet (const interface_t *iface, unsigned char *data,
- unsigned char *buffer, int *buffer_len, int *buffer_pos)
+ unsigned char *buffer, int *buffer_len, int *buffer_pos)
{
- long bytes;
- union
- {
- unsigned char *buffer;
- struct udp_dhcp_packet *packet;
- } pay;
-
- /* We don't use the given buffer, but we need to rewind the position */
- *buffer_pos = 0;
-
- memset (buffer, 0, iface->buffer_length);
- bytes = read (iface->fd, buffer, iface->buffer_length);
-
- if (bytes < 0)
- {
- struct timeval tv;
- logger (LOG_ERR, "read: %s", strerror (errno));
- tv.tv_sec = 3;
- tv.tv_usec = 0;
- select (0, NULL, NULL, NULL, &tv);
- return -1;
- }
-
- *buffer_len = bytes;
- /* If it's an ARP reply, then just send it back */
- if (iface->socket_protocol == ETH_P_ARP)
- {
- memcpy (data, buffer, bytes);
- return bytes;
- }
-
- if ((unsigned) bytes < (sizeof (struct ip) + sizeof (struct udphdr)))
- {
- logger (LOG_DEBUG, "message too short, ignoring");
- return -1;
- }
-
- pay.buffer = buffer;
- if (bytes < ntohs (pay.packet->ip.ip_len))
- {
- logger (LOG_DEBUG, "truncated packet, ignoring");
- return -1;
- }
-
- bytes = ntohs (pay.packet->ip.ip_len);
-
- /* This is like our BPF filter above */
- if (pay.packet->ip.ip_p != IPPROTO_UDP || pay.packet->ip.ip_v != IPVERSION ||
- pay.packet->ip.ip_hl != sizeof (pay.packet->ip) >> 2 ||
- pay.packet->udp.uh_dport != htons (DHCP_CLIENT_PORT) ||
- bytes > (int) sizeof (struct udp_dhcp_packet) ||
- ntohs (pay.packet->udp.uh_ulen)
- != (uint16_t) (bytes - sizeof (pay.packet->ip)))
- {
- return -1;
- }
-
- if (valid_dhcp_packet (buffer) < 0)
- return -1;
-
- memcpy(data, &pay.packet->dhcp,
- bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)));
-
- return bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp));
+ long bytes;
+ union
+ {
+ unsigned char *buffer;
+ struct udp_dhcp_packet *packet;
+ } pay;
+
+ /* We don't use the given buffer, but we need to rewind the position */
+ *buffer_pos = 0;
+
+ memset (buffer, 0, iface->buffer_length);
+ bytes = read (iface->fd, buffer, iface->buffer_length);
+
+ if (bytes < 0) {
+ struct timeval tv;
+ logger (LOG_ERR, "read: %s", strerror (errno));
+ tv.tv_sec = 3;
+ tv.tv_usec = 0;
+ select (0, NULL, NULL, NULL, &tv);
+ return -1;
+ }
+
+ *buffer_len = bytes;
+ /* If it's an ARP reply, then just send it back */
+ if (iface->socket_protocol == ETH_P_ARP) {
+ memcpy (data, buffer, bytes);
+ return bytes;
+ }
+
+ if ((unsigned) bytes < (sizeof (struct ip) + sizeof (struct udphdr))) {
+ logger (LOG_DEBUG, "message too short, ignoring");
+ return -1;
+ }
+
+ pay.buffer = buffer;
+ if (bytes < ntohs (pay.packet->ip.ip_len)) {
+ logger (LOG_DEBUG, "truncated packet, ignoring");
+ return -1;
+ }
+
+ bytes = ntohs (pay.packet->ip.ip_len);
+
+ /* This is like our BPF filter above */
+ if (pay.packet->ip.ip_p != IPPROTO_UDP || pay.packet->ip.ip_v != IPVERSION ||
+ pay.packet->ip.ip_hl != sizeof (pay.packet->ip) >> 2 ||
+ pay.packet->udp.uh_dport != htons (DHCP_CLIENT_PORT) ||
+ bytes > (int) sizeof (struct udp_dhcp_packet) ||
+ ntohs (pay.packet->udp.uh_ulen)
+ != (uint16_t) (bytes - sizeof (pay.packet->ip)))
+ {
+ return -1;
+ }
+
+ if (valid_dhcp_packet (buffer) < 0)
+ return -1;
+
+ memcpy(data, &pay.packet->dhcp,
+ bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)));
+
+ return bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp));
}
#else
#include "interface.h"
void make_dhcp_packet(struct udp_dhcp_packet *packet,
- const unsigned char *data, int length,
- struct in_addr source, struct in_addr dest);
+ const unsigned char *data, int length,
+ struct in_addr source, struct in_addr dest);
int open_socket (interface_t *iface, bool arp);
int send_packet (const interface_t *iface, int type,
- const unsigned char *data, int len);
+ const unsigned char *data, int len);
int get_packet (const interface_t *iface, unsigned char *data,
- unsigned char *buffer, int *buffer_len, int *buffer_pos);
+ unsigned char *buffer, int *buffer_len, int *buffer_pos);
#endif