GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/dhclient/dispatch.c Lines: 0 127 0.0 %
Date: 2016-12-06 Branches: 0 76 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: dispatch.c,v 1.106 2016/07/21 09:58:55 krw Exp $	*/
2
3
/*
4
 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5
 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6
 * The Internet Software Consortium.   All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 *
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 * 3. Neither the name of The Internet Software Consortium nor the names
18
 *    of its contributors may be used to endorse or promote products derived
19
 *    from this software without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
 * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 *
35
 * This software has been written for the Internet Software Consortium
36
 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37
 * Enterprises.  To learn more about the Internet Software Consortium,
38
 * see ``http://www.vix.com/isc''.  To learn more about Vixie
39
 * Enterprises, see ``http://www.vix.com''.
40
 */
41
42
#include <sys/ioctl.h>
43
#include <sys/queue.h>
44
#include <sys/socket.h>
45
#include <sys/types.h>
46
47
#include <net/if.h>
48
#include <net/if_arp.h>
49
#include <net/if_dl.h>
50
#include <net/if_media.h>
51
#include <net/if_types.h>
52
53
#include <netinet/in.h>
54
#include <netinet/if_ether.h>
55
56
#include <errno.h>
57
#include <ifaddrs.h>
58
#include <imsg.h>
59
#include <limits.h>
60
#include <poll.h>
61
#include <signal.h>
62
#include <stdio.h>
63
#include <stdlib.h>
64
#include <string.h>
65
#include <unistd.h>
66
67
#include "dhcp.h"
68
#include "dhcpd.h"
69
#include "privsep.h"
70
71
72
struct dhcp_timeout timeout;
73
74
void packethandler(void);
75
76
void
77
get_hw_address(void)
78
{
79
	struct ifaddrs *ifap, *ifa;
80
	struct sockaddr_dl *sdl;
81
	int found;
82
83
	if (getifaddrs(&ifap) != 0)
84
		error("getifaddrs failed");
85
86
	found = 0;
87
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
88
		if ((ifa->ifa_flags & IFF_LOOPBACK) ||
89
		    (ifa->ifa_flags & IFF_POINTOPOINT) ||
90
		    (!(ifa->ifa_flags & IFF_UP)))
91
			continue;
92
93
		if (strcmp(ifi->name, ifa->ifa_name) != 0)
94
			continue;
95
		found = 1;
96
97
		if (ifa->ifa_addr->sa_family != AF_LINK)
98
			continue;
99
100
		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
101
		if (sdl->sdl_type != IFT_ETHER ||
102
		    sdl->sdl_alen != ETHER_ADDR_LEN)
103
			continue;
104
105
		memcpy(ifi->hw_address.ether_addr_octet, LLADDR(sdl),
106
		    ETHER_ADDR_LEN);
107
		ifi->flags |= IFI_VALID_LLADDR;
108
	}
109
110
	if (!found)
111
		error("%s: no such interface", ifi->name);
112
113
	freeifaddrs(ifap);
114
}
115
116
/*
117
 * Loop waiting for packets, timeouts or routing messages.
118
 */
119
void
120
dispatch(void)
121
{
122
	int count, to_msec;
123
	struct pollfd fds[3];
124
	time_t cur_time, howlong;
125
	void (*func)(void);
126
127
	while (quit == 0) {
128
		if (timeout.func) {
129
			time(&cur_time);
130
			if (timeout.when <= cur_time) {
131
				func = timeout.func;
132
				cancel_timeout();
133
				(*(func))();
134
				continue;
135
			}
136
			/*
137
			 * Figure timeout in milliseconds, and check for
138
			 * potential overflow, so we can cram into an
139
			 * int for poll, while not polling with a
140
			 * negative timeout and blocking indefinitely.
141
			 */
142
			howlong = timeout.when - cur_time;
143
			if (howlong > INT_MAX / 1000)
144
				howlong = INT_MAX / 1000;
145
			to_msec = howlong * 1000;
146
		} else
147
			to_msec = -1;
148
149
		/*
150
		 * Set up the descriptors to be polled.
151
		 *
152
		 *  fds[0] == bpf socket for incoming packets
153
		 *  fds[1] == routing socket for incoming RTM messages
154
		 *  fds[2] == imsg socket to privileged process
155
		*/
156
		fds[0].fd = ifi->bfdesc;
157
		fds[1].fd = routefd;
158
		fds[2].fd = unpriv_ibuf->fd;
159
		fds[0].events = fds[1].events = fds[2].events = POLLIN;
160
161
		if (unpriv_ibuf->w.queued)
162
			fds[2].events |= POLLOUT;
163
164
		count = poll(fds, 3, to_msec);
165
		if (count == -1) {
166
			if (errno == EAGAIN || errno == EINTR) {
167
				continue;
168
			} else {
169
				warning("poll: %s", strerror(errno));
170
				quit = INTERNALSIG;
171
				continue;
172
			}
173
		}
174
175
		if ((fds[0].revents & (POLLIN | POLLHUP)))
176
			packethandler();
177
		if ((fds[1].revents & (POLLIN | POLLHUP)))
178
			routehandler();
179
		if (fds[2].revents & POLLOUT)
180
			flush_unpriv_ibuf("dispatch");
181
		if ((fds[2].revents & (POLLIN | POLLHUP))) {
182
			/* Pipe to [priv] closed. Assume it emitted error. */
183
			quit = INTERNALSIG;
184
		}
185
	}
186
187
	if (quit == SIGHUP) {
188
		/* Tell [priv] process that HUP has occurred. */
189
		sendhup(client->active);
190
		warning("%s; restarting", strsignal(quit));
191
		exit (0);
192
	} else if (quit != INTERNALSIG) {
193
		warning("%s; exiting", strsignal(quit));
194
		exit(1);
195
	}
196
}
197
198
void
199
packethandler(void)
200
{
201
	struct sockaddr_in from;
202
	struct ether_addr hfrom;
203
	struct in_addr ifrom;
204
	ssize_t result;
205
206
	if ((result = receive_packet(&from, &hfrom)) == -1) {
207
		warning("%s receive_packet failed: %s", ifi->name,
208
		    strerror(errno));
209
		ifi->errors++;
210
		if (ifi->errors > 20) {
211
			error("%s too many receive_packet failures; exiting",
212
			    ifi->name);
213
		}
214
		return;
215
	}
216
	ifi->errors = 0;
217
218
	if (result == 0)
219
		return;
220
221
	ifrom.s_addr = from.sin_addr.s_addr;
222
223
	do_packet(from.sin_port, ifrom, &hfrom);
224
}
225
226
void
227
interface_link_forceup(char *ifname)
228
{
229
	struct ifreq ifr;
230
	int sock;
231
232
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
233
		error("Can't create socket");
234
235
	memset(&ifr, 0, sizeof(ifr));
236
	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
237
	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
238
		note("interface_link_forceup: SIOCGIFFLAGS failed (%s)",
239
		    strerror(errno));
240
		close(sock);
241
		return;
242
	}
