/[hurd]/hurd/trans/pump.c
ViewVC logotype

Contents of /hurd/trans/pump.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations) (download)
Tue Jan 30 23:45:32 2001 UTC (23 years, 3 months ago) by marcus
Branch: MAIN
Changes since 1.2: +3 -2 lines
File MIME type: text/plain
daemons/
2001-01-17  Neal H Walfield   <neal@cs.uml.edu>

	* console-run.c (open_console): Conform to new
	fshelp_start_translator semantics.

init/
2001-01-17  Neal H Walfield  <neal@cs.uml.edu>

	* init.c (open_console): Conform to new fshelp_start_translator
	semantics.

libfshelp/
2001-01-17  Neal H Walfield  <neal@cs.uml.edu>

	* fshelp.h: Add two new parameters to fshelp_open_fn_t:
	a port to the new task and a cookie.
	Add a new parameter, cookie, to fshelp_start_translator and
	fshelp_start_translator_long that will be passed to
	fshelp_open_fn_t.

	* fetch-root.c (fshelp_fetch_root): Conform to new
	fshelp_start_translator_long semantics.
	* start-translator-long.c (service_fsys_startup): Likewise.
	(fshelp_start_translator_long): Likewise.
	* start-translator.c (fshelp_start_translator): Likewise.

libtreefs/
Conform to new fshelp_start_translator semantics.

trans/
2001-01-17  Neal H Walfield  <neal@cs.uml.edu>

	* pump.c (start_pfinet): Conform to new fshelp_start_translator
	semantics.

utils/
2001-01-17  Neal H Walfield  <neal@cs.uml.edu>

	* mount.c (do_mount): Conform to new fshelp_start_translator
	semantics.

	* settrans.c (main): Conform to new fshelp_start_translator
	semantics therby allowing us to print the pid of the an
	active translator.

