dispatch.c revision 1.22
1/*	$OpenBSD: dispatch.c,v 1.22 2006/12/12 19:38:55 stevesk Exp $ */
2
3/*
4 * Copyright (c) 1995, 1996, 1997, 1998, 1999
5 * The Internet Software Consortium.   All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of The Internet Software Consortium nor the names
17 *    of its contributors may be used to endorse or promote products derived
18 *    from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * This software has been written for the Internet Software Consortium
35 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36 * Enterprises.  To learn more about the Internet Software Consortium,
37 * see ``http://www.vix.com/isc''.  To learn more about Vixie
38 * Enterprises, see ``http://www.vix.com''.
39 */
40
41#include "dhcpd.h"
42#include <ifaddrs.h>
43#include <sys/ioctl.h>
44#include <poll.h>
45#include <net/if_media.h>
46
47struct interface_info *interfaces;
48struct protocol *protocols;
49struct dhcpd_timeout *timeouts;
50static struct dhcpd_timeout *free_timeouts;
51static int interfaces_invalidated;
52void (*bootp_packet_handler)(struct interface_info *,
53    struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *);
54
55static int interface_status(struct interface_info *ifinfo);
56
57/* Use getifaddrs() to get a list of all the attached interfaces.
58   For each interface that's of type INET and not the loopback interface,
59   register that interface with the network I/O software, figure out what
60   subnet it's on, and add it to the list of interfaces. */
61
62void
63discover_interfaces(void)
64{
65	struct interface_info *tmp;
66	struct interface_info *last, *next;
67	struct subnet *subnet;
68	struct shared_network *share;
69	struct sockaddr_in foo;
70	int ir = 0;
71	struct ifreq *tif;
72	struct ifaddrs *ifap, *ifa;
73
74	if (getifaddrs(&ifap) != 0)
75		error("getifaddrs failed");
76
77	/*
78	 * If we already have a list of interfaces, the interfaces were
79	 * requested.
80	 */
81	if (interfaces != NULL)
82		ir = 1;
83
84	/* Cycle through the list of interfaces looking for IP addresses. */
85	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
86		/*
87		 * See if this is the sort of interface we want to
88		 * deal with.  Skip loopback, point-to-point and down
89		 * interfaces, except don't skip down interfaces if we're
90		 * trying to get a list of configurable interfaces.
91		 */
92		if ((ifa->ifa_flags & IFF_LOOPBACK) ||
93		    (ifa->ifa_flags & IFF_POINTOPOINT) ||
94		    (!(ifa->ifa_flags & IFF_UP)))
95			continue;
96
97		/* See if we've seen an interface that matches this one. */
98		for (tmp = interfaces; tmp; tmp = tmp->next)
99			if (!strcmp(tmp->name, ifa->ifa_name))
100				break;
101
102		/* If we are looking for specific interfaces, ignore others. */
103		if (tmp == NULL && ir)
104			continue;
105
106		/* If there isn't already an interface by this name,
107		   allocate one. */
108		if (tmp == NULL) {
109			tmp = ((struct interface_info *)dmalloc(sizeof *tmp,
110			    "discover_interfaces"));
111			if (!tmp)
112				error("Insufficient memory to %s %s",
113				    "record interface", ifa->ifa_name);
114			strlcpy(tmp->name, ifa->ifa_name, sizeof(tmp->name));
115			tmp->next = interfaces;
116			tmp->noifmedia = tmp->dead = tmp->errors = 0;
117			interfaces = tmp;
118		}
119
120		/* If we have the capability, extract link information
121		   and record it in a linked list. */
122		if (ifa->ifa_addr->sa_family == AF_LINK) {
123			struct sockaddr_dl *foo =
124			    ((struct sockaddr_dl *)(ifa->ifa_addr));
125			tmp->index = foo->sdl_index;
126			tmp->hw_address.hlen = foo->sdl_alen;
127			tmp->hw_address.htype = HTYPE_ETHER; /* XXX */
128			memcpy(tmp->hw_address.haddr,
129			    LLADDR(foo), foo->sdl_alen);
130		} else if (ifa->ifa_addr->sa_family == AF_INET) {
131			struct iaddr addr;
132
133			/* Get a pointer to the address... */
134			bcopy(ifa->ifa_addr, &foo, sizeof(foo));
135
136			/* We don't want the loopback interface. */
137			if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK))
138				continue;
139
140			/* If this is the first real IP address we've
141			   found, keep a pointer to ifreq structure in
142			   which we found it. */
143			if (!tmp->ifp) {
144				int len = (IFNAMSIZ + ifa->ifa_addr->sa_len);
145				tif = (struct ifreq *)malloc(len);
146				if (!tif)
147					error("no space to remember ifp.");
148				strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ);
149				memcpy(&tif->ifr_addr, ifa->ifa_addr,
150				    ifa->ifa_addr->sa_len);
151				tmp->ifp = tif;
152				tmp->primary_address = foo.sin_addr;
153			}
154
155			/* Grab the address... */
156			addr.len = 4;
157			memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len);
158
159			/* If there's a registered subnet for this address,
160			   connect it together... */
161			if ((subnet = find_subnet(addr))) {
162				/* If this interface has multiple aliases
163				   on the same subnet, ignore all but the
164				   first we encounter. */
165				if (!subnet->interface) {
166					subnet->interface = tmp;
167					subnet->interface_address = addr;
168				} else if (subnet->interface != tmp) {
169					warning("Multiple %s %s: %s %s",
170					    "interfaces match the",
171					    "same subnet",
172					    subnet->interface->name,
173					    tmp->name);
174				}
175				share = subnet->shared_network;
176				if (tmp->shared_network &&
177				    tmp->shared_network != share) {
178					warning("Interface %s matches %s",
179					    tmp->name,
180					    "multiple shared networks");
181				} else {
182					tmp->shared_network = share;
183				}
184
185				if (!share->interface) {
186					share->interface = tmp;
187				} else if (share->interface != tmp) {
188					warning("Multiple %s %s: %s %s",
189					    "interfaces match the",
190					    "same shared network",
191					    share->interface->name,
192					    tmp->name);
193				}
194			}
195		}
196	}
197
198	/* Discard interfaces we can't listen on. */
199	last = NULL;
200	for (tmp = interfaces; tmp; tmp = next) {
201		next = tmp->next;
202
203		if (!tmp->ifp) {
204			warning("Can't listen on %s - it has no IP address.",
205			    tmp->name);
206			/* Remove tmp from the list of interfaces. */
207			if (!last)
208				interfaces = interfaces->next;
209			else
210				last->next = tmp->next;
211			continue;
212		}
213
214		memcpy(&foo, &tmp->ifp->ifr_addr, sizeof tmp->ifp->ifr_addr);
215
216		if (!tmp->shared_network) {
217			warning("Can't listen on %s - dhcpd.conf has no subnet "
218			    "declaration for %s.", tmp->name,
219			    inet_ntoa(foo.sin_addr));
220			/* Remove tmp from the list of interfaces. */
221			if (!last)
222				interfaces = interfaces->next;
223			else
224				last->next = tmp->next;
225			continue;
226		}
227
228		last = tmp;
229
230		/* Find subnets that don't have valid interface addresses. */
231		for (subnet = (tmp->shared_network ? tmp->shared_network->subnets :
232		    NULL); subnet; subnet = subnet->next_sibling) {
233			if (!subnet->interface_address.len) {
234				/*
235				 * Set the interface address for this subnet
236				 * to the first address we found.
237				 */
238				subnet->interface_address.len = 4;
239				memcpy(subnet->interface_address.iabuf,
240				    &foo.sin_addr.s_addr, 4);
241			}
242		}
243
244		/* Register the interface... */
245		if_register_receive(tmp);
246		if_register_send(tmp);
247	}
248
249	if (interfaces == NULL)
250		error("No interfaces to listen on.");
251
252	/* Now register all the remaining interfaces as protocols. */
253	for (tmp = interfaces; tmp; tmp = tmp->next)
254		add_protocol(tmp->name, tmp->rfdesc, got_one, tmp);
255
256	freeifaddrs(ifap);
257}
258
259/*
260 * Wait for packets to come in using poll().  When a packet comes in,
261 * call receive_packet to receive the packet and possibly strip hardware
262 * addressing information from it, and then call through the
263 * bootp_packet_handler hook to try to do something with it.
264 */
265void
266dispatch(void)
267{
268	int nfds, i, to_msec;
269	struct protocol *l;
270	static struct pollfd *fds;
271	static int nfds_max;
272	time_t howlong;
273
274	for (nfds = 0, l = protocols; l; l = l->next)
275		nfds++;
276	if (nfds > nfds_max) {
277		fds = realloc(fds, nfds * sizeof(struct pollfd));
278		if (fds == NULL)
279			error("Can't allocate poll structures.");
280		nfds_max = nfds;
281	}
282
283	for (;;) {
284		/*
285		 * Call any expired timeouts, and then if there's
286		 * still a timeout registered, time out the poll
287		 * call then.
288		 */
289		time(&cur_time);
290another:
291		if (timeouts) {
292			if (timeouts->when <= cur_time) {
293				struct dhcpd_timeout *t = timeouts;
294				timeouts = timeouts->next;
295				(*(t->func))(t->what);
296				t->next = free_timeouts;
297				free_timeouts = t;
298				goto another;
299			}
300
301			/*
302			 * Figure timeout in milliseconds, and check for
303			 * potential overflow, so we can cram into an int
304			 * for poll, while not polling with a negative
305			 * timeout and blocking indefinitely.
306			 */
307			howlong = timeouts->when - cur_time;
308			if (howlong > INT_MAX / 1000)
309				howlong = INT_MAX / 1000;
310			to_msec = howlong * 1000;
311		} else
312			to_msec = -1;
313
314		/* Set up the descriptors to be polled. */
315		for (i = 0, l = protocols; l; l = l->next) {
316			struct interface_info *ip = l->local;
317
318			if (ip && (l->handler != got_one || !ip->dead)) {
319				fds[i].fd = l->fd;
320				fds[i].events = POLLIN;
321				++i;
322			}
323		}
324		if (i == 0)
325			error("No live interfaces to poll on - exiting.");
326
327		/* Wait for a packet or a timeout... */
328		switch (poll(fds, nfds, to_msec)) {
329		case -1:
330			if (errno != EAGAIN && errno != EINTR)
331				error("poll: %m");
332			/* FALLTHROUGH */
333		case 0:
334			continue;	/* no packets */
335		}
336
337		for (i = 0, l = protocols; l; l = l->next) {
338			struct interface_info *ip = l->local;
339
340			if ((fds[i].revents & (POLLIN | POLLHUP))) {
341				if (ip && (l->handler != got_one ||
342				    !ip->dead))
343					(*(l->handler))(l);
344				if (interfaces_invalidated)
345					break;
346			}
347			++i;
348		}
349		interfaces_invalidated = 0;
350	}
351}
352
353
354void
355got_one(struct protocol *l)
356{
357	struct sockaddr_in from;
358	struct hardware hfrom;
359	struct iaddr ifrom;
360	ssize_t result;
361	union {
362		unsigned char packbuf[4095];
363		struct dhcp_packet packet;
364	} u;
365	struct interface_info *ip = l->local;
366
367	if ((result = receive_packet(ip, u.packbuf, sizeof u,
368	    &from, &hfrom)) == -1) {
369		warning("receive_packet failed on %s: %s", ip->name,
370		    strerror(errno));
371		ip->errors++;
372		if ((!interface_status(ip)) ||
373		    (ip->noifmedia && ip->errors > 20)) {
374			/* our interface has gone away. */
375			warning("Interface %s no longer appears valid.",
376			    ip->name);
377			ip->dead = 1;
378			interfaces_invalidated = 1;
379			close(l->fd);
380			remove_protocol(l);
381			free(ip);
382		}
383		return;
384	}
385	if (result == 0)
386		return;
387
388	if (bootp_packet_handler) {
389		ifrom.len = 4;
390		memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len);
391
392		(*bootp_packet_handler)(ip, &u.packet, result,
393		    from.sin_port, ifrom, &hfrom);
394	}
395}
396
397int
398interface_status(struct interface_info *ifinfo)
399{
400	char * ifname = ifinfo->name;
401	int ifsock = ifinfo->rfdesc;
402	struct ifreq ifr;
403	struct ifmediareq ifmr;
404
405	/* get interface flags */
406	memset(&ifr, 0, sizeof(ifr));
407	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
408	if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
409		syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
410		goto inactive;
411	}
412	/*
413	 * if one of UP and RUNNING flags is dropped,
414	 * the interface is not active.
415	 */
416	if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
417		goto inactive;
418
419	/* Next, check carrier on the interface, if possible */
420	if (ifinfo->noifmedia)
421		goto active;
422	memset(&ifmr, 0, sizeof(ifmr));
423	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
424	if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
425		if (errno != EINVAL) {
426			syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m",
427			    ifname);
428			ifinfo->noifmedia = 1;
429			goto active;
430		}
431		/*
432		 * EINVAL (or ENOTTY) simply means that the interface
433		 * does not support the SIOCGIFMEDIA ioctl. We regard it alive.
434		 */
435		ifinfo->noifmedia = 1;
436		goto active;
437	}
438	if (ifmr.ifm_status & IFM_AVALID) {
439		switch (ifmr.ifm_active & IFM_NMASK) {
440		case IFM_ETHER:
441			if (ifmr.ifm_status & IFM_ACTIVE)
442				goto active;
443			else
444				goto inactive;
445			break;
446		default:
447			goto inactive;
448		}
449	}
450 inactive:
451	return (0);
452 active:
453	return (1);
454}
455
456int
457locate_network(struct packet *packet)
458{
459	struct iaddr ia;
460
461	/* If this came through a gateway, find the corresponding subnet... */
462	if (packet->raw->giaddr.s_addr) {
463		struct subnet *subnet;
464
465		ia.len = 4;
466		memcpy(ia.iabuf, &packet->raw->giaddr, 4);
467		subnet = find_subnet(ia);
468		if (subnet)
469			packet->shared_network = subnet->shared_network;
470		else
471			packet->shared_network = NULL;
472	} else {
473		packet->shared_network = packet->interface->shared_network;
474	}
475	if (packet->shared_network)
476		return 1;
477	return 0;
478}
479
480void
481add_timeout(time_t when, void (*where)(void *), void *what)
482{
483	struct dhcpd_timeout *t, *q;
484
485	/* See if this timeout supersedes an existing timeout. */
486	t = NULL;
487	for (q = timeouts; q; q = q->next) {
488		if (q->func == where && q->what == what) {
489			if (t)
490				t->next = q->next;
491			else
492				timeouts = q->next;
493			break;
494		}
495		t = q;
496	}
497
498	/* If we didn't supersede a timeout, allocate a timeout
499	   structure now. */
500	if (!q) {
501		if (free_timeouts) {
502			q = free_timeouts;
503			free_timeouts = q->next;
504			q->func = where;
505			q->what = what;
506		} else {
507			q = (struct dhcpd_timeout *)malloc(sizeof (struct dhcpd_timeout));
508			if (!q)
509				error("Can't allocate timeout structure!");
510			q->func = where;
511			q->what = what;
512		}
513	}
514
515	q->when = when;
516
517	/* Now sort this timeout into the timeout list. */
518
519	/* Beginning of list? */
520	if (!timeouts || timeouts->when > q->when) {
521		q->next = timeouts;
522		timeouts = q;
523		return;
524	}
525
526	/* Middle of list? */
527	for (t = timeouts; t->next; t = t->next) {
528		if (t->next->when > q->when) {
529			q->next = t->next;
530			t->next = q;
531			return;
532		}
533	}
534
535	/* End of list. */
536	t->next = q;
537	q->next = NULL;
538}
539
540void
541cancel_timeout(void (*where)(void *), void *what)
542{
543	struct dhcpd_timeout *t, *q;
544
545	/* Look for this timeout on the list, and unlink it if we find it. */
546	t = NULL;
547	for (q = timeouts; q; q = q->next) {
548		if (q->func == where && q->what == what) {
549			if (t)
550				t->next = q->next;
551			else
552				timeouts = q->next;
553			break;
554		}
555		t = q;
556	}
557
558	/* If we found the timeout, put it on the free list. */
559	if (q) {
560		q->next = free_timeouts;
561		free_timeouts = q;
562	}
563}
564
565/* Add a protocol to the list of protocols... */
566void
567add_protocol(char *name, int fd, void (*handler)(struct protocol *),
568    void *local)
569{
570	struct protocol *p;
571
572	p = (struct protocol *)malloc(sizeof *p);
573	if (!p)
574		error("can't allocate protocol struct for %s", name);
575	p->fd = fd;
576	p->handler = handler;
577	p->local = local;
578	p->next = protocols;
579	protocols = p;
580}
581
582void
583remove_protocol(struct protocol *proto)
584{
585	struct protocol *p, *next, *prev = NULL;
586
587	for (p = protocols; p; p = next) {
588		next = p->next;
589		if (p == proto) {
590			if (prev)
591				prev->next = p->next;
592			else
593				protocols = p->next;
594			free(p);
595		}
596	}
597}
598