243
244
	/* Force it down and up so others notice link state change. */
245
	ifr.ifr_flags &= ~IFF_UP;
246
	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
247
		note("interface_link_forceup: SIOCSIFFLAGS DOWN failed (%s)",
248
		    strerror(errno));
249
		close(sock);
250
		return;
251
	}
252
253
	ifr.ifr_flags |= IFF_UP;
254
	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
255
		note("interface_link_forceup: SIOCSIFFLAGS UP failed (%s)",
256
		    strerror(errno));
257
		close(sock);
258
		return;
259
	}
260
261
	close(sock);
262
}
263
264
int
265
interface_status(char *ifname)
266
{
267
	struct ifreq ifr;
268
	struct ifmediareq ifmr;
269
	int sock;
270
271
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
272
		error("Can't create socket");
273
274
	/* Get interface flags. */
275
	memset(&ifr, 0, sizeof(ifr));
276
	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
277
	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
278
		error("ioctl(SIOCGIFFLAGS) on %s: %s", ifname,
279
		    strerror(errno));
280
	}
281
282
	if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
283
		goto inactive;
284
285
	/* Next, check carrier on the interface if possible. */
286
	if (ifi->flags & IFI_NOMEDIA)
287
		goto active;
288
	memset(&ifmr, 0, sizeof(ifmr));
289
	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
290
	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
291
		/*
292
		 * EINVAL or ENOTTY simply means that the interface does not
293
		 * support the SIOCGIFMEDIA ioctl. We regard it alive.
294
		 */
295
#ifdef DEBUG
296
		if (errno != EINVAL && errno != ENOTTY)
297
			debug("ioctl(SIOCGIFMEDIA) on %s: %s", ifname,
298
			    strerror(errno));
299
#endif
300
301
		ifi->flags |= IFI_NOMEDIA;
302
		goto active;
303
	}
304
	if (ifmr.ifm_status & IFM_AVALID) {
305
		if (ifmr.ifm_status & IFM_ACTIVE)
306
			goto active;
307
		else
308
			goto inactive;
309
	}
310
311
	/* Assume 'active' if IFM_AVALID is not set. */
312
313
active:
314
	close(sock);
315
	return (1);
316
inactive:
317
	close(sock);
318
	return (0);
319
}
320
321
void
322
set_timeout(time_t when, void (*where)(void))
323
{
324
	timeout.when = when;
325
	timeout.func = where;
326
}
327
328
void
329
set_timeout_interval(time_t secs, void (*where)(void))
330
{
331
	timeout.when = time(NULL) + secs;
332
	timeout.func = where;
333
}
334
335
void
336
cancel_timeout(void)
337
{
338
	timeout.when = 0;
339
	timeout.func = NULL;
340
}
341
342
int
343
get_rdomain(char *name)
344
{
345
	int rv = 0, s;
346
	struct ifreq ifr;
347
348
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
349
	    error("get_rdomain socket: %s", strerror(errno));
350
351
	memset(&ifr, 0, sizeof(ifr));
352
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
353
	if (ioctl(s, SIOCGIFRDOMAIN, (caddr_t)&ifr) != -1)
354
	    rv = ifr.ifr_rdomainid;
355
356
	close(s);
357
	return rv;
358
}