1 /* Initialize an Ethernet interface
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3 Written by Thomas Bushnell, BSG.
4
5 This file is part of the GNU Hurd.
6
7 The GNU Hurd is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 The GNU Hurd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
20
21 /*
22 * Copyright 1999 Red Hat Software, Inc.
23 *
24 * This program is free software; you can redistribute it and/or modify
25 * it under the terms of the GNU General Public License as published by
26 * the Free Software Foundation; either version 2 of the License, or
27 * (at your option) any later version.
28 *
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
33 *
34 * You should have received a copy of the GNU General Public License
35 * along with this program; if not, write to the Free Software
36 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 *
38 */
39
40 /* This probably doesn't work on anything other then Ethernet! It may work
41 on PLIP as well, but ARCnet and Token Ring are unlikely at best. */
42
43 #define DHCP_FLAG_NODAEMON (1 << 0)
44 #define DHCP_FLAG_NOCONFIG (1 << 1)
45 #define DHCP_FLAG_FORCEHNLOOKUP (1 << 2)
46
47 #define RESULT_OKAY 0
48 #define RESULT_FAILED 1
49 #define RESULT_UNKNOWNIFACE 2
50
51 #define N_(foo) (foo)
52
53 #define PROGNAME "pump"
54 #define CONTROLSOCKET "/var/run/pump.sock"
55
56 #define _(foo) ((foo))
57 #include <stdarg.h>
58
59 void logMessage(char * mess, ...) {
60 va_list args;
61
62 va_start(args, mess);
63 vprintf(mess, args);
64 va_end(args);
65 puts("");
66 }
67
68 typedef int bp_int32;
69 typedef short bp_int16;
70
71 #define BOOTP_OPTION_NETMASK 1
72 #define BOOTP_OPTION_GATEWAY 3
73 #define BOOTP_OPTION_DNS 6
74 #define BOOTP_OPTION_HOSTNAME 12
75 #define BOOTP_OPTION_BOOTFILE 13
76 #define BOOTP_OPTION_DOMAIN 15
77 #define BOOTP_OPTION_BROADCAST 28
78
79 #define DHCP_OPTION_REQADDR 50
80 #define DHCP_OPTION_LEASE 51
81 #define DHCP_OPTION_OVERLOAD 52
82 #define DHCP_OPTION_TYPE 53
83 #define DHCP_OPTION_SERVER 54
84 #define DHCP_OPTION_OPTIONREQ 55
85 #define DHCP_OPTION_MAXSIZE 57
86 #define DHCP_OPTION_T1 58
87
88 #define BOOTP_CLIENT_PORT 68
89 #define BOOTP_SERVER_PORT 67
90
91 #define BOOTP_OPCODE_REQUEST 1
92 #define BOOTP_OPCODE_REPLY 2
93
94 #define NORESPONSE -10
95 #define DHCP_TYPE_DISCOVER 1
96 #define DHCP_TYPE_OFFER 2
97 #define DHCP_TYPE_REQUEST 3
98 #define DHCP_TYPE_DECLINE 4
99 #define DHCP_TYPE_ACK 5
100 #define DHCP_TYPE_NAK 6
101 #define DHCP_TYPE_RELEASE 7
102 #define DHCP_TYPE_INFORM 8
103
104 #define BOOTP_VENDOR_LENGTH 64
105 #define DHCP_VENDOR_LENGTH 312
106
107 struct bootpRequest {
108 char opcode;
109 char hw;
110 char hwlength;
111 char hopcount;
112 bp_int32 id;
113 bp_int16 secs;
114 bp_int16 flags;
115 bp_int32 ciaddr, yiaddr, server_ip, bootp_gw_ip;
116 char hwaddr[16];
117 char servername[64];
118 char bootfile[128];
119 char vendor[DHCP_VENDOR_LENGTH];
120 } ;
121
122 struct psuedohUdpHeader {
123 bp_int32 source, dest;
124 char zero;
125 char protocol;
126 bp_int16 len;
127 };
128
129 struct command {
130 enum { CMD_STARTIFACE, CMD_RESULT, CMD_DIE, CMD_STOPIFACE,
131 CMD_FORCERENEW, CMD_REQSTATUS, CMD_STATUS } type;
132 union {
133 struct {
134 char device[20];
135 int flags;
136 int reqLease; /* in hours */
137 char reqHostname[200];
138 } start;
139 int result; /* 0 for success */
140 struct {
141 char device[20];
142 } stop;
143 struct {
144 char device[20];
145 } renew;
146 struct {
147 char device[20];
148 } reqstatus;
149 struct {
150 struct intfInfo intf;
151 char hostname[1024];
152 char domain[1024];
153 char bootFile[1024];
154 } status;
155 } u;
156 };
157
158 static char * doDhcp(char * device, int flags, int lease,
159 char * reqHostname, struct intfInfo * intf,
160 struct overrideInfo * override);
161
162 static const char vendCookie[] = { 99, 130, 83, 99, 255 };
163
164 static char * perrorstr(char * msg);
165 static char * setupInterface(struct intfInfo * intf, int s);
166 static char * prepareInterface(struct intfInfo * intf, int s);
167 static char * getInterfaceInfo(struct intfInfo * intf, int s);
168 static char * disableInterface(char * device);
169 static void parseReply(struct bootpRequest * breq, struct intfInfo * intf);
170 static char * prepareRequest(struct bootpRequest * breq,
171 int sock, char * device, time_t startTime);
172 static void parseLease(struct bootpRequest * bresp, struct intfInfo * intf);
173 static void initVendorCodes(struct bootpRequest * breq);
174 static char * handleTransaction(int s, struct overrideInfo * override,
175 struct bootpRequest * breq,
176 struct bootpRequest * bresp,
177 struct sockaddr_in * serverAddr,
178 struct sockaddr_in * respondant,
179 int useBootPacket, int dhcpResponseType);
180 static int dhcpMessageType(struct bootpRequest * response);
181 static void setMissingIpInfo(struct intfInfo * intf);
182 static int openControlSocket(char * configFile);
183 static int dhcpRenew(struct intfInfo * intf);
184 static int dhcpRelease(struct intfInfo * intf);
185
186 /* Various hurd-specific decls here */
187 #define _HURD_PFINET _HURD "pfinet"
188 io_t underlying_pfinet;
189 device_t ethernet_device;
190 char ethernet_address[ETH_ALEN];
191
192
193 /* Open the ethernet device */
194 char *
195 prepareInterface (struct intfInfo *intf, int s);
196 {
197 u_int count;
198 int addr[2];
199
200 err = device_open (master_device, D_WRITE|D_READ,
201 intf->device, &ethernet_device);
202 if (err)
203 return err;
204
205 err = device_get_status (ethernet_device, NET_ADDRESS, addr, &count);
206 if (err)
207 return err;
208
209 addr[0] = ntohl (addr[0]);
210 addr[1] = ntohl (addr[1]);
211 bcopy (addr, ethernet_address, ETH_ALEN);
212 return 0;
213 }
214
215 /* Open the node underlying the pfinet translator, and set
216 underlying_pfinet to a port to that file. */
217 error_t
218 open_underlying_pfinet ()
219 {
220 char *path;
221
222 if (underlying_pfinet != MACH_PORT_NULL)
223 return 0;
224
225 asprintf (&path, "%s/%d", _SERVERS_SOCKET, PF_INET);
226
227 underlying_pfinet = file_name_lookup (path, O_NOTRANS, 0);
228 free (path);
229 return underlying_pfinet == MACH_PORT_NULL ? errno : 0;
230 }
231
232 /* Start pfinet with the specified arguments */
233 error_t
234 start_pfinet (char *argz, int argz_len)
235 {
236 error_t open_function (int flags,
237 mach_port_t *underlying,
238 mach_msg_type_name_t *underlying_type,
239 task_t task, void *cookie)
240 {
241 int err;
242
243 err = open_underlying_pfinet ();
244 if (err)
245 return err;
246
247 *underlying = underlying_pfinet;
248 *underlying_type = MACH_MSG_TYPE_COPY_SEND;
249 return 0;
250 }
251
252 err = fshelp_start_translator (open_function, NULL,
253 _HURD_PFINET, argz, argz_len,
254 60 * 1000, &control);
255 if (err)
256 return err;
257
258 err = file_set_translator (underlying_pfinet,
259 0, FS_TRANS_SET,
260 FSYS_GOAWAY_FORCE,
261 argz, argz_len,
262 control, MACH_MSG_TYPE_COPY_SEND);
263 mach_port_deallocate (mach_task_self (), control);
264
265 /* Force the C library to forget about any old cached server
266 access port. */
267 _hurd_socket_server (PFINET, 1);
268 }
269
270
271
272 int newKernel(void) {
273 #ifdef NOTHURD
274 struct utsname ubuf;
275 int major1, major2;
276
277 uname(&ubuf);
278 if (!strcasecmp(ubuf.sysname, "linux")) {
279 if (sscanf(ubuf.release, "%d.%d", &major1, &major2) != 2 ||
280 (major1 < 2) || (major1 == 2 && major2 == 0)) {
281 return 0;
282 }
283 }
284 #endif
285
286 return 1;
287 }
288
289 static char * disableInterface(char * device) {
290 #ifdef NOTHURD
291 struct ifreq req;
292 int s;
293
294 s = socket(AF_INET, SOCK_DGRAM, 0);
295
296 strcpy(req.ifr_name, device);
297 if (ioctl(s, SIOCGIFFLAGS, &req)) {
298 close(s);
299 return perrorstr("SIOCGIFFLAGS");
300 }
301
302 req.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
303 if (ioctl(s, SIOCSIFFLAGS, &req)) {
304 close(s);
305 return perrorstr("SIOCSIFFLAGS");
306 }
307
308 close(s);
309
310 return NULL;
311 #else
312 error_t err;
313
314 err = open_underlying_pfinet ();
315 if (err)
316 return strerror (err);
317
318 err = file_set_translator (underlying_pfinet,
319 0, FS_TRANS_SET | FS_TRANS_FORCE,
320 FSYS_GOAWAY_FORCE,
321 0, 0, MACH_PORT_NULL);
322 return err ? strerror (err) : 0;
323 #endif
324 }
325
326 static char * setupInterface(struct intfInfo * intf, int s) {
327 char * rc;
328 char * s;
329 char * argz = 0;
330 int argz_len = 0;
331
332 /* Construct the args to pfinet. */
333 /* /hurd/pfinet */
334 argz_add (&argz, &argz_len, _HURD_PFINET);
335
336 /* Interface name */
337 asprintf (&s, "--interface=%s", intf->decive);
338 argz_add (&argz, &argz_len, s);
339 free (s);
340
341 /* Address */
342 asprintf (&s, "--address=%s", inet_ntoa (intf->ip));
343 argz_add (&argz, &argz_len, s);
344 free (s);
345
346 /* Netmask */
347 asprintf (&s, "--netmask=%s", inet_ntoa (intf->netmask));
348 argz_add (&argz, &argz_len, s);
349 free (s);
350
351 /* Gateway */
352 asprintf (&s, "--gateway=%s", inet_ntoa (intf->gateway));
353 argz_add (&argz, &argz_len, s);
354 free (s);
355
356 /* Now set it up */
357 err = start_pfinet (argz, argz_len);
358 free (argz);
359
360 return err ? strerror (err) : 0;
361
362
363 #ifdef NOTHURD
364 struct sockaddr_in * addrp;
365 struct ifreq req;
366 struct rtentry route;
367
368 if ((rc = disableInterface(intf->device))) return rc;
369
370 /* we have to have basic information to get this far */
371 addrp = (struct sockaddr_in *) &req.ifr_addr;
372 addrp->sin_family = AF_INET;
373 strcpy(req.ifr_name, intf->device);
374
375 addrp->sin_addr = intf->ip;
376 if (ioctl(s, SIOCSIFADDR, &req))
377 return perrorstr("SIOCSIFADDR");
378
379 addrp->sin_addr = intf->netmask;
380 if (ioctl(s, SIOCSIFNETMASK, &req))
381 return perrorstr("SIOCSIFNETMASK");
382
383 addrp->sin_addr = intf->broadcast;
384 if (ioctl(s, SIOCSIFBRDADDR, &req))
385 return perrorstr("SIOCSIFBRDADDR");
386
387 /* bring up the device, and specifically allow broadcasts through it */
388 req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST;
389 if (ioctl(s, SIOCSIFFLAGS, &req))
390 return perrorstr("SIOCSIFFLAGS");
391
392 /* add a route for this network */
393 route.rt_dev = intf->device;
394 route.rt_flags = RTF_UP;
395 route.rt_metric = 0;
396
397 if (!newKernel()) {
398 addrp->sin_family = AF_INET;
399 addrp->sin_port = 0;
400 addrp->sin_addr = intf->network;
401 memcpy(&route.rt_dst, addrp, sizeof(*addrp));
402 addrp->sin_addr = intf->netmask;
403 memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
404
405 if (ioctl(s, SIOCADDRT, &route)) {
406 /* the route cannot already exist, as we've taken the device down */
407 return perrorstr("SIOCADDRT 1");
408 }
409 }
410 return NULL;
411 }
412
413 #ifdef NOTHURD
414 static char * setupDefaultGateway(struct in_addr * gw, int s) {
415 struct sockaddr_in addr;
416 struct rtentry route;
417
418 addr.sin_family = AF_INET;
419 addr.sin_port = 0;
420 addr.sin_addr.s_addr = INADDR_ANY;
421 memcpy(&route.rt_dst, &addr, sizeof(addr));
422 memcpy(&route.rt_genmask, &addr, sizeof(addr));
423 addr.sin_addr = *gw;
424 memcpy(&route.rt_gateway, &addr, sizeof(addr));
425
426 route.rt_flags = RTF_UP | RTF_GATEWAY;
427 route.rt_metric = 0;
428 route.rt_dev = NULL;
429
430 if (ioctl(s, SIOCADDRT, &route)) {
431 /* the route cannot already exist, as we've taken the device
432 down */
433 return perrorstr("SIOCADDRT 2");
434 }
435
436 return NULL;
437 }
438
439 static char * getInterfaceInfo(struct intfInfo * intf, int s) {
440 struct ifreq req;
441 struct sockaddr_in * addrp;
442
443 strcpy(req.ifr_name, intf->device);
444 if (ioctl(s, SIOCGIFBRDADDR, &req))
445 return perrorstr("SIOCGIFBRDADDR");
446
447 addrp = (struct sockaddr_in *) &req.ifr_addr;
448 intf->broadcast = addrp->sin_addr;
449 intf->set = INTFINFO_HAS_BROADCAST;
450
451 return NULL;
452 }
453
454 static char * prepareInterface(struct intfInfo * intf, int s) {
455 struct sockaddr_in * addrp;
456 struct ifreq req;
457 struct rtentry route;
458
459 addrp = (struct sockaddr_in *) &req.ifr_addr;
460
461 strcpy(req.ifr_name, intf->device);
462 addrp->sin_family = AF_INET;
463 addrp->sin_port = 0;
464 memset(&addrp->sin_addr, 0, sizeof(addrp->sin_addr));
465
466 addrp->sin_family = AF_INET;
467 addrp->sin_addr.s_addr = htonl(0);
468
469 if (ioctl(s, SIOCSIFADDR, &req))
470 return perrorstr("SIOCSIFADDR");
471
472 if (!newKernel()) {
473 if (ioctl(s, SIOCSIFNETMASK, &req))
474 return perrorstr("SIOCSIFNETMASK");
475
476 /* the broadcast address is 255.255.255.255 */
477 memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
478 if (ioctl(s, SIOCSIFBRDADDR, &req))
479 return perrorstr("SIOCSIFBRDADDR");
480 }
481
482 req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
483 if (ioctl(s, SIOCSIFFLAGS, &req))
484 return perrorstr("SIOCSIFFLAGS");
485
486 memset(&route, 0, sizeof(route));
487 memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
488
489 addrp->sin_family = AF_INET;
490 addrp->sin_port = 0;
491 addrp->sin_addr.s_addr = INADDR_ANY;
492 memcpy(&route.rt_dst, addrp, sizeof(*addrp));
493 memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
494
495 route.rt_dev = intf->device;
496 route.rt_flags = RTF_UP;
497 route.rt_metric = 0;
498
499 if (ioctl(s, SIOCADDRT, &route)) {
500 if (errno != EEXIST) {
501 close(s);
502 return perrorstr("SIOCADDRT 3");
503 }
504 }
505
506 return NULL;
507 }
508 #endif
509
510 static int dhcpMessageType(struct bootpRequest * response) {
511 unsigned char * chptr;
512 unsigned char option, length;
513
514 chptr = response->vendor;
515
516 chptr += 4;
517 while (*chptr != 0xFF) {
518 option = *chptr++;
519 if (!option) continue;
520 length = *chptr++;
521 if (option == DHCP_OPTION_TYPE)
522 return *chptr;
523
524 chptr += length;
525 }
526
527 return -1;
528 }
529
530 static void setMissingIpInfo(struct intfInfo * intf) {
531 bp_int32 ipNum = *((bp_int32 *) &intf->ip);
532 bp_int32 nmNum = *((bp_int32 *) &intf->netmask);
533 bp_int32 ipRealNum = ntohl(ipNum);
534
535 if (!(intf->set & INTFINFO_HAS_NETMASK)) {
536 if (((ipRealNum & 0xFF000000) >> 24) <= 127)
537 nmNum = 0xFF000000;
538 else if (((ipRealNum & 0xFF000000) >> 24) <= 191)
539 nmNum = 0xFFFF0000;
540 else
541 nmNum = 0xFFFFFF00;
542 *((bp_int32 *) &intf->netmask) = nmNum = htonl(nmNum);
543 syslog (LOG_DEBUG, "intf: netmask: %s", inet_ntoa (intf->netmask));
544 }
545
546 if (!(intf->set & INTFINFO_HAS_BROADCAST)) {
547 *((bp_int32 *) &intf->broadcast) = (ipNum & nmNum) | ~(nmNum);
548 syslog (LOG_DEBUG, "intf: broadcast: %s", inet_ntoa (intf->broadcast));
549 }
550
551 if (!(intf->set & INTFINFO_HAS_NETWORK)) {
552 *((bp_int32 *) &intf->network) = ipNum & nmNum;
553 syslog (LOG_DEBUG, "intf: network: %s", inet_ntoa (intf->network));
554 }
555
556 intf->set |= INTFINFO_HAS_BROADCAST | INTFINFO_HAS_NETWORK |
557 INTFINFO_HAS_NETMASK;
558 }
559
560 static void parseReply(struct bootpRequest * breq, struct intfInfo * intf) {
561 unsigned int i;
562 unsigned char * chptr;
563 unsigned char option, length;
564
565 syslog (LOG_DEBUG, "intf: device: %s", intf->device);
566 syslog (LOG_DEBUG, "intf: set: %i", intf->set);
567 syslog (LOG_DEBUG, "intf: bootServer: %s", inet_ntoa (intf->bootServer));
568 syslog (LOG_DEBUG, "intf: reqLease: %i", intf->reqLease);
569
570 i = ~(INTFINFO_HAS_IP | INTFINFO_HAS_NETMASK | INTFINFO_HAS_NETWORK |
571 INTFINFO_HAS_BROADCAST);
572 intf->set &= i;
573
574 if (strlen(breq->bootfile)) {
575 intf->bootFile = strdup(breq->bootfile);
576 intf->set |= INTFINFO_HAS_BOOTFILE;
577 } else {
578 intf->set &= ~INTFINFO_HAS_BOOTFILE;
579 }
580 syslog (LOG_DEBUG, "intf: bootFile: %s", intf->bootFile);
581
582 memcpy(&intf->ip, &breq->yiaddr, 4);
583 intf->set |= INTFINFO_HAS_IP;
584 syslog (LOG_DEBUG, "intf: ip: %s", inet_ntoa (intf->ip));
585
586 chptr = breq->vendor;
587 chptr += 4;
588 while (*chptr != 0xFF && (void *) chptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH) {
589 option = *chptr++;
590 if (!option) continue;
591 length = *chptr++;
592
593 switch (option) {
594 case BOOTP_OPTION_DNS:
595 intf->numDns = 0;
596 for (i = 0; i < length; i += 4) {
597 if (intf->numDns < MAX_DNS_SERVERS) {
598 memcpy(&intf->dnsServers[intf->numDns++], chptr + i, 4);
599 syslog(LOG_DEBUG, "intf: dnsServers[%i]: %s",
600 i/4, inet_ntoa (intf->dnsServers[i/4]));
601 }
602 }
603 intf->set |= NETINFO_HAS_DNS;
604 syslog (LOG_DEBUG, "intf: numDns: %i", intf->numDns);
605 break;
606
607 case BOOTP_OPTION_NETMASK:
608 memcpy(&intf->netmask, chptr, 4);
609 intf->set |= INTFINFO_HAS_NETMASK;
610 syslog (LOG_DEBUG, "intf: netmask: %s", inet_ntoa (intf->netmask));
611 break;
612
613 case BOOTP_OPTION_DOMAIN:
614 if ((intf->domain = malloc(length + 1))) {
615 memcpy(intf->domain, chptr, length);
616 intf->domain[length] = '\0';
617 intf->set |= NETINFO_HAS_DOMAIN;
618 syslog (LOG_DEBUG, "intf: domain: %s", intf->domain);
619 }
620 break;
621
622 case BOOTP_OPTION_BROADCAST:
623 memcpy(&intf->broadcast, chptr, 4);
624 intf->set |= INTFINFO_HAS_BROADCAST;
625 syslog (LOG_DEBUG, "intf: broadcast: %s", inet_ntoa (intf->broadcast));
626 break;
627
628 case BOOTP_OPTION_GATEWAY:
629 memcpy(&intf->gateway, chptr, 4);
630 intf->set |= NETINFO_HAS_GATEWAY;
631 syslog (LOG_DEBUG, "intf: gateway: %s", inet_ntoa (intf->gateway));
632 break;
633
634 case BOOTP_OPTION_HOSTNAME:
635 if ((intf->hostname = malloc(length + 1))) {
636 memcpy(intf->hostname, chptr, length);
637 intf->hostname[length] = '\0';
638 intf->set |= NETINFO_HAS_HOSTNAME;
639 syslog (LOG_DEBUG, "intf: hostname: %s", intf->hostname);
640 }
641 break;
642
643 case BOOTP_OPTION_BOOTFILE:
644 /* we ignore this right now */
645 break;
646
647 case DHCP_OPTION_OVERLOAD:
648 /* FIXME: we should pay attention to this */
649 logMessage("dhcp overload option is currently ignored!");
650 break;
651 }
652
653 chptr += length;
654 }
655
656 setMissingIpInfo(intf);
657 }
658
659 static char * perrorstr(char * msg) {
660 static char * err = NULL;
661 static int errsize = 0;
662 static int newsize;
663
664 newsize = strlen(msg) + strlen(strerror(errno)) + 3;
665 if (!errsize) {
666 errsize = newsize;
667 err = malloc(errsize);
668 } else if (errsize < newsize) {
669 free(err);
670 errsize = newsize;
671 err = malloc(errsize);
672 }
673
674 if (err)
675 sprintf(err, "%s: %s", msg, strerror(errno));
676 else
677 err = "out of memory!";
678
679 return err;
680 }
681
682 static void initVendorCodes(struct bootpRequest * breq) {
683 memcpy(breq->vendor, vendCookie, sizeof(vendCookie));
684 }
685
686 static char * prepareRequest(struct bootpRequest * breq,
687 int sock, char * device, time_t startTime) {
688 #ifdef NOTHURD
689 struct ifreq req;
690 #endif
691 int i;
692
693 memset(breq, 0, sizeof(*breq));
694
695 breq->opcode = BOOTP_OPCODE_REQUEST;
696
697 #ifdef NOTHURD
698 strcpy(req.ifr_name, device);
699 if (ioctl(sock, SIOCGIFHWADDR, &req))
700 return perrorstr("SIOCSIFHWADDR");
701
702 breq->hw = 1; /* ethernet */
703 breq->hwlength = IFHWADDRLEN;
704 memcpy(breq->hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
705 #else
706 breq->hw = 1; /* ethernet */
707 breq->hwlength = IFHWADDRLEN;
708 memcpy(breq->hwaddr, ethernet_address, IFHWADDRLEN);
709 #endif
710
711 /* we should use something random here, but I don't want to start using
712 stuff from the math library */
713 breq->id = time(NULL);
714 for (i = 0; i < IFHWADDRLEN; i++)
715 breq->id ^= breq->hwaddr[i] << (8 * (i % 4));
716
717 breq->hopcount = 0;
718 breq->secs = time(NULL) - startTime;
719
720 initVendorCodes(breq);
721
722 return NULL;
723 }
724
725 static unsigned int verifyChecksum(void * buf, int length, void * buf2,
726 int length2) {
727 unsigned int csum;
728 unsigned short * sp;
729
730 csum = 0;
731 for (sp = (unsigned short *) buf; length > 0; (length -= 2), sp++)
732 csum += *sp;
733
734 /* this matches rfc 1071, but not Steven's */
735 if (length)
736 csum += *((unsigned char *) sp);
737
738 for (sp = (unsigned short *) buf2; length2 > 0; (length2 -= 2), sp++)
739 csum += *sp;
740
741 /* this matches rfc 1071, but not Steven's */
742 if (length)
743 csum += *((unsigned char *) sp);
744
745 while (csum >> 16)
746 csum = (csum & 0xffff) + (csum >> 16);
747
748 if (csum!=0x0000 && csum != 0xffff) return 0; else return 1;
749 }
750
751 void debugbootpRequest(char *name, struct bootpRequest *breq) {
752 char vendor[28], vendor2[28];
753 int i;
754 struct in_addr address;
755 unsigned char *vndptr;
756 unsigned char option, length;
757
758 syslog (LOG_DEBUG, "%s: opcode: %i", name, breq->opcode);
759 syslog (LOG_DEBUG, "%s: hw: %i", name, breq->hw);
760 syslog (LOG_DEBUG, "%s: hwlength: %i", name, breq->hwlength);
761 syslog (LOG_DEBUG, "%s: hopcount: %i", name, breq->hopcount);
762 syslog (LOG_DEBUG, "%s: id: 0x%8x", name, breq->id);
763 syslog (LOG_DEBUG, "%s: secs: %i", name, breq->secs);
764 syslog (LOG_DEBUG, "%s: flags: 0x%4x", name, breq->flags);
765
766 address.s_addr = breq->ciaddr;
767 syslog (LOG_DEBUG, "%s: ciaddr: %s", name, inet_ntoa (address));
768
769 address.s_addr = breq->yiaddr;
770 syslog (LOG_DEBUG, "%s: yiaddr: %s", name, inet_ntoa (address));
771
772 address.s_addr = breq->server_ip;
773 syslog (LOG_DEBUG, "%s: server_ip: %s", name, inet_ntoa (address));
774
775 address.s_addr = breq->bootp_gw_ip;
776 syslog (LOG_DEBUG, "%s: bootp_gw_ip: %s", name, inet_ntoa (address));
777
778 syslog (LOG_DEBUG, "%s: hwaddr: %s", name, breq->hwaddr);
779 syslog (LOG_DEBUG, "%s: servername: %s", name, breq->servername);
780 syslog (LOG_DEBUG, "%s: bootfile: %s", name, breq->bootfile);
781
782 vndptr = breq->vendor;
783 sprintf (vendor, "0x%2x 0x%2x 0x%2x 0x%2x", *vndptr++, *vndptr++, *vndptr++, *vndptr++);
784 syslog (LOG_DEBUG, "%s: vendor: %s", name, vendor);
785
786
787 for (; (void *) vndptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH;)
788 {
789 option = *vndptr++;
790 if (option == 0xFF)
791 {
792 sprintf (vendor, "0x%2x", option);
793 vndptr = breq->vendor + DHCP_VENDOR_LENGTH;
794 }
795 else if (option == 0x00)
796 {
797 for (i = 1; *vndptr == 0x00; i++, vndptr++);
798 sprintf (vendor, "0x%2x x %i", option, i);
799 }
800 else
801 {
802 length = *vndptr++;
803 sprintf (vendor, "%3u %3u", option, length);
804 for (i = 0; i < length; i++)
805 {
806 if (strlen (vendor) > 22)
807 {
808 syslog (LOG_DEBUG, "%s: vendor: %s", name, vendor);
809 strcpy (vendor, "++++++");
810 }
811 snprintf (vendor2, 27, "%s 0x%2x", vendor, *vndptr++);
812 strcpy (vendor, vendor2);
813
814 }
815 }
816
817 syslog (LOG_DEBUG, "%s: vendor: %s", name, vendor);
818 }
819
820 return;
821
822 }
823
824 static char * handleTransaction(int s, struct overrideInfo * override,
825 struct bootpRequest * breq,
826 struct bootpRequest * bresp,
827 struct sockaddr_in * serverAddr,
828 struct sockaddr_in * respondant,
829 int useBootpPacket, int dhcpResponseType) {
830 struct timeval tv;
831 fd_set readfs;
832 int i, j;
833 struct sockaddr_pkt tmpAddress;
834 int gotit = 0;
835 int tries;
836 int nextTimeout = 2;
837 time_t timeoutTime;
838 int sin;
839 int resend = 1;
840 struct ethhdr;
841 char ethPacket[ETH_FRAME_LEN];
842 struct iphdr * ipHdr;
843 struct udphdr * udpHdr;
844 struct psuedohUdpHeader pHdr;
845 time_t start = time(NULL);
846
847 debugbootpRequest("breq", breq);
848
849 if (!override) {
850 override = alloca(sizeof(*override));
851 initOverride(override);
852 }
853
854 tries = override->numRetries + 1;
855
856 sin = socket(AF_PACKET, SOCK_DGRAM, ntohs(ETH_P_IP));
857 if (sin < 0) {
858 return strerror(errno);
859 }
860
861 while (!gotit && tries) {
862 i = sizeof(*breq);
863 if (useBootpPacket)
864 i -= (DHCP_VENDOR_LENGTH - BOOTP_VENDOR_LENGTH);
865
866 if (resend) {
867 if (sendto(s, breq, i, 0, (struct sockaddr *) serverAddr,
868 sizeof(*serverAddr)) != i) {
869 close(sin);
870 return perrorstr("sendto");
871 }
872
873 tries--;
874 nextTimeout *= 2;
875
876 switch (time(NULL) & 4) {
877 case 0: if (nextTimeout >= 2) nextTimeout--; break;
878 case 1: nextTimeout++; break;
879 }
880
881 timeoutTime = time(NULL) + nextTimeout;
882 i = override->timeout + start;
883 if (timeoutTime > i) timeoutTime = i;
884
885 resend = 0;
886 }
887
888 if (dhcpResponseType == NORESPONSE) {
889 close(sin);
890 return NULL;
891 }
892
893 tv.tv_usec = 0;
894 tv.tv_sec = timeoutTime - time(NULL);
895 if (timeoutTime < time(NULL)) {
896 tries = 0;
897 continue;
898 }
899
900 FD_ZERO(&readfs);
901 FD_SET(sin, &readfs);
902 switch ((select(sin + 1, &readfs, NULL, NULL, &tv))) {
903 case 0:
904 resend = 1;
905 break;
906
907 case 1:
908 i = sizeof(tmpAddress);
909 if ((j = recvfrom(sin, ethPacket, sizeof(ethPacket), 0,
910 (struct sockaddr *) &tmpAddress, &i)) < 0)
911 return perrorstr("recvfrom");
912
913 /* We need to do some basic sanity checking of the header */
914 if (j < (sizeof(*ipHdr) + sizeof(*udpHdr))) continue;
915
916 ipHdr = (void *) ethPacket;
917 if (!verifyChecksum(NULL, 0, ipHdr, sizeof(*ipHdr)))
918 continue;
919
920 if (ntohs(ipHdr->tot_len) > j)
921 continue;
922 j = ntohs(ipHdr->tot_len);
923
924 if (ipHdr->protocol != IPPROTO_UDP) continue;
925
926 udpHdr = (void *) (ethPacket + sizeof(*ipHdr));
927 pHdr.source = ipHdr->saddr;
928 pHdr.dest = ipHdr->daddr;
929 pHdr.zero = 0;
930 pHdr.protocol = ipHdr->protocol;
931 pHdr.len = udpHdr->len;
932
933 /*
934 egcs bugs make this problematic
935
936 if (udpHdr->check && !verifyChecksum(&pHdr, sizeof(pHdr),
937 udpHdr, j - sizeof(*ipHdr)))
938 continue;
939 */
940
941 if (ntohs(udpHdr->source) != BOOTP_SERVER_PORT)
942 continue;
943 if (ntohs(udpHdr->dest) != BOOTP_CLIENT_PORT)
944 continue;
945 /* Go on with this packet; it looks sane */
946
947 /* Originally copied sizeof (*bresp) - this is a security
948 problem due to a potential underflow of the source
949 buffer. Also, it trusted that the packet was properly
950 0xFF terminated, which is not true in the case of the
951 DHCP server on Cisco 800 series ISDN router. */
952
953 memset (bresp, 0xFF, sizeof (*bresp));
954 memcpy (bresp, (char *) udpHdr + sizeof (*udpHdr), j - sizeof (*ipHdr) - sizeof (*udpHdr));
955
956 /* sanity checks */
957 if (bresp->id != breq->id) continue;
958 if (bresp->opcode != BOOTP_OPCODE_REPLY) continue;
959 if (bresp->hwlength != breq->hwlength) continue;
960 if (memcmp(bresp->hwaddr, breq->hwaddr, bresp->hwlength)) continue;
961 i = dhcpMessageType(bresp);
962 if (!(i == -1 && useBootpPacket) && (i != dhcpResponseType))
963 continue;
964 if (memcmp(bresp->vendor, vendCookie, 4)) continue;
965 /* if (respondant) *respondant = tmpAddress; */
966 gotit = 1;
967
968 break;
969
970 default:
971 close(sin);
972 return perrorstr("select");
973 }
974 }
975
976 if (!gotit) {
977 close(sin);
978 return _("No DHCP reply received");
979 }
980
981 close(sin);
982
983 debugbootpRequest("bresp", bresp);
984
985 return NULL;
986 }
987
988 static void addVendorCode(struct bootpRequest * breq, unsigned char option,
989 unsigned char length, void * data) {
990 unsigned char * chptr;
991 int theOption, theLength;
992
993 chptr = breq->vendor;
994 chptr += 4;
995 while (*chptr != 0xFF && *chptr != option) {
996 theOption = *chptr++;
997 if (!theOption) continue;
998 theLength = *chptr++;
999 chptr += theLength;
1000 }
1001
1002 *chptr++ = option;
1003 *chptr++ = length;
1004 memcpy(chptr, data, length);
1005 chptr[length] = 0xff;
1006 }
1007
1008 static int getVendorCode(struct bootpRequest * bresp, unsigned char option,
1009 void * data) {
1010 unsigned char * chptr;
1011 unsigned int length, theOption;
1012
1013 chptr = bresp->vendor;
1014 chptr += 4;
1015 while (*chptr != 0xFF && *chptr != option) {
1016 theOption = *chptr++;
1017 if (!theOption) continue;
1018 length = *chptr++;
1019 chptr += length;
1020 }
1021
1022 if (*chptr++ == 0xff) return 1;
1023
1024 length = *chptr++;
1025 memcpy(data, chptr, length);
1026
1027 return 0;
1028 }
1029
1030 static int createSocket(void) {
1031 struct sockaddr_in clientAddr;
1032 int s;
1033
1034 s = socket(AF_INET, SOCK_DGRAM, 0);
1035 if (s < 0)
1036 return -1;
1037
1038 memset(&clientAddr.sin_addr, 0, sizeof(&clientAddr.sin_addr));
1039 clientAddr.sin_family = AF_INET;
1040 clientAddr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */
1041
1042 if (bind(s, (struct sockaddr *) &clientAddr, sizeof(clientAddr))) {
1043 close(s);
1044 return -1;
1045 }
1046
1047 return s;
1048 }
1049
1050 static int dhcpRelease(struct intfInfo * intf) {
1051 struct bootpRequest breq, bresp;
1052 unsigned char messageType;
1053 struct sockaddr_in serverAddr;
1054 char * chptr;
1055 int s;
1056
1057 if (!(intf->set & INTFINFO_HAS_LEASE)) {
1058 disableInterface(intf->device);
1059 syslog(LOG_INFO, "disabling interface %s", intf->device);
1060
1061 return 0;
1062 }
1063
1064 if ((s = createSocket()) < 0) return 1;
1065
1066 if ((chptr = prepareRequest(&breq, s, intf->device, time(NULL)))) {
1067 close(s);
1068 while (1) {
1069 disableInterface(intf->device);
1070 return 0;
1071 }
1072 }
1073
1074 messageType = DHCP_TYPE_RELEASE;
1075 addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
1076 memcpy(&breq.ciaddr, &intf->ip, sizeof(breq.ciaddr));
1077
1078 serverAddr.sin_family = AF_INET;
1079 serverAddr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
1080 serverAddr.sin_addr = intf->bootServer;
1081
1082 if (!handleTransaction(s, NULL, &breq, &bresp, &serverAddr, NULL, 0,
1083 NORESPONSE)) {
1084 disableInterface(intf->device);
1085 close(s);
1086 return 0;
1087 }
1088
1089 disableInterface(intf->device);
1090 close(s);
1091
1092 syslog(LOG_INFO, "disabling interface %s", intf->device);
1093
1094 return 1;
1095 }
1096
1097 /* This is somewhat broken. We try only to renew the lease. If we fail,
1098 we don't try to completely rebind. This doesn't follow the DHCP spec,
1099 but for the install it should be a reasonable compromise. */
1100 static int dhcpRenew(struct intfInfo * intf) {
1101 struct bootpRequest breq, bresp;
1102 unsigned char messageType;
1103 struct sockaddr_in serverAddr;
1104 char * chptr;
1105 int s;
1106 int i;
1107
1108 s = createSocket();
1109
1110 if ((chptr = prepareRequest(&breq, s, intf->device, time(NULL)))) {
1111 close(s);
1112 while (1); /* problem */
1113 }
1114
1115 messageType = DHCP_TYPE_REQUEST;
1116 addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
1117 memcpy(&breq.ciaddr, &intf->ip, sizeof(breq.ciaddr));
1118
1119 i = htonl(intf->reqLease);
1120 addVendorCode(&breq, DHCP_OPTION_LEASE, 4, &i);
1121
1122 serverAddr.sin_family = AF_INET;
1123 serverAddr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
1124 serverAddr.sin_addr = intf->bootServer;
1125
1126 if (handleTransaction(s, NULL, &breq, &bresp, &serverAddr, NULL, 0,
1127 DHCP_TYPE_ACK)) {
1128 close(s);
1129 return 1;
1130 }
1131
1132 parseLease(&bresp, intf);
1133
1134 syslog(LOG_INFO, "renewed lease for interface %s", intf->device);
1135
1136 close(s);
1137 return 0;
1138 }
1139
1140 static void parseLease(struct bootpRequest * bresp, struct intfInfo * intf) {
1141 int lease;
1142 time_t now;
1143
1144 intf->set &= INTFINFO_HAS_LEASE;
1145 if (getVendorCode(bresp, DHCP_OPTION_LEASE, &lease))
1146 return;
1147
1148 lease = ntohl(lease);
1149
1150 if (lease && lease != 0xffffffff) {
1151 now = time(NULL);
1152 intf->set |= INTFINFO_HAS_LEASE;
1153 intf->leaseExpiration = now + lease;
1154 intf->renewAt = now + (7 * lease / 8);
1155 }
1156 }
1157
1158 char * readSearchPath(void) {
1159 int fd;
1160 struct stat sb;
1161 char * buf;
1162 char * start;
1163
1164 fd = open("/etc/resolv.conf", O_RDONLY);
1165 if (fd < 0) return NULL;
1166
1167 fstat(fd, &sb);
1168 buf = alloca(sb.st_size + 2);
1169 if (read(fd, buf, sb.st_size) != sb.st_size) return NULL;
1170 buf[sb.st_size] = '\n';
1171 buf[sb.st_size + 1] = '\0';
1172 close(fd);
1173
1174 start = buf;
1175 while (start && *start) {
1176 while (isspace(*start) && (*start != '\n')) start++;
1177 if (*start == '\n') {
1178 start++;
1179 continue;
1180 }
1181
1182 if (!strncmp("search", start, 6) && isspace(start[6])) {
1183 start += 6;
1184 while (isspace(*start) && *start != '\n') start++;
1185 if (*start == '\n') return NULL;
1186
1187 buf = strchr(start, '\n');
1188 *buf = '\0';
1189 return strdup(start);
1190 }
1191 }
1192
1193 return NULL;
1194 }
1195
1196 static void createResolvConf(struct intfInfo * intf, char * domain,
1197 int isSearchPath) {
1198 FILE * f;
1199 int i;
1200 char * chptr;
1201
1202 /* force a reread of /etc/resolv.conf if we need it again */
1203 res_close();
1204
1205 if (!domain) {
1206 domain = readSearchPath();
1207 if (domain) {
1208 chptr = alloca(strlen(domain) + 1);
1209 strcpy(chptr, domain);
1210 free(domain);
1211 domain = chptr;
1212 isSearchPath = 1;
1213 }
1214 }
1215
1216 f = fopen("/etc/resolv.conf", "w");
1217 if (!f) {
1218 syslog(LOG_ERR, "cannot create /etc/resolv.conf: %s\n",
1219 strerror(errno));
1220 return;
1221 }
1222
1223 if (domain && isSearchPath) {
1224 fprintf(f, "search %s\n", domain);
1225 } else if (domain) {
1226 fprintf(f, "search");
1227 chptr = domain;
1228 do {
1229 fprintf(f, " %s", chptr);
1230 chptr = strchr(chptr, '.');
1231 if (chptr) {
1232 chptr++;
1233 if (!strchr(chptr, '.'))
1234 chptr = NULL;
1235 }
1236 } while (chptr);
1237
1238 fprintf(f, "\n");
1239 }
1240
1241 for (i = 0; i < intf->numDns; i++)
1242 fprintf(f, "nameserver %s\n", inet_ntoa(intf->dnsServers[i]));
1243
1244 fclose(f);
1245
1246 /* force a reread of /etc/resolv.conf */
1247 endhostent();
1248 }
1249
1250 void setupDns(struct intfInfo * intf, struct overrideInfo * override) {
1251 char * hn, * dn = NULL;
1252 struct hostent * he;
1253
1254 if (override->flags & OVERRIDE_FLAG_NODNS) {
1255 return;
1256 }
1257
1258 if (override->searchPath) {
1259 createResolvConf(intf, override->searchPath, 1);
1260 return;
1261 }
1262
1263 if (intf->set & NETINFO_HAS_DNS) {
1264 if (!(intf->set & NETINFO_HAS_DOMAIN)) {
1265 if (intf->set & NETINFO_HAS_HOSTNAME) {
1266 hn = intf->hostname;
1267 } else {
1268 createResolvConf(intf, NULL, 0);
1269
1270 he = gethostbyaddr((char *) &intf->ip, sizeof(intf->ip),
1271 AF_INET);
1272 if (he) {
1273 hn = he->h_name;
1274 } else {
1275 hn = NULL;
1276 }
1277 }
1278
1279 if (hn) {
1280 dn = strchr(hn, '.');
1281 if (dn)
1282 dn++;
1283 }
1284 } else {
1285 dn = intf->domain;
1286 }
1287
1288 createResolvConf(intf, dn, 0);
1289 }
1290 }
1291
1292 static char * doDhcp(char * device, int flags, int reqLease,
1293 char * reqHostname, struct intfInfo * intf,
1294 struct overrideInfo * override) {
1295 int s, i;
1296 struct sockaddr_in serverAddr;
1297 struct sockaddr_in clientAddr;
1298 struct sockaddr_in broadcastAddr;
1299 struct bootpRequest breq, bresp;
1300 struct bootpRequest protoReq;
1301 unsigned char * chptr;
1302 unsigned char messageType;
1303 time_t startTime = time(NULL);
1304 int true = 1;
1305 char optionsRequested[50];
1306 int numOptions;
1307 short aShort;
1308
1309 memset(intf, 0, sizeof(*intf));
1310 strcpy(intf->device, device);
1311 intf->reqLease = reqLease;
1312 intf->set |= INTFINFO_HAS_REQLEASE;
1313
1314 s = socket(AF_INET, SOCK_DGRAM, 0);
1315 if (s < 0) {
1316 return perrorstr("socket");
1317 }
1318
1319 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &true, sizeof(true))) {
1320 close(s);
1321 return perrorstr("setsockopt");
1322 }
1323
1324 if (flags & DHCP_FLAG_NOCONFIG) {
1325 if ((chptr = getInterfaceInfo(intf, s))) {
1326 close(s);
1327 return chptr;
1328 }
1329 } else if ((chptr = prepareInterface(intf, s))) {
1330 close(s);
1331 return chptr;
1332 }
1333
1334 if ((chptr = prepareRequest(&breq, s, intf->device, startTime))) {
1335 close(s);
1336 disableInterface(intf->device);
1337 return chptr;
1338 }
1339
1340 messageType = DHCP_TYPE_DISCOVER;
1341 addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
1342
1343 memset(&clientAddr.sin_addr, 0, sizeof(&clientAddr.sin_addr));
1344 clientAddr.sin_family = AF_INET;
1345 clientAddr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */
1346
1347 if (bind(s, (struct sockaddr *) &clientAddr, sizeof(clientAddr))) {
1348 disableInterface(intf->device);
1349 close(s);
1350 return perrorstr("bind");
1351 }
1352
1353 serverAddr.sin_family = AF_INET;
1354 serverAddr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */
1355
1356 #if 0
1357 /* seems like a good idea?? */
1358 if (intf->set & INTFINFO_HAS_BOOTSERVER)
1359 serverAddr.sin_addr = intf->bootServer;
1360 #endif
1361
1362 broadcastAddr.sin_family = AF_INET;
1363 broadcastAddr.sin_port = htons(BOOTP_SERVER_PORT);
1364
1365 #if 0
1366 /* this too! */
1367 if (intf->set & INTFINFO_HAS_BROADCAST)
1368 broadcastAddr.sin_addr = intf->broadcast;
1369 #endif
1370
1371 memset(&broadcastAddr.sin_addr, 0xff,
1372 sizeof(broadcastAddr.sin_addr)); /* all 1's broadcast */
1373
1374 syslog (LOG_DEBUG, "PUMP: sending discover\n");
1375
1376 if ((chptr = handleTransaction(s, override, &breq, &bresp, &broadcastAddr,
1377 NULL, 1, DHCP_TYPE_OFFER))) {
1378 close(s);
1379 disableInterface(intf->device);
1380 return chptr;
1381 }
1382
1383 /* Otherwise we're in the land of bootp */
1384 if (dhcpMessageType(&bresp) == DHCP_TYPE_OFFER) {
1385 /* Admittedly, this seems a bit odd. If we find a dhcp server, we
1386 rerun the dhcp discover broadcast, but with the proper option
1387 field this time. This makes me rfc compliant. */
1388 syslog (LOG_DEBUG, "got dhcp offer\n");
1389
1390 initVendorCodes(&breq);
1391
1392 aShort = ntohs(sizeof(struct bootpRequest));
1393 addVendorCode(&breq, DHCP_OPTION_MAXSIZE, 2, &aShort);
1394
1395 numOptions = 0;
1396 optionsRequested[numOptions++] = BOOTP_OPTION_NETMASK;
1397 optionsRequested[numOptions++] = BOOTP_OPTION_GATEWAY;
1398 optionsRequested[numOptions++] = BOOTP_OPTION_DNS;
1399 optionsRequested[numOptions++] = BOOTP_OPTION_DOMAIN;
1400 optionsRequested[numOptions++] = BOOTP_OPTION_BROADCAST;
1401 optionsRequested[numOptions++] = BOOTP_OPTION_HOSTNAME;
1402 addVendorCode(&breq, DHCP_OPTION_OPTIONREQ, numOptions,
1403 optionsRequested);
1404
1405 if (reqHostname) {
1406 syslog(LOG_DEBUG, "HOSTNAME: requesting %s\n", reqHostname);
1407 addVendorCode(&breq, BOOTP_OPTION_HOSTNAME, strlen(reqHostname),
1408 reqHostname);
1409 }
1410
1411 i = htonl(intf->reqLease);
1412 addVendorCode(&breq, DHCP_OPTION_LEASE, 4, &i);
1413
1414 protoReq = breq;
1415
1416 syslog (LOG_DEBUG, "PUMP: sending second discover");
1417
1418 messageType = DHCP_TYPE_DISCOVER;
1419 addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
1420
1421 /* Send another DHCP_REQUEST with the proper option list */
1422 if ((chptr = handleTransaction(s, override, &breq, &bresp,
1423 &broadcastAddr, NULL, 1,
1424 DHCP_TYPE_OFFER))) {
1425 close(s);
1426 disableInterface(intf->device);
1427 return chptr;
1428 }
1429
1430
1431 if (dhcpMessageType(&bresp) != DHCP_TYPE_OFFER) {
1432 close(s);
1433 disableInterface(intf->device);
1434 return "dhcp offer expected";
1435 }
1436
1437 syslog (LOG_DEBUG, "PUMP: got an offer");
1438
1439 if (getVendorCode(&bresp, DHCP_OPTION_SERVER, &serverAddr.sin_addr)) {
1440 syslog (LOG_DEBUG, "DHCPOFFER didn't include server address");
1441 intf->bootServer = broadcastAddr.sin_addr;
1442 }
1443
1444 breq = protoReq;
1445 messageType = DHCP_TYPE_REQUEST;
1446 addVendorCode(&breq, DHCP_OPTION_TYPE, 1, &messageType);
1447
1448 addVendorCode(&breq, DHCP_OPTION_SERVER, 4, &serverAddr.sin_addr);
1449 addVendorCode(&breq, DHCP_OPTION_REQADDR, 4, &bresp.yiaddr);
1450
1451 /* why do we need to use the broadcast address here? better reread the
1452 spec! */
1453 if ((chptr = handleTransaction(s, override, &breq, &bresp,
1454 &broadcastAddr, NULL, 0,
1455 DHCP_TYPE_ACK))) {
1456 close(s);
1457 disableInterface(intf->device);
1458 return chptr;
1459 }
1460
1461 syslog (LOG_DEBUG, "PUMP: got lease");
1462
1463 parseLease(&bresp, intf);
1464
1465 if (getVendorCode(&bresp, DHCP_OPTION_SERVER, &intf->bootServer)) {
1466 syslog (LOG_DEBUG, "DHCPACK didn't include server address");
1467 intf->bootServer = broadcastAddr.sin_addr;
1468 }
1469
1470 intf->set |= INTFINFO_HAS_BOOTSERVER;
1471 }
1472
1473 parseReply(&bresp, intf);
1474 if (flags & DHCP_FLAG_FORCEHNLOOKUP)
1475 intf->set &= ~(NETINFO_HAS_DOMAIN | NETINFO_HAS_HOSTNAME);
1476
1477 chptr = setupInterface(intf, s);
1478 if (chptr) {
1479 close(s);
1480 disableInterface(intf->device);
1481 return chptr;
1482 }
1483
1484 syslog(LOG_INFO, "configured interface %s", intf->device);
1485
1486 if (intf->set & NETINFO_HAS_GATEWAY) {
1487 chptr = setupDefaultGateway(&intf->gateway, s);
1488 }
1489
1490 setupDns(intf, override);
1491
1492 close(s);
1493
1494 return NULL;
1495 }
1496
1497 static void runDaemon(int sock, char * configFile) {
1498 int conn;
1499 struct sockaddr_un addr;
1500 int addrLength;
1501 struct command cmd;
1502 struct intfInfo intf[20];
1503 int numInterfaces = 0;
1504 int i;
1505 int closest;
1506 struct timeval tv;
1507 fd_set fds;
1508 struct overrideInfo * overrides = NULL;
1509 struct overrideInfo emptyOverride, * o;
1510
1511 readPumpConfig(configFile, &overrides);
1512 if (!overrides) {
1513 overrides = &emptyOverride;
1514 overrides->intf.device[0] = '\0';
1515 }
1516
1517 while (1) {
1518 FD_ZERO(&fds);
1519 FD_SET(sock, &fds);
1520
1521 tv.tv_sec = tv.tv_usec = 0;
1522 closest = -1;
1523 if (numInterfaces) {
1524 for (i = 0; i < numInterfaces; i++)
1525 if ((intf[i].set & INTFINFO_HAS_LEASE) &&
1526 (closest == -1 ||
1527 (intf[closest].renewAt > intf[i].renewAt)))
1528 closest = i;
1529 if (closest != -1) {
1530 tv.tv_sec = intf[closest].renewAt - time(NULL);
1531 if (tv.tv_sec <= 0) {
1532 dhcpRenew(intf + closest);
1533 continue;
1534 }
1535 }
1536 }
1537
1538 if (select(sock + 1, &fds, NULL, NULL,
1539 closest != -1 ? &tv : NULL) > 0) {
1540 conn = accept(sock, &addr, &addrLength);
1541
1542 if (read(conn, &cmd, sizeof(cmd)) != sizeof(cmd)) {
1543 close(conn);
1544 continue;
1545 }
1546
1547 switch (cmd.type) {
1548 case CMD_DIE:
1549 for (i = 0; i < numInterfaces; i++)
1550 dhcpRelease(intf + i);
1551
1552 syslog(LOG_INFO, "terminating at root's request");
1553
1554 cmd.type = CMD_RESULT;
1555 cmd.u.result = 0;
1556 write(conn, &cmd, sizeof(cmd));
1557 exit(0);
1558
1559 case CMD_STARTIFACE:
1560 o = overrides;
1561 while (*o->intf.device &&
1562 strcmp(o->intf.device, cmd.u.start.device)) {
1563 o++;
1564 }
1565 if (!*o->intf.device) o = overrides;
1566
1567 if (doDhcp(cmd.u.start.device,
1568 cmd.u.start.flags, cmd.u.start.reqLease,
1569 cmd.u.start.reqHostname[0] ?
1570 cmd.u.start.reqHostname : NULL,
1571 intf + numInterfaces, o)) {
1572 cmd.u.result = 1;
1573 } else {
1574 cmd.u.result = 0;
1575 numInterfaces++;
1576 }
1577 break;
1578
1579 case CMD_FORCERENEW:
1580 for (i = 0; i < numInterfaces; i++)
1581 if (!strcmp(intf[i].device, cmd.u.renew.device)) break;
1582 if (i == numInterfaces)
1583 cmd.u.result = RESULT_UNKNOWNIFACE;
1584 else
1585 cmd.u.result = dhcpRenew(intf + i);
1586 break;
1587
1588 case CMD_STOPIFACE:
1589 for (i = 0; i < numInterfaces; i++)
1590 if (!strcmp(intf[i].device, cmd.u.stop.device)) break;
1591 if (i == numInterfaces)
1592 cmd.u.result = RESULT_UNKNOWNIFACE;
1593 else {
1594 cmd.u.result = dhcpRelease(intf + i);
1595 if (numInterfaces == 1) {
1596 cmd.type = CMD_RESULT;
1597 write(conn, &cmd, sizeof(cmd));
1598
1599 syslog(LOG_INFO, "terminating as there are no "
1600 "more devices under management");
1601
1602 exit(0);
1603 }
1604
1605 intf[i] = intf[numInterfaces - 1];
1606 numInterfaces--;
1607 }
1608 break;
1609
1610 case CMD_REQSTATUS:
1611 for (i = 0; i < numInterfaces; i++)
1612 if (!strcmp(intf[i].device, cmd.u.stop.device)) break;
1613 if (i == numInterfaces) {
1614 cmd.u.result = RESULT_UNKNOWNIFACE;
1615 } else {
1616 cmd.type = CMD_STATUS;
1617 cmd.u.status.intf = intf[i];
1618 if (intf[i].set & NETINFO_HAS_HOSTNAME)
1619 strncpy(cmd.u.status.hostname,
1620 intf->hostname, sizeof(cmd.u.status.hostname));
1621 cmd.u.status.hostname[sizeof(cmd.u.status.hostname)] = '\0';
1622
1623 if (intf[i].set & NETINFO_HAS_DOMAIN)
1624 strncpy(cmd.u.status.domain,
1625 intf->domain, sizeof(cmd.u.status.domain));
1626 cmd.u.status.domain[sizeof(cmd.u.status.domain) - 1] = '\0';
1627
1628 if (intf[i].set & INTFINFO_HAS_BOOTFILE)
1629 strncpy(cmd.u.status.bootFile,
1630 intf->bootFile, sizeof(cmd.u.status.bootFile));
1631 cmd.u.status.bootFile[sizeof(cmd.u.status.bootFile) - 1] =
1632 '\0';
1633 }
1634
1635 case CMD_STATUS:
1636 case CMD_RESULT:
1637 /* can't happen */
1638 break;
1639 }
1640
1641 if (cmd.type != CMD_STATUS) cmd.type = CMD_RESULT;
1642 write(conn, &cmd, sizeof(cmd));
1643
1644 close(conn);
1645 }
1646 }
1647
1648 exit(0);
1649 }
1650
1651 static int openControlSocket(char * configFile) {
1652 struct sockaddr_un addr;
1653 int sock;
1654 size_t addrLength;
1655 pid_t child;
1656 int status;
1657
1658 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1659 return -1;
1660
1661 addr.sun_family = AF_UNIX;
1662 strcpy(addr.sun_path, CONTROLSOCKET);
1663 addrLength = sizeof(addr.sun_family) + strlen(addr.sun_path);
1664
1665 if (!connect(sock, (struct sockaddr *) &addr, addrLength))
1666 return sock;
1667
1668 if (errno != ENOENT && errno != ECONNREFUSED) {
1669 fprintf(stderr, "failed to connect to %s: %s\n", CONTROLSOCKET,
1670 strerror(errno));
1671 close(sock);
1672 return -1;
1673 }
1674
1675 if (!(child = fork())) {
1676 close(sock);
1677
1678 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
1679 fprintf(stderr, "failed to create socket: %s\n", strerror(errno));
1680 exit(1);
1681 }
1682
1683 unlink(CONTROLSOCKET);
1684 umask(077);
1685 if (bind(sock, (struct sockaddr *) &addr, addrLength)) {
1686 fprintf(stderr, "bind to %s failed: %s\n", CONTROLSOCKET,
1687 strerror(errno));
1688 exit(1);
1689 }
1690 umask(033);
1691
1692 listen(sock, 5);
1693
1694 if (fork()) _exit(0);
1695
1696 close(0);
1697 close(1);
1698 close(2);
1699
1700 openlog("pumpd", LOG_PID, LOG_DAEMON);
1701 {
1702 time_t t;
1703
1704 t = time(NULL);
1705 syslog(LOG_INFO, "starting at %s\n", ctime(&t));
1706 }
1707
1708 runDaemon(sock, configFile);
1709 }
1710
1711 waitpid(child, &status, 0);
1712 if (!WIFEXITED(status) || WEXITSTATUS(status))
1713 return -1;
1714
1715 if (!connect(sock, (struct sockaddr *) &addr, addrLength))
1716 return sock;
1717
1718 fprintf(stderr, "failed to connect to %s: %s\n", CONTROLSOCKET,
1719 strerror(errno));
1720
1721 return 0;
1722 }
1723
1724 void printStatus(struct intfInfo i, char * hostname, char * domain,
1725 char * bootFile) {
1726 int j;
1727
1728 printf("Device %s\n", i.device);
1729 printf("\tIP: %s\n", inet_ntoa(i.ip));
1730 printf("\tNetmask: %s\n", inet_ntoa(i.netmask));
1731 printf("\tBroadcast: %s\n", inet_ntoa(i.broadcast));
1732 printf("\tNetwork: %s\n", inet_ntoa(i.network));
1733 printf("\tBoot server %s\n", inet_ntoa(i.bootServer));
1734
1735 if (i.set & NETINFO_HAS_GATEWAY)
1736 printf("\tGateway: %s\n", inet_ntoa(i.gateway));
1737
1738 if (i.set & INTFINFO_HAS_BOOTFILE)
1739 printf("\tBoot file: %s\n", bootFile);
1740
1741 if (i.set & NETINFO_HAS_HOSTNAME)
1742 printf("\tHostname: %s\n", hostname);
1743
1744 if (i.set & NETINFO_HAS_DOMAIN)
1745 printf("\tDomain: %s\n", domain);
1746
1747 if (i.numDns) {
1748 printf("\tNameservers:");
1749 for (j = 0; j < i.numDns; j++)
1750 printf(" %s", inet_ntoa(i.dnsServers[j]));
1751 printf("\n");
1752 }
1753
1754 if (i.set & INTFINFO_HAS_LEASE) {
1755 printf("\tRenewal time: %s", ctime(&i.renewAt));
1756 printf("\tExpiration time: %s", ctime(&i.leaseExpiration));
1757 }
1758 }
1759
1760 int main (int argc, char ** argv) {
1761 char * device = "eth0";
1762 char * hostname = "";
1763 poptContext optCon;
1764 int rc;
1765 int test = 0;
1766 int flags = 0;
1767 int lease = 6;
1768 int killDaemon = 0;
1769 int release = 0, renew = 0, status = 0, lookupHostname = 0;
1770 struct command cmd, response;
1771 char * configFile = "/etc/pump.conf";
1772 struct overrideInfo * overrides;
1773 int cont;
1774 struct poptOption options[] = {
1775 { "config-file", 'c', POPT_ARG_STRING, &configFile, 0,
1776 N_("Configuration file to use instead of "
1777 "/etc/pump.conf") },
1778 { "hostname", 'h', POPT_ARG_STRING, &hostname, 0,
1779 N_("Hostname to request"), N_("hostname") },
1780 { "interface", 'i', POPT_ARG_STRING, &device, 0,
1781 N_("Interface to configure (normally eth0)"),
1782 N_("iface") },
1783 { "kill", 'k', POPT_ARG_NONE, &killDaemon, 0,
1784 N_("Kill daemon (and disable all interfaces)"), NULL },
1785 { "lease", 'l', POPT_ARG_INT, &lease, 0,
1786 N_("Lease time to request (in hours)"), N_("hours") },
1787 { "lookup-hostname", '\0', POPT_ARG_NONE, &lookupHostname, 0,
1788 N_("Force lookup of hostname") },
1789 { "release", 'r', POPT_ARG_NONE, &release, 0,
1790 N_("Release interface"), NULL },
1791 { "renew", 'R', POPT_ARG_NONE, &renew, 0,
1792 N_("Force immediate lease renewal"), NULL },
1793 { "status", 's', POPT_ARG_NONE, &status, 0,
1794 N_("Display interface status"), NULL },
1795 /*{ "test", 't', POPT_ARG_NONE, &test, 0,
1796 N_("Don't change the interface configuration or "
1797 "run as a deamon.") },*/
1798 POPT_AUTOHELP
1799 { NULL, '\0', 0, NULL, 0 }
1800 };
1801
1802 optCon = poptGetContext(PROGNAME, argc, argv, options,0);
1803 poptReadDefaultConfig(optCon, 1);
1804
1805 if ((rc = poptGetNextOpt(optCon)) < -1) {
1806 fprintf(stderr, _("%s: bad argument %s: %s\n"), PROGNAME,
1807 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
1808 poptStrerror(rc));
1809 return 1;
1810 }
1811
1812 if (poptGetArg(optCon)) {
1813 fprintf(stderr, _("%s: no extra parameters are expected\n"), PROGNAME);
1814 return 1;
1815 }
1816
1817 /* make sure the config file is parseable before going on any further */
1818 if (readPumpConfig(configFile, &overrides)) return 1;
1819
1820 if (geteuid()) {
1821 fprintf(stderr, _("%s: must be run as root\n"), PROGNAME);
1822 exit(1);
1823 }
1824
1825 if (test)
1826 flags = DHCP_FLAG_NODAEMON | DHCP_FLAG_NOCONFIG;
1827 if (lookupHostname)
1828 flags |= DHCP_FLAG_FORCEHNLOOKUP;
1829
1830 cont = openControlSocket(configFile);
1831 if (cont < 0)
1832 exit(1);
1833
1834 if (killDaemon) {
1835 cmd.type = CMD_DIE;
1836 } else if (status) {
1837 cmd.type = CMD_REQSTATUS;
1838 strcpy(cmd.u.reqstatus.device, device);
1839 } else if (renew) {
1840 cmd.type = CMD_FORCERENEW;
1841 strcpy(cmd.u.renew.device, device);
1842 } else if (release) {
1843 cmd.type = CMD_STOPIFACE;
1844 strcpy(cmd.u.stop.device, device);
1845 } else {
1846 cmd.type = CMD_STARTIFACE;
1847 strcpy(cmd.u.start.device, device);
1848 cmd.u.start.flags = flags;
1849 cmd.u.start.reqLease = lease * 60 * 60;
1850 strcpy(cmd.u.start.reqHostname, hostname);
1851 }
1852
1853 write(cont, &cmd, sizeof(cmd));
1854 read(cont, &response, sizeof(response));
1855
1856 if (response.type == CMD_RESULT && response.u.result &&
1857 cmd.type == CMD_STARTIFACE) {
1858 cont = openControlSocket(configFile);
1859 if (cont < 0)
1860 exit(1);
1861 write(cont, &cmd, sizeof(cmd));
1862 read(cont, &response, sizeof(response));
1863 }
1864
1865 if (response.type == CMD_RESULT) {
1866 if (response.u.result) {
1867 fprintf(stderr, "Operation failed.\n");
1868 return 1;
1869 }
1870 } else if (response.type == CMD_STATUS) {
1871 printStatus(response.u.status.intf, response.u.status.hostname,
1872 response.u.status.domain, response.u.status.bootFile);
1873 }
1874
1875 return 0;
1876 }

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26