From 18c73715b596af1481c71d680d36723ba6161670 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Sun, 8 Dec 2002 23:48:30 +0000 Subject: 2002-12-08 Roland McGrath * pump.c: File removed. --- trans/pump.c | 1876 ---------------------------------------------------------- 1 file changed, 1876 deletions(-) delete mode 100644 trans/pump.c 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 - -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, ðernet_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; -} -- cgit v1.2.3