summaryrefslogtreecommitdiff
path: root/trans
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-12-08 23:48:30 +0000
committerRoland McGrath <roland@gnu.org>2002-12-08 23:48:30 +0000
commit18c73715b596af1481c71d680d36723ba6161670 (patch)
tree1cd649b1b6944fdd5322b8eceeca8fa755918c63 /trans
parentae455be78fd2b49048608af72e1547adef57d204 (diff)
2002-12-08 Roland McGrath <roland@frob.com>
* pump.c: File removed.
Diffstat (limited to 'trans')
-rw-r--r--trans/pump.c1876
1 files changed, 0 insertions, 1876 deletions
diff --git a/trans/pump.c b/trans/pump.c
deleted file mode 100644
index f9cf5586..00000000
--- a/trans/pump.c
+++ /dev/null
@@ -1,1876 +0,0 @@
-/* Initialize an Ethernet interface
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
- Written by Thomas Bushnell, BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-/*
- * Copyright 1999 Red Hat Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* This probably doesn't work on anything other then Ethernet! It may work
- on PLIP as well, but ARCnet and Token Ring are unlikely at best. */
-
-#define DHCP_FLAG_NODAEMON (1 << 0)
-#define DHCP_FLAG_NOCONFIG (1 << 1)
-#define DHCP_FLAG_FORCEHNLOOKUP (1 << 2)
-
-#define RESULT_OKAY 0
-#define RESULT_FAILED 1
-#define RESULT_UNKNOWNIFACE 2
-
-#define N_(foo) (foo)
-
-#define PROGNAME "pump"
-#define CONTROLSOCKET "/var/run/pump.sock"
-
-#define _(foo) ((foo))
-#include <stdarg.h>
-
-void logMessage(char * mess, ...) {
- va_list args;
-
- va_start(args, mess);
- vprintf(mess, args);
- va_end(args);
- puts("");
-}
-
-typedef int bp_int32;
-typedef short bp_int16;
-
-#define BOOTP_OPTION_NETMASK 1
-#define BOOTP_OPTION_GATEWAY 3
-#define BOOTP_OPTION_DNS 6
-#define BOOTP_OPTION_HOSTNAME 12
-#define BOOTP_OPTION_BOOTFILE 13
-#define BOOTP_OPTION_DOMAIN 15
-#define BOOTP_OPTION_BROADCAST 28
-
-#define DHCP_OPTION_REQADDR 50
-#define DHCP_OPTION_LEASE 51
-#define DHCP_OPTION_OVERLOAD 52
-#define DHCP_OPTION_TYPE 53
-#define DHCP_OPTION_SERVER 54
-#define DHCP_OPTION_OPTIONREQ 55
-#define DHCP_OPTION_MAXSIZE 57
-#define DHCP_OPTION_T1 58
-
-#define BOOTP_CLIENT_PORT 68
-#define BOOTP_SERVER_PORT 67
-
-#define BOOTP_OPCODE_REQUEST 1
-#define BOOTP_OPCODE_REPLY 2
-
-#define NORESPONSE -10
-#define DHCP_TYPE_DISCOVER 1
-#define DHCP_TYPE_OFFER 2
-#define DHCP_TYPE_REQUEST 3
-#define DHCP_TYPE_DECLINE 4
-#define DHCP_TYPE_ACK 5
-#define DHCP_TYPE_NAK 6
-#define DHCP_TYPE_RELEASE 7
-#define DHCP_TYPE_INFORM 8
-
-#define BOOTP_VENDOR_LENGTH 64
-#define DHCP_VENDOR_LENGTH 312
-
-struct bootpRequest {
- char opcode;
- char hw;
- char hwlength;
- char hopcount;
- bp_int32 id;
- bp_int16 secs;
- bp_int16 flags;
- bp_int32 ciaddr, yiaddr, server_ip, bootp_gw_ip;
- char hwaddr[16];
- char servername[64];
- char bootfile[128];
- char vendor[DHCP_VENDOR_LENGTH];
-} ;
-
-struct psuedohUdpHeader {
- bp_int32 source, dest;
- char zero;
- char protocol;
- bp_int16 len;
-};
-
-struct command {
- enum { CMD_STARTIFACE, CMD_RESULT, CMD_DIE, CMD_STOPIFACE,
- CMD_FORCERENEW, CMD_REQSTATUS, CMD_STATUS } type;
- union {
- struct {
- char device[20];
- int flags;
- int reqLease; /* in hours */
- char reqHostname[200];
- } start;
- int result; /* 0 for success */
- struct {
- char device[20];
- } stop;
- struct {
- char device[20];
- } renew;
- struct {
- char device[20];
- } reqstatus;
- struct {
- struct intfInfo intf;
- char hostname[1024];
- char domain[1024];
- char bootFile[1024];
- } status;
- } u;
-};
-
-static char * doDhcp(char * device, int flags, int lease,
- char * reqHostname, struct intfInfo * intf,
- struct overrideInfo * override);
-
-static const char vendCookie[] = { 99, 130, 83, 99, 255 };
-
-static char * perrorstr(char * msg);
-static char * setupInterface(struct intfInfo * intf, int s);
-static char * prepareInterface(struct intfInfo * intf, int s);
-static char * getInterfaceInfo(struct intfInfo * intf, int s);
-static char * disableInterface(char * device);
-static void parseReply(struct bootpRequest * breq, struct intfInfo * intf);
-static char * prepareRequest(struct bootpRequest * breq,
- int sock, char * device, time_t startTime);
-static void parseLease(struct bootpRequest * bresp, struct intfInfo * intf);
-static void initVendorCodes(struct bootpRequest * breq);
-static char * handleTransaction(int s, struct overrideInfo * override,
- struct bootpRequest * breq,
- struct bootpRequest * bresp,
- struct sockaddr_in * serverAddr,
- struct sockaddr_in * respondant,
- int useBootPacket, int dhcpResponseType);
-static int dhcpMessageType(struct bootpRequest * response);
-static void setMissingIpInfo(struct intfInfo * intf);
-static int openControlSocket(char * configFile);
-static int dhcpRenew(struct intfInfo * intf);
-static int dhcpRelease(struct intfInfo * intf);
-
-/* Various hurd-specific decls here */
-#define _HURD_PFINET _HURD "pfinet"
-io_t underlying_pfinet;
-device_t ethernet_device;
-char ethernet_address[ETH_ALEN];
-
-
-/* Open the ethernet device */
-char *
-prepareInterface (struct intfInfo *intf, int s);
-{
- u_int count;
- int addr[2];
-
- err = device_open (master_device, D_WRITE|D_READ,
- intf->device, &ethernet_device);
- if (err)
- return err;
-
- err = device_get_status (ethernet_device, NET_ADDRESS, addr, &count);
- if (err)
- return err;
-
- addr[0] = ntohl (addr[0]);
- addr[1] = ntohl (addr[1]);
- bcopy (addr, ethernet_address, ETH_ALEN);
- return 0;
-}
-
-/* Open the node underlying the pfinet translator, and set
- underlying_pfinet to a port to that file. */
-error_t
-open_underlying_pfinet ()
-{
- char *path;
-
- if (underlying_pfinet != MACH_PORT_NULL)
- return 0;
-
- asprintf (&path, "%s/%d", _SERVERS_SOCKET, PF_INET);
-
- underlying_pfinet = file_name_lookup (path, O_NOTRANS, 0);
- free (path);
- return underlying_pfinet == MACH_PORT_NULL ? errno : 0;
-}
-
-/* Start pfinet with the specified arguments */
-error_t
-start_pfinet (char *argz, int argz_len)
-{
- error_t open_function (int flags,
- mach_port_t *underlying,
- mach_msg_type_name_t *underlying_type,
- task_t task, void *cookie)
- {
- int err;
-
- err = open_underlying_pfinet ();
- if (err)
- return err;
-
- *underlying = underlying_pfinet;
- *underlying_type = MACH_MSG_TYPE_COPY_SEND;
- return 0;
- }
-
- err = fshelp_start_translator (open_function, NULL,
- _HURD_PFINET, argz, argz_len,
- 60 * 1000, &control);
- if (err)
- return err;
-
- err = file_set_translator (underlying_pfinet,
- 0, FS_TRANS_SET,
- FSYS_GOAWAY_FORCE,
- argz, argz_len,
- control, MACH_MSG_TYPE_COPY_SEND);
- mach_port_deallocate (mach_task_self (), control);
-
- /* Force the C library to forget about any old cached server
- access port. */
- _hurd_socket_server (PFINET, 1);
-}
-
-
-
-int newKernel(void) {
-#ifdef NOTHURD
- struct utsname ubuf;
- int major1, major2;
-
- uname(&ubuf);
- if (!strcasecmp(ubuf.sysname, "linux")) {
- if (sscanf(ubuf.release, "%d.%d", &major1, &major2) != 2 ||
- (major1 < 2) || (major1 == 2 && major2 == 0)) {
- return 0;
- }
- }
-#endif
-
- return 1;
-}
-
-static char * disableInterface(char * device) {
-#ifdef NOTHURD
- struct ifreq req;
- int s;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
-
- strcpy(req.ifr_name, device);
- if (ioctl(s, SIOCGIFFLAGS, &req)) {
- close(s);
- return perrorstr("SIOCGIFFLAGS");
- }
-
- req.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
- if (ioctl(s, SIOCSIFFLAGS, &req)) {
- close(s);
- return perrorstr("SIOCSIFFLAGS");
- }
-
- close(s);
-
- return NULL;
-#else
- error_t err;
-
- err = open_underlying_pfinet ();
- if (err)
- return strerror (err);
-
- err = file_set_translator (underlying_pfinet,
- 0, FS_TRANS_SET | FS_TRANS_FORCE,
- FSYS_GOAWAY_FORCE,
- 0, 0, MACH_PORT_NULL);
- return err ? strerror (err) : 0;
-#endif
-}
-
-static char * setupInterface(struct intfInfo * intf, int s) {
- char * rc;
- char * s;
- char * argz = 0;
- int argz_len = 0;
-
- /* Construct the args to pfinet. */
- /* /hurd/pfinet */
- argz_add (&argz, &argz_len, _HURD_PFINET);
-
- /* Interface name */
- asprintf (&s, "--interface=%s", intf->decive);
- argz_add (&argz, &argz_len, s);
- free (s);
-
- /* Address */
- asprintf (&s, "--address=%s", inet_ntoa (intf->ip));
- argz_add (&argz, &argz_len, s);
- free (s);
-
- /* Netmask */
- asprintf (&s, "--netmask=%s", inet_ntoa (intf->netmask));
- argz_add (&argz, &argz_len, s);
- free (s);
-
- /* Gateway */
- asprintf (&s, "--gateway=%s", inet_ntoa (intf->gateway));
- argz_add (&argz, &argz_len, s);
- free (s);
-
- /* Now set it up */
- err = start_pfinet (argz, argz_len);
- free (argz);
-
- return err ? strerror (err) : 0;
-
-
-#ifdef NOTHURD
- struct sockaddr_in * addrp;
- struct ifreq req;
- struct rtentry route;
-
- if ((rc = disableInterface(intf->device))) return rc;
-
- /* we have to have basic information to get this far */
- addrp = (struct sockaddr_in *) &req.ifr_addr;
- addrp->sin_family = AF_INET;
- strcpy(req.ifr_name, intf->device);
-
- addrp->sin_addr = intf->ip;
- if (ioctl(s, SIOCSIFADDR, &req))
- return perrorstr("SIOCSIFADDR");
-
- addrp->sin_addr = intf->netmask;
- if (ioctl(s, SIOCSIFNETMASK, &req))
- return perrorstr("SIOCSIFNETMASK");
-
- addrp->sin_addr = intf->broadcast;
- if (ioctl(s, SIOCSIFBRDADDR, &req))
- return perrorstr("SIOCSIFBRDADDR");
-
- /* bring up the device, and specifically allow broadcasts through it */
- req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST;
- if (ioctl(s, SIOCSIFFLAGS, &req))
- return perrorstr("SIOCSIFFLAGS");
-
- /* add a route for this network */
- route.rt_dev = intf->device;
- route.rt_flags = RTF_UP;
- route.rt_metric = 0;
-
- if (!newKernel()) {
- addrp->sin_family = AF_INET;
- addrp->sin_port = 0;
- addrp->sin_addr = intf->network;
- memcpy(&route.rt_dst, addrp, sizeof(*addrp));
- addrp->sin_addr = intf->netmask;
- memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
-
- if (ioctl(s, SIOCADDRT, &route)) {
- /* the route cannot already exist, as we've taken the device down */
- return perrorstr("SIOCADDRT 1");
- }
- }
- return NULL;
-}
-
-#ifdef NOTHURD
-static char * setupDefaultGateway(struct in_addr * gw, int s) {
- struct sockaddr_in addr;
- struct rtentry route;
-
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.s_addr = INADDR_ANY;
- memcpy(&route.rt_dst, &addr, sizeof(addr));
- memcpy(&route.rt_genmask, &addr, sizeof(addr));
- addr.sin_addr = *gw;
- memcpy(&route.rt_gateway, &addr, sizeof(addr));
-
- route.rt_flags = RTF_UP | RTF_GATEWAY;
- route.rt_metric = 0;
- route.rt_dev = NULL;
-
- if (ioctl(s, SIOCADDRT, &route)) {
- /* the route cannot already exist, as we've taken the device
- down */
- return perrorstr("SIOCADDRT 2");
- }
-
- return NULL;
-}
-
-static char * getInterfaceInfo(struct intfInfo * intf, int s) {
- struct ifreq req;
- struct sockaddr_in * addrp;
-
- strcpy(req.ifr_name, intf->device);
- if (ioctl(s, SIOCGIFBRDADDR, &req))
- return perrorstr("SIOCGIFBRDADDR");
-
- addrp = (struct sockaddr_in *) &req.ifr_addr;
- intf->broadcast = addrp->sin_addr;
- intf->set = INTFINFO_HAS_BROADCAST;
-
- return NULL;
-}
-
-static char * prepareInterface(struct intfInfo * intf, int s) {
- struct sockaddr_in * addrp;
- struct ifreq req;
- struct rtentry route;
-
- addrp = (struct sockaddr_in *) &req.ifr_addr;
-
- strcpy(req.ifr_name, intf->device);
- addrp->sin_family = AF_INET;
- addrp->sin_port = 0;
- memset(&addrp->sin_addr, 0, sizeof(addrp->sin_addr));
-
- addrp->sin_family = AF_INET;
- addrp->sin_addr.s_addr = htonl(0);
-
- if (ioctl(s, SIOCSIFADDR, &req))
- return perrorstr("SIOCSIFADDR");
-
- if (!newKernel()) {
- if (ioctl(s, SIOCSIFNETMASK, &req))
- return perrorstr("SIOCSIFNETMASK");
-
- /* the broadcast address is 255.255.255.255 */
- memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
- if (ioctl(s, SIOCSIFBRDADDR, &req))
- return perrorstr("SIOCSIFBRDADDR");
- }
-
- req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
- if (ioctl(s, SIOCSIFFLAGS, &req))
- return perrorstr("SIOCSIFFLAGS");
-
- memset(&route, 0, sizeof(route));
- memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
-
- addrp->sin_family = AF_INET;
- addrp->sin_port = 0;
- addrp->sin_addr.s_addr = INADDR_ANY;
- memcpy(&route.rt_dst, addrp, sizeof(*addrp));
- memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
-
- route.rt_dev = intf->device;
- route.rt_flags = RTF_UP;
- route.rt_metric = 0;
-
- if (ioctl(s, SIOCADDRT, &route)) {
- if (errno != EEXIST) {
- close(s);
- return perrorstr("SIOCADDRT 3");
- }
- }
-
- return NULL;
-}
-#endif
-
-static int dhcpMessageType(struct bootpRequest * response) {
- unsigned char * chptr;
- unsigned char option, length;
-
- chptr = response->vendor;
-
- chptr += 4;
- while (*chptr != 0xFF) {
- option = *chptr++;
- if (!option) continue;
- length = *chptr++;
- if (option == DHCP_OPTION_TYPE)
- return *chptr;
-
- chptr += length;
- }
-
- return -1;
-}
-
-static void setMissingIpInfo(struct intfInfo * intf) {
- bp_int32 ipNum = *((bp_int32 *) &intf->ip);
- bp_int32 nmNum = *((bp_int32 *) &intf->netmask);
- bp_int32 ipRealNum = ntohl(ipNum);
-
- if (!(intf->set & INTFINFO_HAS_NETMASK)) {
- if (((ipRealNum & 0xFF000000) >> 24) <= 127)
- nmNum = 0xFF000000;
- else if (((ipRealNum & 0xFF000000) >> 24) <= 191)
- nmNum = 0xFFFF0000;
- else
- nmNum = 0xFFFFFF00;
- *((bp_int32 *) &intf->netmask) = nmNum = htonl(nmNum);
- syslog (LOG_DEBUG, "intf: netmask: %s", inet_ntoa (intf->netmask));
- }
-
- if (!(intf->set & INTFINFO_HAS_BROADCAST)) {
- *((bp_int32 *) &intf->broadcast) = (ipNum & nmNum) | ~(nmNum);
- syslog (LOG_DEBUG, "intf: broadcast: %s", inet_ntoa (intf->broadcast));
- }
-
- if (!(intf->set & INTFINFO_HAS_NETWORK)) {
- *((bp_int32 *) &intf->network) = ipNum & nmNum;
- syslog (LOG_DEBUG, "intf: network: %s", inet_ntoa (intf->network));
- }
-
- intf->set |= INTFINFO_HAS_BROADCAST | INTFINFO_HAS_NETWORK |
- INTFINFO_HAS_NETMASK;
-}
-
-static void parseReply(struct bootpRequest * breq, struct intfInfo * intf) {
- unsigned int i;
- unsigned char * chptr;
- unsigned char option, length;
-
- syslog (LOG_DEBUG, "intf: device: %s", intf->device);
- syslog (LOG_DEBUG, "intf: set: %i", intf->set);
- syslog (LOG_DEBUG, "intf: bootServer: %s", inet_ntoa (intf->bootServer));
- syslog (LOG_DEBUG, "intf: reqLease: %i", intf->reqLease);
-
- i = ~(INTFINFO_HAS_IP | INTFINFO_HAS_NETMASK | INTFINFO_HAS_NETWORK |
- INTFINFO_HAS_BROADCAST);
- intf->set &= i;
-
- if (strlen(breq->bootfile)) {
- intf->bootFile = strdup(breq->bootfile);
- intf->set |= INTFINFO_HAS_BOOTFILE;
- } else {
- intf->set &= ~INTFINFO_HAS_BOOTFILE;
- }
- syslog (LOG_DEBUG, "intf: bootFile: %s", intf->bootFile);
-
- memcpy(&intf->ip, &breq->yiaddr, 4);
- intf->set |= INTFINFO_HAS_IP;
- syslog (LOG_DEBUG, "intf: ip: %s", inet_ntoa (intf->ip));
-
- chptr = breq->vendor;
- chptr += 4;
- while (*chptr != 0xFF && (void *) chptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH) {
- option = *chptr++;
- if (!option) continue;
- length = *chptr++;
-
- switch (option) {
- case BOOTP_OPTION_DNS:
- intf->numDns = 0;
- for (i = 0; i < length; i += 4) {
- if (intf->numDns < MAX_DNS_SERVERS) {
- memcpy(&intf->dnsServers[intf->numDns++], chptr + i, 4);
- syslog(LOG_DEBUG, "intf: dnsServers[%i]: %s",
- i/4, inet_ntoa (intf->dnsServers[i/4]));
- }
- }
- intf->set |= NETINFO_HAS_DNS;
- syslog (LOG_DEBUG, "intf: numDns: %i", intf->numDns);
- break;
-
- case BOOTP_OPTION_NETMASK:
- memcpy(&intf->netmask, chptr, 4);
- intf->set |= INTFINFO_HAS_NETMASK;
- syslog (LOG_DEBUG, "intf: netmask: %s", inet_ntoa (intf->netmask));
- break;
-
- case BOOTP_OPTION_DOMAIN:
- if ((intf->domain = malloc(length + 1))) {
- memcpy(intf->domain, chptr, length);
- intf->domain[length] = '\0';
- intf->set |= NETINFO_HAS_DOMAIN;
- syslog (LOG_DEBUG, "intf: domain: %s", intf->domain);
- }
- break;
-
- case BOOTP_OPTION_BROADCAST:
- memcpy(&intf->broadcast, chptr, 4);
- intf->set |= INTFINFO_HAS_BROADCAST;
- syslog (LOG_DEBUG, "intf: broadcast: %s", inet_ntoa (intf->broadcast));
- break;
-
- case BOOTP_OPTION_GATEWAY:
- memcpy(&intf->gateway, chptr, 4);
- intf->set |= NETINFO_HAS_GATEWAY;
- syslog (LOG_DEBUG, "intf: gateway: %s", inet_ntoa (intf->gateway));
- break;
-
- case BOOTP_OPTION_HOSTNAME:
- if ((intf->hostname = malloc(length + 1))) {
- memcpy(intf->hostname, chptr, length);
- intf->hostname[length] = '\0';
- intf->set |= NETINFO_HAS_HOSTNAME;
- syslog (LOG_DEBUG, "intf: hostname: %s", intf->hostname);
- }
- break;
-
- case BOOTP_OPTION_BOOTFILE:
- /* we ignore this right now */
- break;
-
- case DHCP_OPTION_OVERLOAD:
- /* FIXME: we should pay attention to this */
- logMessage("dhcp overload option is currently ignored!");
- break;
- }
-
- chptr += length;
- }
-
- setMissingIpInfo(intf);
-}
-
-static char * perrorstr(char * msg) {
- static char * err = NULL;
- static int errsize = 0;
- static int newsize;
-
- newsize = strlen(msg) + strlen(strerror(errno)) + 3;
- if (!errsize) {
- errsize = newsize;
- err = malloc(errsize);
- } else if (errsize < newsize) {
- free(err);
- errsize = newsize;
- err = malloc(errsize);
- }
-
- if (err)
- sprintf(err, "%s: %s", msg, strerror(errno));
- else
- err = "out of memory!";
-
- return err;
-}
-
-static void initVendorCodes(struct bootpRequest * breq) {
- memcpy(breq->vendor, vendCookie, sizeof(vendCookie));
-}
-
-static char * prepareRequest(struct bootpRequest * breq,
- int sock, char * device, time_t startTime) {
-#ifdef NOTHURD
- struct ifreq req;
-#endif
- int i;
-
- memset(breq, 0, sizeof(*breq));
-
- breq->opcode = BOOTP_OPCODE_REQUEST;
-
-#ifdef NOTHURD
- strcpy(req.ifr_name, device);
- if (ioctl(sock, SIOCGIFHWADDR, &req))
- return perrorstr("SIOCSIFHWADDR");
-
- breq->hw = 1; /* ethernet */
- breq->hwlength = IFHWADDRLEN;
- memcpy(breq->hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
-#else
- breq->hw = 1; /* ethernet */
- breq->hwlength = IFHWADDRLEN;
- memcpy(breq->hwaddr, ethernet_address, IFHWADDRLEN);
-#endif
-
- /* we should use something random here, but I don't want to start using
- stuff from the math library */
- breq->id = time(NULL);
- for (i = 0; i < IFHWADDRLEN; i++)
- breq->id ^= breq->hwaddr[i] << (8 * (i % 4));
-
- breq->hopcount = 0;
- breq->secs = time(NULL) - startTime;
-
- initVendorCodes(breq);
-
- return NULL;
-}
-
-static unsigned int verifyChecksum(void * buf, int length, void * buf2,
- int length2) {
- unsigned int csum;
- unsigned short * sp;
-
- csum = 0;
- for (sp = (unsigned short *) buf; length > 0; (length -= 2), sp++)
- csum += *sp;
-
- /* this matches rfc 1071, but not Steven's */
- if (length)
- csum += *((unsigned char *) sp);
-
- for (sp = (unsigned short *) buf2; length2 > 0; (length2 -= 2), sp++)
- csum += *sp;
-
- /* this matches rfc 1071, but not Steven's */
- if (length)
- csum += *((unsigned char *) sp);
-
- while (csum >> 16)
- csum = (csum & 0xffff) + (csum >> 16);
-
- if (csum!=0x0000 && csum != 0xffff) return 0; else return 1;
-}
-
-void debugbootpRequest(char *name, struct bootpRequest *breq) {
- char vendor[28], vendor2[28];
- int i;
- struct in_addr address;
- unsigned char *vndptr;
- unsigned char option, length;
-
- syslog (LOG_DEBUG, "%s: opcode: %i", name, breq->opcode);
- syslog (LOG_DEBUG, "%s: hw: %i", name, breq->hw);
- syslog (LOG_DEBUG, "%s: hwlength: %i", name, breq->hwlength);
- syslog (LOG_DEBUG, "%s: hopcount: %i", name, breq->hopcount);
- syslog (LOG_DEBUG, "%s: id: 0x%8x", name, breq->id);
- syslog (LOG_DEBUG, "%s: secs: %i", name, breq->secs);
- syslog (LOG_DEBUG, "%s: flags: 0x%4x", name, breq->flags);
-
- address.s_addr = breq->ciaddr;
- syslog (LOG_DEBUG, "%s: ciaddr: %s", name, inet_ntoa (address));
-
- address.s_addr = breq->yiaddr;
- syslog (LOG_DEBUG, "%s: yiaddr: %s", name, inet_ntoa (address));
-
- address.s_addr = breq->server_ip;
- syslog (LOG_DEBUG, "%s: server_ip: %s", name, inet_ntoa (address));
-
- address.s_addr = breq->bootp_gw_ip;
- syslog (LOG_DEBUG, "%s: bootp_gw_ip: %s", name, inet_ntoa (address));
-
- syslog (LOG_DEBUG, "%s: hwaddr: %s", name, breq->hwaddr);
- syslog (LOG_DEBUG, "%s: servername: %s", name, breq->servername);
- syslog (LOG_DEBUG, "%s: bootfile: %s", name, breq->bootfile);
-
- vndptr = breq->vendor;
- sprintf (vendor, "0x%2x 0x%2x 0x%2x 0x%2x", *vndptr++, *vndptr++, *vndptr++, *vndptr++);
- syslog (LOG_DEBUG, "%s: vendor: %s", name, vendor);
-
-
- for (; (void *) vndptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH;)
- {
- option = *vndptr++;
- if (option == 0xFF)
- {
- sprintf (vendor, "0x%2x", option);
- vndptr = breq->vendor + DHCP_VENDOR_LENGTH;
- }
- else if (option == 0x00)
- {
- for (i = 1; *vndptr == 0x00; i++, vndptr++);
- sprintf (vendor, "0x%2x x %i", option, i);
- }
- else
- {
- length = *vndptr++;
- sprintf (vendor, "%3u %3u", option, length);
- for (i = 0; i < length; i++)
- {
- if (strlen (vendor) > 22)
- {
- syslog (LOG_DEBUG, "%s: vendor: %s", name, vendor);
- strcpy (vendor, "++++++");
- }
- snprintf (vendor2, 27, "%s 0x%2x", vendor, *vndptr++);
- strcpy (vendor, vendor2);
-
- }
- }
-
- syslog (LOG_DEBUG, "%s: vendor: %s", name, vendor);
- }
-
- return;
-
-}
-
-static char * handleTransaction(int s, struct overrideInfo * override,
- struct bootpRequest * breq,
- struct bootpRequest * bresp,
- struct sockaddr_in * serverAddr,
- struct sockaddr_in * respondant,
- int useBootpPacket, int dhcpResponseType) {
- struct timeval tv;
- fd_set readfs;
- int i, j;
- struct sockaddr_pkt tmpAddress;
- int gotit = 0;
- int tries;
- int nextTimeout = 2;
- time_t timeoutTime;
- int sin;
- int resend = 1;
- struct ethhdr;
- char ethPacket[ETH_FRAME_LEN];
- struct iphdr * ipHdr;
- struct udphdr * udpHdr;
- struct psuedohUdpHeader pHdr;
- time_t start = time(NULL);
-
- debugbootpRequest("breq", breq);
-
- if (!override) {
- override = alloca(sizeof(*override));
- initOverride(override);
- }
-
- tries = override->numRetries + 1;
-
- sin = socket(AF_PACKET, SOCK_DGRAM, ntohs(ETH_P_IP));
- if (sin < 0) {
- return strerror(errno);
- }
-
- while (!gotit && tries) {
- i = sizeof(*breq);
- if (useBootpPacket)
- i -= (DHCP_VENDOR_LENGTH - BOOTP_VENDOR_LENGTH);
-
- if (resend) {
- if (sendto(s, breq, i, 0, (struct sockaddr *) serverAddr,
- sizeof(*serverAddr)) != i) {
- close(sin);
- return perrorstr("sendto");
- }
-
- tries--;
- nextTimeout *= 2;
-
- switch (time(NULL) & 4) {
- case 0: if (nextTimeout >= 2) nextTimeout--; break;
- case 1: nextTimeout++; break;
- }
-
- timeoutTime = time(NULL) + nextTimeout;
- i = override->timeout + start;
- if (timeoutTime > i) timeoutTime = i;
-
- resend = 0;
- }
-
- if (dhcpResponseType == NORESPONSE) {
- close(sin);
- return NULL;
- }
-
- tv.tv_usec = 0;
- tv.tv_sec = timeoutTime - time(NULL);
- if (timeoutTime < time(NULL)) {
- tries = 0;
- continue;
- }
-
- FD_ZERO(&readfs);
- FD_SET(sin, &readfs);
- switch ((select(sin + 1, &readfs, NULL, NULL, &tv))) {
- case 0:
- resend = 1;
- break;
-
- case 1:
- i = sizeof(tmpAddress);
- if ((j = recvfrom(sin, ethPacket, sizeof(ethPacket), 0,
- (struct sockaddr *) &tmpAddress, &i)) < 0)
- return perrorstr("recvfrom");
-
- /* We need to do some basic sanity checking of the header */
- if (j < (sizeof(*ipHdr) + sizeof(*udpHdr))) continue;
-
- ipHdr = (void *) ethPacket;
- if (!verifyChecksum(NULL, 0, ipHdr, sizeof(*ipHdr)))
- continue;
-
- if (ntohs(ipHdr->tot_len) > j)
- continue;
- j = ntohs(ipHdr->tot_len);
-
- if (ipHdr->protocol != IPPROTO_UDP) continue;
-
- udpHdr = (void *) (ethPacket + sizeof(*ipHdr));
- pHdr.source = ipHdr->saddr;
- pHdr.dest = ipHdr->daddr;
- pHdr.zero = 0;
- pHdr.protocol = ipHdr->protocol;
- pHdr.len = udpHdr->len;
-
-/*
- egcs bugs make this problematic
-
- if (udpHdr->check && !verifyChecksum(&pHdr, sizeof(pHdr),
- udpHdr, j - sizeof(*ipHdr)))
- continue;
-*/
-
- if (ntohs(udpHdr->source) != BOOTP_SERVER_PORT)
- continue;
- if (ntohs(udpHdr->dest) != BOOTP_CLIENT_PORT)
- continue;
- /* Go on with this packet; it looks sane */
-
- /* Originally copied sizeof (*bresp) - this is a security
- problem due to a potential underflow of the source
- buffer. Also, it trusted that the packet was properly
- 0xFF terminated, which is not true in the case of the
- DHCP server on Cisco 800 series ISDN router. */
-
- memset (bresp, 0xFF, sizeof (*bresp));
- memcpy (bresp, (char *) udpHdr + sizeof (*udpHdr), j - sizeof (*ipHdr) - sizeof (*udpHdr));
-
- /* sanity checks */
- if (bresp->id != breq->id) continue;
- if (bresp->opcode != BOOTP_OPCODE_REPLY) continue;
- if (bresp->hwlength != breq->hwlength) continue;
- if (memcmp(bresp->hwaddr, breq->hwaddr, bresp->hwlength)) continue;
- i = dhcpMessageType(bresp);
- if (!(i == -1 && useBootpPacket) && (i != dhcpResponseType))
- continue;
- if (memcmp(bresp->vendor, vendCookie, 4)) continue;
- /* if (respondant) *respondant = tmpAddress; */
- gotit = 1;
-
- break;
-
- default:
- close(sin);
- return perrorstr("select");
- }
- }
-
- if (!gotit) {
- close(sin);
- return _("No DHCP reply received");
- }
-
- close(sin);
-
- debugbootpRequest("bresp", bresp);
-
- return NULL;
-}
-
-static void addVendorCode(struct bootpRequest * breq, unsigned char option,
- unsigned char length, void * data) {
- unsigned char * chptr;
- int theOption, theLength;
-
- chptr = breq->vendor;
- chptr += 4;
- while (*chptr != 0xFF && *chptr != option) {
- theOption = *chptr++;
- if (!theOption) continue;
- theLength = *chptr++;
- chptr += theLength;
- }
-
- *chptr++ = option;
- *chptr++ = length;
- memcpy(chptr, data, length);
- chptr[length] = 0xff;
-}
-
-static int getVendorCode(struct bootpRequest * bresp, unsigned char option,
- void * data) {
- unsigned char * chptr;
- unsigned int length, theOption;
-
- chptr = bresp->vendor;
- chptr += 4;
- while (*chptr != 0xFF && *chptr != option) {
- theOption = *chptr++;
- if (!theOption) continue;
- length = *chptr++;
- chptr += length;
- }
-
- if (*chptr++ == 0xff) return 1;
-
- length = *chptr++;
- memcpy(data, chptr, length);
-
- return 0;
-}
-
-static int createSocket(void) {
- struct sockaddr_in clientAddr;
- int s;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0)
- return -1;
-
- memset(&clientAddr.sin_addr, 0, sizeof(&clientAddr.sin_addr));
- clientAddr.sin_family = AF_INET;
- clientAddr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */
-
- if (bind(s, (struct sockaddr *) &clientAddr, sizeof(clientAddr))) {
- close(s);
- return -1;
- }
-
- return s;
-}
-
-static int dhcpRelease(struct intfInfo * intf) {
- struct bootpRequest breq, bresp;
- unsigned char messageType;
- struct sockaddr_in serverAddr;
- char * chptr;
- int s;
-
- if (!(intf->set & INTFINFO_HAS_LEASE)) {
- disableInterface(intf->device);
- syslog(LOG_INFO, "disabling interface %s", intf->device);
-
- return 0;
- }
-
- if ((s = createSocket()) < 0) return 1;
-
- if ((chptr = prepareRequest(&breq, s, intf->device, time(NULL)))) {
- close(s);
- while (1) {
- disableInterface(intf->device);
- return 0;
- }
- }
-
- messageType = DHCP_TYPE_RELEASE;
- addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
- memcpy(&breq.ciaddr, &intf->ip, sizeof(breq.ciaddr));
-
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
- serverAddr.sin_addr = intf->bootServer;
-
- if (!handleTransaction(s, NULL, &breq, &bresp, &serverAddr, NULL, 0,
- NORESPONSE)) {
- disableInterface(intf->device);
- close(s);
- return 0;
- }
-
- disableInterface(intf->device);
- close(s);
-
- syslog(LOG_INFO, "disabling interface %s", intf->device);
-
- return 1;
-}
-
-/* This is somewhat broken. We try only to renew the lease. If we fail,
- we don't try to completely rebind. This doesn't follow the DHCP spec,
- but for the install it should be a reasonable compromise. */
-static int dhcpRenew(struct intfInfo * intf) {
- struct bootpRequest breq, bresp;
- unsigned char messageType;
- struct sockaddr_in serverAddr;
- char * chptr;
- int s;
- int i;
-
- s = createSocket();
-
- if ((chptr = prepareRequest(&breq, s, intf->device, time(NULL)))) {
- close(s);
- while (1); /* problem */
- }
-
- messageType = DHCP_TYPE_REQUEST;
- addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
- memcpy(&breq.ciaddr, &intf->ip, sizeof(breq.ciaddr));
-
- i = htonl(intf->reqLease);
- addVendorCode(&breq, DHCP_OPTION_LEASE, 4, &i);
-
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
- serverAddr.sin_addr = intf->bootServer;
-
- if (handleTransaction(s, NULL, &breq, &bresp, &serverAddr, NULL, 0,
- DHCP_TYPE_ACK)) {
- close(s);
- return 1;
- }
-
- parseLease(&bresp, intf);
-
- syslog(LOG_INFO, "renewed lease for interface %s", intf->device);
-
- close(s);
- return 0;
-}
-
-static void parseLease(struct bootpRequest * bresp, struct intfInfo * intf) {
- int lease;
- time_t now;
-
- intf->set &= INTFINFO_HAS_LEASE;
- if (getVendorCode(bresp, DHCP_OPTION_LEASE, &lease))
- return;
-
- lease = ntohl(lease);
-
- if (lease && lease != 0xffffffff) {
- now = time(NULL);
- intf->set |= INTFINFO_HAS_LEASE;
- intf->leaseExpiration = now + lease;
- intf->renewAt = now + (7 * lease / 8);
- }
-}
-
-char * readSearchPath(void) {
- int fd;
- struct stat sb;
- char * buf;
- char * start;
-
- fd = open("/etc/resolv.conf", O_RDONLY);
- if (fd < 0) return NULL;
-
- fstat(fd, &sb);
- buf = alloca(sb.st_size + 2);
- if (read(fd, buf, sb.st_size) != sb.st_size) return NULL;
- buf[sb.st_size] = '\n';
- buf[sb.st_size + 1] = '\0';
- close(fd);
-
- start = buf;
- while (start && *start) {
- while (isspace(*start) && (*start != '\n')) start++;
- if (*start == '\n') {
- start++;
- continue;
- }
-
- if (!strncmp("search", start, 6) && isspace(start[6])) {
- start += 6;
- while (isspace(*start) && *start != '\n') start++;
- if (*start == '\n') return NULL;
-
- buf = strchr(start, '\n');
- *buf = '\0';
- return strdup(start);
- }
- }
-
- return NULL;
-}
-
-static void createResolvConf(struct intfInfo * intf, char * domain,
- int isSearchPath) {
- FILE * f;
- int i;
- char * chptr;
-
- /* force a reread of /etc/resolv.conf if we need it again */
- res_close();
-
- if (!domain) {
- domain = readSearchPath();
- if (domain) {
- chptr = alloca(strlen(domain) + 1);
- strcpy(chptr, domain);
- free(domain);
- domain = chptr;
- isSearchPath = 1;
- }
- }
-
- f = fopen("/etc/resolv.conf", "w");
- if (!f) {
- syslog(LOG_ERR, "cannot create /etc/resolv.conf: %s\n",
- strerror(errno));
- return;
- }
-
- if (domain && isSearchPath) {
- fprintf(f, "search %s\n", domain);
- } else if (domain) {
- fprintf(f, "search");
- chptr = domain;
- do {
- fprintf(f, " %s", chptr);
- chptr = strchr(chptr, '.');
- if (chptr) {
- chptr++;
- if (!strchr(chptr, '.'))
- chptr = NULL;
- }
- } while (chptr);
-
- fprintf(f, "\n");
- }
-
- for (i = 0; i < intf->numDns; i++)
- fprintf(f, "nameserver %s\n", inet_ntoa(intf->dnsServers[i]));
-
- fclose(f);
-
- /* force a reread of /etc/resolv.conf */
- endhostent();
-}
-
-void setupDns(struct intfInfo * intf, struct overrideInfo * override) {
- char * hn, * dn = NULL;
- struct hostent * he;
-
- if (override->flags & OVERRIDE_FLAG_NODNS) {
- return;
- }
-
- if (override->searchPath) {
- createResolvConf(intf, override->searchPath, 1);
- return;
- }
-
- if (intf->set & NETINFO_HAS_DNS) {
- if (!(intf->set & NETINFO_HAS_DOMAIN)) {
- if (intf->set & NETINFO_HAS_HOSTNAME) {
- hn = intf->hostname;
- } else {
- createResolvConf(intf, NULL, 0);
-
- he = gethostbyaddr((char *) &intf->ip, sizeof(intf->ip),
- AF_INET);
- if (he) {
- hn = he->h_name;
- } else {
- hn = NULL;
- }
- }
-
- if (hn) {
- dn = strchr(hn, '.');
- if (dn)
- dn++;
- }
- } else {
- dn = intf->domain;
- }
-
- createResolvConf(intf, dn, 0);
- }
-}
-
-static char * doDhcp(char * device, int flags, int reqLease,
- char * reqHostname, struct intfInfo * intf,
- struct overrideInfo * override) {
- int s, i;
- struct sockaddr_in serverAddr;
- struct sockaddr_in clientAddr;
- struct sockaddr_in broadcastAddr;
- struct bootpRequest breq, bresp;
- struct bootpRequest protoReq;
- unsigned char * chptr;
- unsigned char messageType;
- time_t startTime = time(NULL);
- int true = 1;
- char optionsRequested[50];
- int numOptions;
- short aShort;
-
- memset(intf, 0, sizeof(*intf));
- strcpy(intf->device, device);
- intf->reqLease = reqLease;
- intf->set |= INTFINFO_HAS_REQLEASE;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- return perrorstr("socket");
- }
-
- if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &true, sizeof(true))) {
- close(s);
- return perrorstr("setsockopt");
- }
-
- if (flags & DHCP_FLAG_NOCONFIG) {
- if ((chptr = getInterfaceInfo(intf, s))) {
- close(s);
- return chptr;
- }
- } else if ((chptr = prepareInterface(intf, s))) {
- close(s);
- return chptr;
- }
-
- if ((chptr = prepareRequest(&breq, s, intf->device, startTime))) {
- close(s);
- disableInterface(intf->device);
- return chptr;
- }
-
- messageType = DHCP_TYPE_DISCOVER;
- addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
-
- memset(&clientAddr.sin_addr, 0, sizeof(&clientAddr.sin_addr));
- clientAddr.sin_family = AF_INET;
- clientAddr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */
-
- if (bind(s, (struct sockaddr *) &clientAddr, sizeof(clientAddr))) {
- disableInterface(intf->device);
- close(s);
- return perrorstr("bind");
- }
-
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
-
-#if 0
- /* seems like a good idea?? */
- if (intf->set & INTFINFO_HAS_BOOTSERVER)
- serverAddr.sin_addr = intf->bootServer;
-#endif
-
- broadcastAddr.sin_family = AF_INET;
- broadcastAddr.sin_port = htons(BOOTP_SERVER_PORT);
-
-#if 0
- /* this too! */
- if (intf->set & INTFINFO_HAS_BROADCAST)
- broadcastAddr.sin_addr = intf->broadcast;
-#endif
-
- memset(&broadcastAddr.sin_addr, 0xff,
- sizeof(broadcastAddr.sin_addr)); /* all 1's broadcast */
-
- syslog (LOG_DEBUG, "PUMP: sending discover\n");
-
- if ((chptr = handleTransaction(s, override, &breq, &bresp, &broadcastAddr,
- NULL, 1, DHCP_TYPE_OFFER))) {
- close(s);
- disableInterface(intf->device);
- return chptr;
- }
-
- /* Otherwise we're in the land of bootp */
- if (dhcpMessageType(&bresp) == DHCP_TYPE_OFFER) {
- /* Admittedly, this seems a bit odd. If we find a dhcp server, we
- rerun the dhcp discover broadcast, but with the proper option
- field this time. This makes me rfc compliant. */
- syslog (LOG_DEBUG, "got dhcp offer\n");
-
- initVendorCodes(&breq);
-
- aShort = ntohs(sizeof(struct bootpRequest));
- addVendorCode(&breq, DHCP_OPTION_MAXSIZE, 2, &aShort);
-
- numOptions = 0;
- optionsRequested[numOptions++] = BOOTP_OPTION_NETMASK;
- optionsRequested[numOptions++] = BOOTP_OPTION_GATEWAY;
- optionsRequested[numOptions++] = BOOTP_OPTION_DNS;
- optionsRequested[numOptions++] = BOOTP_OPTION_DOMAIN;
- optionsRequested[numOptions++] = BOOTP_OPTION_BROADCAST;
- optionsRequested[numOptions++] = BOOTP_OPTION_HOSTNAME;
- addVendorCode(&breq, DHCP_OPTION_OPTIONREQ, numOptions,
- optionsRequested);
-
- if (reqHostname) {
- syslog(LOG_DEBUG, "HOSTNAME: requesting %s\n", reqHostname);
- addVendorCode(&breq, BOOTP_OPTION_HOSTNAME, strlen(reqHostname),
- reqHostname);
- }
-
- i = htonl(intf->reqLease);
- addVendorCode(&breq, DHCP_OPTION_LEASE, 4, &i);
-
- protoReq = breq;
-
- syslog (LOG_DEBUG, "PUMP: sending second discover");
-
- messageType = DHCP_TYPE_DISCOVER;
- addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
-
- /* Send another DHCP_REQUEST with the proper option list */
- if ((chptr = handleTransaction(s, override, &breq, &bresp,
- &broadcastAddr, NULL, 1,
- DHCP_TYPE_OFFER))) {
- close(s);
- disableInterface(intf->device);
- return chptr;
- }
-
-
- if (dhcpMessageType(&bresp) != DHCP_TYPE_OFFER) {
- close(s);
- disableInterface(intf->device);
- return "dhcp offer expected";
- }
-
- syslog (LOG_DEBUG, "PUMP: got an offer");
-
- if (getVendorCode(&bresp, DHCP_OPTION_SERVER, &serverAddr.sin_addr)) {
- syslog (LOG_DEBUG, "DHCPOFFER didn't include server address");
- intf->bootServer = broadcastAddr.sin_addr;
- }
-
- breq = protoReq;
- messageType = DHCP_TYPE_REQUEST;
- addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
-
- addVendorCode(&breq, DHCP_OPTION_SERVER, 4, &serverAddr.sin_addr);
- addVendorCode(&breq, DHCP_OPTION_REQADDR, 4, &bresp.yiaddr);
-
- /* why do we need to use the broadcast address here? better reread the
- spec! */
- if ((chptr = handleTransaction(s, override, &breq, &bresp,
- &broadcastAddr, NULL, 0,
- DHCP_TYPE_ACK))) {
- close(s);
- disableInterface(intf->device);
- return chptr;
- }
-
- syslog (LOG_DEBUG, "PUMP: got lease");
-
- parseLease(&bresp, intf);
-
- if (getVendorCode(&bresp, DHCP_OPTION_SERVER, &intf->bootServer)) {
- syslog (LOG_DEBUG, "DHCPACK didn't include server address");
- intf->bootServer = broadcastAddr.sin_addr;
- }
-
- intf->set |= INTFINFO_HAS_BOOTSERVER;
- }
-
- parseReply(&bresp, intf);
- if (flags & DHCP_FLAG_FORCEHNLOOKUP)
- intf->set &= ~(NETINFO_HAS_DOMAIN | NETINFO_HAS_HOSTNAME);
-
- chptr = setupInterface(intf, s);
- if (chptr) {
- close(s);
- disableInterface(intf->device);
- return chptr;
- }
-
- syslog(LOG_INFO, "configured interface %s", intf->device);
-
- if (intf->set & NETINFO_HAS_GATEWAY) {
- chptr = setupDefaultGateway(&intf->gateway, s);
- }
-
- setupDns(intf, override);
-
- close(s);
-
- return NULL;
-}
-
-static void runDaemon(int sock, char * configFile) {
- int conn;
- struct sockaddr_un addr;
- int addrLength;
- struct command cmd;
- struct intfInfo intf[20];
- int numInterfaces = 0;
- int i;
- int closest;
- struct timeval tv;
- fd_set fds;
- struct overrideInfo * overrides = NULL;
- struct overrideInfo emptyOverride, * o;
-
- readPumpConfig(configFile, &overrides);
- if (!overrides) {
- overrides = &emptyOverride;
- overrides->intf.device[0] = '\0';
- }
-
- while (1) {
- FD_ZERO(&fds);
- FD_SET(sock, &fds);
-
- tv.tv_sec = tv.tv_usec = 0;
- closest = -1;
- if (numInterfaces) {
- for (i = 0; i < numInterfaces; i++)
- if ((intf[i].set & INTFINFO_HAS_LEASE) &&
- (closest == -1 ||
- (intf[closest].renewAt > intf[i].renewAt)))
- closest = i;
- if (closest != -1) {
- tv.tv_sec = intf[closest].renewAt - time(NULL);
- if (tv.tv_sec <= 0) {
- dhcpRenew(intf + closest);
- continue;
- }
- }
- }
-
- if (select(sock + 1, &fds, NULL, NULL,
- closest != -1 ? &tv : NULL) > 0) {
- conn = accept(sock, &addr, &addrLength);
-
- if (read(conn, &cmd, sizeof(cmd)) != sizeof(cmd)) {
- close(conn);
- continue;
- }
-
- switch (cmd.type) {
- case CMD_DIE:
- for (i = 0; i < numInterfaces; i++)
- dhcpRelease(intf + i);
-
- syslog(LOG_INFO, "terminating at root's request");
-
- cmd.type = CMD_RESULT;
- cmd.u.result = 0;
- write(conn, &cmd, sizeof(cmd));
- exit(0);
-
- case CMD_STARTIFACE:
- o = overrides;
- while (*o->intf.device &&
- strcmp(o->intf.device, cmd.u.start.device)) {
- o++;
- }
- if (!*o->intf.device) o = overrides;
-
- if (doDhcp(cmd.u.start.device,
- cmd.u.start.flags, cmd.u.start.reqLease,
- cmd.u.start.reqHostname[0] ?
- cmd.u.start.reqHostname : NULL,
- intf + numInterfaces, o)) {
- cmd.u.result = 1;
- } else {
- cmd.u.result = 0;
- numInterfaces++;
- }
- break;
-
- case CMD_FORCERENEW:
- for (i = 0; i < numInterfaces; i++)
- if (!strcmp(intf[i].device, cmd.u.renew.device)) break;
- if (i == numInterfaces)
- cmd.u.result = RESULT_UNKNOWNIFACE;
- else
- cmd.u.result = dhcpRenew(intf + i);
- break;
-
- case CMD_STOPIFACE:
- for (i = 0; i < numInterfaces; i++)
- if (!strcmp(intf[i].device, cmd.u.stop.device)) break;
- if (i == numInterfaces)
- cmd.u.result = RESULT_UNKNOWNIFACE;
- else {
- cmd.u.result = dhcpRelease(intf + i);
- if (numInterfaces == 1) {
- cmd.type = CMD_RESULT;
- write(conn, &cmd, sizeof(cmd));
-
- syslog(LOG_INFO, "terminating as there are no "
- "more devices under management");
-
- exit(0);
- }
-
- intf[i] = intf[numInterfaces - 1];
- numInterfaces--;
- }
- break;
-
- case CMD_REQSTATUS:
- for (i = 0; i < numInterfaces; i++)
- if (!strcmp(intf[i].device, cmd.u.stop.device)) break;
- if (i == numInterfaces) {
- cmd.u.result = RESULT_UNKNOWNIFACE;
- } else {
- cmd.type = CMD_STATUS;
- cmd.u.status.intf = intf[i];
- if (intf[i].set & NETINFO_HAS_HOSTNAME)
- strncpy(cmd.u.status.hostname,
- intf->hostname, sizeof(cmd.u.status.hostname));
- cmd.u.status.hostname[sizeof(cmd.u.status.hostname)] = '\0';
-
- if (intf[i].set & NETINFO_HAS_DOMAIN)
- strncpy(cmd.u.status.domain,
- intf->domain, sizeof(cmd.u.status.domain));
- cmd.u.status.domain[sizeof(cmd.u.status.domain) - 1] = '\0';
-
- if (intf[i].set & INTFINFO_HAS_BOOTFILE)
- strncpy(cmd.u.status.bootFile,
- intf->bootFile, sizeof(cmd.u.status.bootFile));
- cmd.u.status.bootFile[sizeof(cmd.u.status.bootFile) - 1] =
- '\0';
- }
-
- case CMD_STATUS:
- case CMD_RESULT:
- /* can't happen */
- break;
- }
-
- if (cmd.type != CMD_STATUS) cmd.type = CMD_RESULT;
- write(conn, &cmd, sizeof(cmd));
-
- close(conn);
- }
- }
-
- exit(0);
-}
-
-static int openControlSocket(char * configFile) {
- struct sockaddr_un addr;
- int sock;
- size_t addrLength;
- pid_t child;
- int status;
-
- if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
- return -1;
-
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, CONTROLSOCKET);
- addrLength = sizeof(addr.sun_family) + strlen(addr.sun_path);
-
- if (!connect(sock, (struct sockaddr *) &addr, addrLength))
- return sock;
-
- if (errno != ENOENT && errno != ECONNREFUSED) {
- fprintf(stderr, "failed to connect to %s: %s\n", CONTROLSOCKET,
- strerror(errno));
- close(sock);
- return -1;
- }
-
- if (!(child = fork())) {
- close(sock);
-
- if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
- fprintf(stderr, "failed to create socket: %s\n", strerror(errno));
- exit(1);
- }
-
- unlink(CONTROLSOCKET);
- umask(077);
- if (bind(sock, (struct sockaddr *) &addr, addrLength)) {
- fprintf(stderr, "bind to %s failed: %s\n", CONTROLSOCKET,
- strerror(errno));
- exit(1);
- }
- umask(033);
-
- listen(sock, 5);
-
- if (fork()) _exit(0);
-
- close(0);
- close(1);
- close(2);
-
- openlog("pumpd", LOG_PID, LOG_DAEMON);
- {
- time_t t;
-
- t = time(NULL);
- syslog(LOG_INFO, "starting at %s\n", ctime(&t));
- }
-
- runDaemon(sock, configFile);
- }
-
- waitpid(child, &status, 0);
- if (!WIFEXITED(status) || WEXITSTATUS(status))
- return -1;
-
- if (!connect(sock, (struct sockaddr *) &addr, addrLength))
- return sock;
-
- fprintf(stderr, "failed to connect to %s: %s\n", CONTROLSOCKET,
- strerror(errno));
-
- return 0;
-}
-
-void printStatus(struct intfInfo i, char * hostname, char * domain,
- char * bootFile) {
- int j;
-
- printf("Device %s\n", i.device);
- printf("\tIP: %s\n", inet_ntoa(i.ip));
- printf("\tNetmask: %s\n", inet_ntoa(i.netmask));
- printf("\tBroadcast: %s\n", inet_ntoa(i.broadcast));
- printf("\tNetwork: %s\n", inet_ntoa(i.network));
- printf("\tBoot server %s\n", inet_ntoa(i.bootServer));
-
- if (i.set & NETINFO_HAS_GATEWAY)
- printf("\tGateway: %s\n", inet_ntoa(i.gateway));
-
- if (i.set & INTFINFO_HAS_BOOTFILE)
- printf("\tBoot file: %s\n", bootFile);
-
- if (i.set & NETINFO_HAS_HOSTNAME)
- printf("\tHostname: %s\n", hostname);
-
- if (i.set & NETINFO_HAS_DOMAIN)
- printf("\tDomain: %s\n", domain);
-
- if (i.numDns) {
- printf("\tNameservers:");
- for (j = 0; j < i.numDns; j++)
- printf(" %s", inet_ntoa(i.dnsServers[j]));
- printf("\n");
- }
-
- if (i.set & INTFINFO_HAS_LEASE) {
- printf("\tRenewal time: %s", ctime(&i.renewAt));
- printf("\tExpiration time: %s", ctime(&i.leaseExpiration));
- }
-}
-
-int main (int argc, char ** argv) {
- char * device = "eth0";
- char * hostname = "";
- poptContext optCon;
- int rc;
- int test = 0;
- int flags = 0;
- int lease = 6;
- int killDaemon = 0;
- int release = 0, renew = 0, status = 0, lookupHostname = 0;
- struct command cmd, response;
- char * configFile = "/etc/pump.conf";
- struct overrideInfo * overrides;
- int cont;
- struct poptOption options[] = {
- { "config-file", 'c', POPT_ARG_STRING, &configFile, 0,
- N_("Configuration file to use instead of "
- "/etc/pump.conf") },
- { "hostname", 'h', POPT_ARG_STRING, &hostname, 0,
- N_("Hostname to request"), N_("hostname") },
- { "interface", 'i', POPT_ARG_STRING, &device, 0,
- N_("Interface to configure (normally eth0)"),
- N_("iface") },
- { "kill", 'k', POPT_ARG_NONE, &killDaemon, 0,
- N_("Kill daemon (and disable all interfaces)"), NULL },
- { "lease", 'l', POPT_ARG_INT, &lease, 0,
- N_("Lease time to request (in hours)"), N_("hours") },
- { "lookup-hostname", '\0', POPT_ARG_NONE, &lookupHostname, 0,
- N_("Force lookup of hostname") },
- { "release", 'r', POPT_ARG_NONE, &release, 0,
- N_("Release interface"), NULL },
- { "renew", 'R', POPT_ARG_NONE, &renew, 0,
- N_("Force immediate lease renewal"), NULL },
- { "status", 's', POPT_ARG_NONE, &status, 0,
- N_("Display interface status"), NULL },
- /*{ "test", 't', POPT_ARG_NONE, &test, 0,
- N_("Don't change the interface configuration or "
- "run as a deamon.") },*/
- POPT_AUTOHELP
- { NULL, '\0', 0, NULL, 0 }
- };
-
- optCon = poptGetContext(PROGNAME, argc, argv, options,0);
- poptReadDefaultConfig(optCon, 1);
-
- if ((rc = poptGetNextOpt(optCon)) < -1) {
- fprintf(stderr, _("%s: bad argument %s: %s\n"), PROGNAME,
- poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
- poptStrerror(rc));
- return 1;
- }
-
- if (poptGetArg(optCon)) {
- fprintf(stderr, _("%s: no extra parameters are expected\n"), PROGNAME);
- return 1;
- }
-
- /* make sure the config file is parseable before going on any further */
- if (readPumpConfig(configFile, &overrides)) return 1;
-
- if (geteuid()) {
- fprintf(stderr, _("%s: must be run as root\n"), PROGNAME);
- exit(1);
- }
-
- if (test)
- flags = DHCP_FLAG_NODAEMON | DHCP_FLAG_NOCONFIG;
- if (lookupHostname)
- flags |= DHCP_FLAG_FORCEHNLOOKUP;
-
- cont = openControlSocket(configFile);
- if (cont < 0)
- exit(1);
-
- if (killDaemon) {
- cmd.type = CMD_DIE;
- } else if (status) {
- cmd.type = CMD_REQSTATUS;
- strcpy(cmd.u.reqstatus.device, device);
- } else if (renew) {
- cmd.type = CMD_FORCERENEW;
- strcpy(cmd.u.renew.device, device);
- } else if (release) {
- cmd.type = CMD_STOPIFACE;
- strcpy(cmd.u.stop.device, device);
- } else {
- cmd.type = CMD_STARTIFACE;
- strcpy(cmd.u.start.device, device);
- cmd.u.start.flags = flags;
- cmd.u.start.reqLease = lease * 60 * 60;
- strcpy(cmd.u.start.reqHostname, hostname);
- }
-
- write(cont, &cmd, sizeof(cmd));
- read(cont, &response, sizeof(response));
-
- if (response.type == CMD_RESULT && response.u.result &&
- cmd.type == CMD_STARTIFACE) {
- cont = openControlSocket(configFile);
- if (cont < 0)
- exit(1);
- write(cont, &cmd, sizeof(cmd));
- read(cont, &response, sizeof(response));
- }
-
- if (response.type == CMD_RESULT) {
- if (response.u.result) {
- fprintf(stderr, "Operation failed.\n");
- return 1;
- }
- } else if (response.type == CMD_STATUS) {
- printStatus(response.u.status.intf, response.u.status.hostname,
- response.u.status.domain, response.u.status.bootFile);
- }
-
- return 0;
-}