1/* dhcpc.c
2 *
3 * udhcp DHCP client
4 *
5 * Russ Dill <Russ.Dill@asu.edu> July 2001
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <stdio.h>
23#include <sys/time.h>
24#include <sys/types.h>
25#include <sys/file.h>
26#include <unistd.h>
27#include <getopt.h>
28#include <stdlib.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <signal.h>
33#include <time.h>
34#include <string.h>
35#include <sys/ioctl.h>
36#include <net/if.h>
37#include <errno.h>
38
39#include "dhcpd.h"
40#include "dhcpc.h"
41#include "options.h"
42#include "clientpacket.h"
43#include "packet.h"
44#include "script.h"
45#include "socket.h"
46#include "debug.h"
47#include "pidfile.h"
48#include "uptime.h"
49
50static int state;
51static unsigned long requested_ip; /* = 0 */
52static unsigned long server_addr;
53static unsigned long timeout;
54static int packet_num; /* = 0 */
55static int fd = -1;
56static int signal_pipe[2];
57
58#define LISTEN_NONE 0
59#define LISTEN_KERNEL 1
60#define LISTEN_RAW 2
61static int listen_mode;
62
63#define DEFAULT_SCRIPT	"/usr/share/udhcpc/default.script"
64
65struct client_config_t client_config = {
66	/* Default options. */
67	abort_if_no_lease: 0,
68	foreground: 0,
69	quit_after_lease: 0,
70	background_if_no_lease: 0,
71	interface: "eth0",
72	pidfile: NULL,
73	script: DEFAULT_SCRIPT,
74	clientid: NULL,
75	hostname: NULL,
76	ifindex: 0,
77	arp: "\0\0\0\0\0\0",		/* appease gcc-3.0 */
78};
79
80#ifndef BB_VER
81static void show_usage(void)
82{
83	printf(
84"Usage: udhcpc [OPTIONS]\n\n"
85"  -c, --clientid=CLIENTID         Client identifier\n"
86"  -H, --hostname=HOSTNAME         Client hostname\n"
87"  -h                              Alias for -H\n"
88"  -f, --foreground                Do not fork after getting lease\n"
89"  -b, --background                Fork to background if lease cannot be\n"
90"                                  immediately negotiated.\n"
91"  -i, --interface=INTERFACE       Interface to use (default: eth0)\n"
92"  -n, --now                       Exit with failure if lease cannot be\n"
93"                                  immediately negotiated.\n"
94"  -p, --pidfile=file              Store process ID of daemon in file\n"
95"  -q, --quit                      Quit after obtaining lease\n"
96"  -r, --request=IP                IP address to request (default: none)\n"
97"  -s, --script=file               Run file at dhcp events (default:\n"
98"                                  " DEFAULT_SCRIPT ")\n"
99"  -v, --version                   Display version\n"
100	);
101	exit(0);
102}
103#endif
104
105
106/* just a little helper */
107static void change_mode(int new_mode)
108{
109	DEBUG(LOG_INFO, "entering %s listen mode",
110		new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
111
112	listen_mode = new_mode;
113	if (fd >= 0) {
114		close(fd);
115		fd = -1;
116	}
117
118	if (new_mode == LISTEN_KERNEL)
119		fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
120	else if (new_mode != LISTEN_NONE)
121		fd = raw_socket(client_config.ifindex);
122	/* else LISTEN_NONE: fd stays closed */
123}
124
125
126/* perform a renew */
127static void perform_renew(void)
128{
129	LOG(LOG_INFO, "Performing a DHCP renew");
130	switch (state) {
131	case BOUND:
132		change_mode(LISTEN_KERNEL);
133	case RENEWING:
134	case REBINDING:
135		state = RENEW_REQUESTED;
136		break;
137	case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
138		run_script(NULL, "deconfig");
139	case REQUESTING:
140	case RELEASED:
141		change_mode(LISTEN_RAW);
142		state = INIT_SELECTING;
143		break;
144	case INIT_SELECTING:
145		break;
146	}
147
148	/* start things over */
149	packet_num = 0;
150
151	/* Kill any timeouts because the user wants this to hurry along */
152	timeout = 0;
153}
154
155
156/* perform a release */
157static void perform_release(void)
158{
159	char buffer[16];
160	struct in_addr temp_addr;
161
162	/* send release packet */
163	if (state == BOUND || state == RENEWING || state == REBINDING) {
164		temp_addr.s_addr = server_addr;
165		sprintf(buffer, "%s", inet_ntoa(temp_addr));
166		temp_addr.s_addr = requested_ip;
167		LOG(LOG_INFO, "Unicasting a release of %s to %s",
168				inet_ntoa(temp_addr), buffer);
169		send_release(server_addr, requested_ip); /* unicast */
170		run_script(NULL, "deconfig");
171	}
172	LOG(LOG_INFO, "Entering released state");
173
174	change_mode(LISTEN_NONE);
175	state = RELEASED;
176	timeout = 0x7fffffff;
177}
178
179
180/* Exit and cleanup */
181static void exit_client(int retval)
182{
183	pidfile_delete(client_config.pidfile);
184	CLOSE_LOG();
185	exit(retval);
186}
187
188
189/* Signal handler */
190static void signal_handler(int sig)
191{
192	if (write(signal_pipe[1], &sig, sizeof(sig)) < 0) {
193		LOG(LOG_ERR, "Could not send signal: %s",
194			strerror(errno));
195	}
196}
197
198
199static void background(void)
200{
201	int pid_fd;
202
203	pid_fd = pidfile_acquire(client_config.pidfile); /* hold lock during fork. */
204	while (pid_fd >= 0 && pid_fd < 3) pid_fd = dup(pid_fd); /* don't let daemon close it */
205	if (daemon(0, 0) == -1) {
206		perror("fork");
207		exit_client(1);
208	}
209	client_config.foreground = 1; /* Do not fork again. */
210	client_config.background_if_no_lease = 0;
211	pidfile_write_release(pid_fd);
212}
213
214
215#ifdef COMBINED_BINARY
216int udhcpc_main(int argc, char *argv[])
217#else
218int main(int argc, char *argv[])
219#endif
220{
221	unsigned char *temp, *message;
222	unsigned long t1 = 0, t2 = 0, xid = 0;
223	unsigned long start = 0, lease;
224	fd_set rfds;
225	int retval;
226	struct timeval tv;
227	int c, len;
228	struct dhcpMessage packet;
229	struct in_addr temp_addr;
230	int pid_fd;
231	time_t now;
232	int max_fd;
233	int sig;
234
235	static struct option arg_options[] = {
236		{"clientid",	required_argument,	0, 'c'},
237		{"foreground",	no_argument,		0, 'f'},
238		{"background",	no_argument,		0, 'b'},
239		{"hostname",	required_argument,	0, 'H'},
240		{"hostname",    required_argument,      0, 'h'},
241		{"interface",	required_argument,	0, 'i'},
242		{"now", 	no_argument,		0, 'n'},
243		{"pidfile",	required_argument,	0, 'p'},
244		{"quit",	no_argument,		0, 'q'},
245		{"request",	required_argument,	0, 'r'},
246		{"script",	required_argument,	0, 's'},
247		{"version",	no_argument,		0, 'v'},
248		{"help",	no_argument,		0, '?'},
249		{0, 0, 0, 0}
250	};
251
252	/* get options */
253	while (1) {
254		int option_index = 0;
255		c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:s:v", arg_options, &option_index);
256		if (c == -1) break;
257
258		switch (c) {
259		case 'c':
260			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
261			if (client_config.clientid) free(client_config.clientid);
262			client_config.clientid = xmalloc(len + 2);
263			client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
264			client_config.clientid[OPT_LEN] = len;
265			client_config.clientid[OPT_DATA] = '\0';
266			strncpy(client_config.clientid + OPT_DATA, optarg, len);
267			break;
268		case 'f':
269			client_config.foreground = 1;
270			break;
271		case 'b':
272			client_config.background_if_no_lease = 1;
273			break;
274		case 'h':
275		case 'H':
276			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
277			if (client_config.hostname) free(client_config.hostname);
278			client_config.hostname = xmalloc(len + 2);
279			client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
280			client_config.hostname[OPT_LEN] = len;
281			strncpy(client_config.hostname + 2, optarg, len);
282			break;
283		case 'i':
284			client_config.interface =  optarg;
285			break;
286		case 'n':
287			client_config.abort_if_no_lease = 1;
288			break;
289		case 'p':
290			client_config.pidfile = optarg;
291			break;
292		case 'q':
293			client_config.quit_after_lease = 1;
294			break;
295		case 'r':
296			requested_ip = inet_addr(optarg);
297			break;
298		case 's':
299			client_config.script = optarg;
300			break;
301		case 'v':
302			printf("udhcpcd, version %s\n\n", VERSION);
303			exit_client(0);
304			break;
305		default:
306			show_usage();
307		}
308	}
309
310	OPEN_LOG("udhcpc");
311	LOG(LOG_INFO, "udhcp client (v%s) started", VERSION);
312
313	pid_fd = pidfile_acquire(client_config.pidfile);
314	pidfile_write_release(pid_fd);
315
316	if (read_interface(client_config.interface, &client_config.ifindex,
317			   NULL, client_config.arp) < 0)
318		exit_client(1);
319
320	if (!client_config.clientid) {
321		client_config.clientid = xmalloc(6 + 3);
322		client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
323		client_config.clientid[OPT_LEN] = 7;
324		client_config.clientid[OPT_DATA] = 1;
325		memcpy(client_config.clientid + 3, client_config.arp, 6);
326	}
327
328	/* ensure that stdin/stdout/stderr are never returned by pipe() */
329	if (fcntl(STDIN_FILENO, F_GETFL) == -1)
330		(void) open("/dev/null", O_RDONLY);
331	if (fcntl(STDOUT_FILENO, F_GETFL) == -1)
332		(void) open("/dev/null", O_WRONLY);
333	if (fcntl(STDERR_FILENO, F_GETFL) == -1)
334		(void) open("/dev/null", O_WRONLY);
335
336	/* setup signal handlers */
337	pipe(signal_pipe);
338	signal(SIGUSR1, signal_handler);
339	signal(SIGUSR2, signal_handler);
340	signal(SIGTERM, signal_handler);
341
342	state = INIT_SELECTING;
343	run_script(NULL, "deconfig");
344	change_mode(LISTEN_RAW);
345
346	for (;;) {
347
348		//tv.tv_sec = timeout - time(0);
349		tv.tv_sec = timeout - uptime();
350		tv.tv_usec = 0;
351		FD_ZERO(&rfds);
352
353		if (listen_mode != LISTEN_NONE && fd < 0) {
354			if (listen_mode == LISTEN_KERNEL)
355				fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
356			else
357				fd = raw_socket(client_config.ifindex);
358			if (fd < 0) {
359				LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s", strerror(errno));
360				exit_client(0);
361			}
362		}
363		if (fd >= 0) FD_SET(fd, &rfds);
364		FD_SET(signal_pipe[0], &rfds);
365
366		if (tv.tv_sec > 0) {
367			DEBUG(LOG_INFO, "Waiting on select...\n");
368			max_fd = signal_pipe[0] > fd ? signal_pipe[0] : fd;
369			retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
370		} else retval = 0; /* If we already timed out, fall through */
371
372		//now = time(0);
373		now = uptime();
374		if (retval == 0) {
375			/* timeout dropped to zero */
376			switch (state) {
377			case INIT_SELECTING:
378				if (packet_num < 3) {
379					if (packet_num == 0)
380						xid = random_xid();
381
382					/* send discover packet */
383					send_discover(xid, requested_ip); /* broadcast */
384
385					timeout = now + ((packet_num == 2) ? 4 : 2);
386					packet_num++;
387				} else {
388					if (client_config.background_if_no_lease) {
389						LOG(LOG_INFO, "No lease, forking to background.");
390						background();
391					} else if (client_config.abort_if_no_lease) {
392						LOG(LOG_INFO, "No lease, failing.");
393						exit_client(1);
394				  	}
395					/* wait to try again */
396					packet_num = 0;
397					timeout = now + 5;
398				}
399				break;
400			case RENEW_REQUESTED:
401			case REQUESTING:
402				if (packet_num < 3) {
403					/* send request packet */
404					if (state == RENEW_REQUESTED)
405						send_renew(xid, server_addr, requested_ip); /* unicast */
406					else send_selecting(xid, server_addr, requested_ip); /* broadcast */
407
408					timeout = now + ((packet_num == 2) ? 10 : 2);
409					packet_num++;
410				} else {
411					/* timed out, go back to init state */
412					if (state == RENEW_REQUESTED) run_script(NULL, "deconfig");
413					state = INIT_SELECTING;
414					timeout = now;
415					packet_num = 0;
416					change_mode(LISTEN_RAW);
417				}
418				break;
419			case BOUND:
420				/* Lease is starting to run out, time to enter renewing state */
421				state = RENEWING;
422				change_mode(LISTEN_KERNEL);
423				DEBUG(LOG_INFO, "Entering renew state");
424				/* fall right through */
425			case RENEWING:
426				/* Either set a new T1, or enter REBINDING state */
427				if ((t2 - t1) <= (lease / 14400 + 1)) {
428					/* timed out, enter rebinding state */
429					state = REBINDING;
430					change_mode(LISTEN_RAW);
431					timeout = now + (t2 - t1);
432					DEBUG(LOG_INFO, "Entering rebinding state");
433				} else {
434					/* send a request packet */
435					send_renew(xid, server_addr, requested_ip); /* unicast */
436
437					t1 = (t2 - t1) / 2 + t1;
438					timeout = t1 + start;
439				}
440				break;
441			case REBINDING:
442				/* Either set a new T2, or enter INIT state */
443				if ((lease - t2) <= (lease / 14400 + 1)) {
444					/* timed out, enter init state */
445					state = INIT_SELECTING;
446					LOG(LOG_INFO, "Lease lost, entering init state");
447					run_script(NULL, "deconfig");
448					timeout = now;
449					packet_num = 0;
450					change_mode(LISTEN_RAW);
451				} else {
452					/* send a request packet */
453					send_renew(xid, 0, requested_ip); /* broadcast */
454
455					t2 = (lease - t2) / 2 + t2;
456					timeout = t2 + start;
457				}
458				break;
459			case RELEASED:
460				/* yah, I know, *you* say it would never happen */
461				timeout = 0x7fffffff;
462				break;
463			}
464		} else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) {
465			/* a packet is ready, read it */
466
467			if (listen_mode == LISTEN_KERNEL)
468				len = get_packet(&packet, fd);
469			else len = get_raw_packet(&packet, fd);
470
471			if (len == -1 && errno != EINTR) {
472				DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
473				change_mode(listen_mode); /* just close and reopen */
474			}
475			if (len < 0) continue;
476
477			if (packet.xid != xid) {
478				DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
479					(unsigned long) packet.xid, xid);
480				continue;
481			}
482
483			if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
484				DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
485				continue;
486			}
487
488			/* Ignore packets that aren't for us */
489			if (memcmp(client_config.arp,packet.chaddr,6))
490				continue;
491
492			switch (state) {
493			case INIT_SELECTING:
494				/* Must be a DHCPOFFER to one of our xid's */
495				if (*message == DHCPOFFER) {
496					if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
497						memcpy(&server_addr, temp, 4);
498						xid = packet.xid;
499						requested_ip = packet.yiaddr;
500
501						/* enter requesting state */
502						state = REQUESTING;
503						timeout = now;
504						packet_num = 0;
505					} else {
506						DEBUG(LOG_ERR, "No server ID in message");
507					}
508				}
509				break;
510			case RENEW_REQUESTED:
511			case REQUESTING:
512			case RENEWING:
513			case REBINDING:
514				if (*message == DHCPACK) {
515					if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
516						LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease");
517						lease = 60 * 60;
518					} else {
519						memcpy(&lease, temp, 4);
520						lease = ntohl(lease);
521					}
522
523					/* enter bound state */
524					t1 = lease / 2;
525
526					/* little fixed point for n * .875 */
527					t2 = (lease * 0x7) >> 3;
528					temp_addr.s_addr = packet.yiaddr;
529					LOG(LOG_INFO, "(%d) Lease of %s obtained, lease time %ld",
530						state, inet_ntoa(temp_addr), lease);
531					start = now;
532					timeout = t1 + start;
533					requested_ip = packet.yiaddr;
534					run_script(&packet,
535						((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
536
537					state = BOUND;
538					change_mode(LISTEN_NONE);
539					if (client_config.quit_after_lease)
540						exit_client(0);
541					if (!client_config.foreground)
542						background();
543
544				} else if (*message == DHCPNAK) {
545					/* return to init state */
546					LOG(LOG_INFO, "Received DHCP NAK");
547					run_script(&packet, "nak");
548					if (state != REQUESTING)
549						run_script(NULL, "deconfig");
550					state = INIT_SELECTING;
551					timeout = now;
552					requested_ip = 0;
553					packet_num = 0;
554					change_mode(LISTEN_RAW);
555					sleep(3); /* avoid excessive network traffic */
556				}
557				break;
558			/* case BOUND, RELEASED: - ignore all packets */
559			}
560		} else if (retval > 0 && FD_ISSET(signal_pipe[0], &rfds)) {
561			if (read(signal_pipe[0], &sig, sizeof(sig)) < 0) {
562				DEBUG(LOG_ERR, "Could not read signal: %s",
563					strerror(errno));
564				continue; /* probably just EINTR */
565			}
566			switch (sig) {
567			case SIGUSR1:
568				perform_renew();
569				break;
570			case SIGUSR2:
571				perform_release();
572				break;
573			case SIGTERM:
574				LOG(LOG_INFO, "Received SIGTERM");
575				exit_client(0);
576			}
577		} else if (retval == -1 && errno == EINTR) {
578			/* a signal was caught */
579		} else {
580			/* An error occured */
581			DEBUG(LOG_ERR, "Error on select");
582		}
583
584	}
585	return 0;
586}
587
588