GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/dhclient/kroute.c Lines: 0 379 0.0 %
Date: 2017-11-07 Branches: 0 208 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: kroute.c,v 1.153 2017/09/20 19:21:00 krw Exp $	*/
2
3
/*
4
 * Copyright 2012 Kenneth R Westerback <krw@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/ioctl.h>
20
#include <sys/socket.h>
21
#include <sys/stat.h>
22
#include <sys/sysctl.h>
23
24
#include <arpa/inet.h>
25
26
#include <net/if.h>
27
#include <net/if_types.h>
28
#include <net/route.h>
29
30
#include <netinet/in.h>
31
#include <netinet/if_ether.h>
32
33
#include <errno.h>
34
#include <fcntl.h>
35
#include <ifaddrs.h>
36
#include <imsg.h>
37
#include <limits.h>
38
#include <poll.h>
39
#include <resolv.h>
40
#include <signal.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <unistd.h>
45
46
#include "dhcp.h"
47
#include "dhcpd.h"
48
#include "log.h"
49
#include "privsep.h"
50
51
#define ROUNDUP(a) \
52
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
53
54
void		 get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
55
void		 add_route(struct in_addr, struct in_addr, struct in_addr, int);
56
void		 flush_routes(uint8_t *, unsigned int);
57
int		 delete_addresses(char *, struct in_addr, struct in_addr);
58
char		*get_routes(int, size_t *);
59
unsigned int	 route_in_rtstatic(struct rt_msghdr *, uint8_t *, unsigned int);
60
61
char *
62
get_routes(int rdomain, size_t *len)
63
{
64
	int		 mib[7];
65
	char		*buf, *bufp, *errmsg = NULL;
66
	size_t		 needed;
67
68
	mib[0] = CTL_NET;
69
	mib[1] = PF_ROUTE;
70
	mib[2] = 0;
71
	mib[3] = AF_INET;
72
	mib[4] = NET_RT_FLAGS;
73
	mib[5] = RTF_STATIC | RTF_GATEWAY | RTF_LLINFO;
74
	mib[6] = rdomain;
75
76
	buf = NULL;
77
	errmsg = NULL;
78
	while (1) {
79
		if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) {
80
			errmsg = "sysctl size of routes:";
81
			break;
82
		}
83
		if (needed == 0) {
84
			free(buf);
85
			return NULL;
86
		}
87
		if ((bufp = realloc(buf, needed)) == NULL) {
88
			errmsg = "routes buf realloc:";
89
			break;
90
		}
91
		buf = bufp;
92
		if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) {
93
			if (errno == ENOMEM)
94
				continue;
95
			errmsg = "sysctl retrieval of routes:";
96
			break;
97
		}
98
		break;
99
	}
100
101
	if (errmsg != NULL) {
102
		log_warn("%s: get_routes - %s (msize=%zu)", log_procname,
103
		    errmsg, needed);
104
		free(buf);
105
		buf = NULL;
106
	}
107
108
	*len = needed;
109
	return buf;
110
}
111
112
/*
113
 * [priv_]flush_routes do the equivalent of
114
 *
115
 *	route -q -T $rdomain -n flush -inet -iface $interface
116
 *	arp -dan
117
 */
118
void
119
flush_routes(uint8_t *rtstatic, unsigned int rtstatic_len)
120
{
121
	struct	imsg_flush_routes	 imsg;
122
	int				 rslt;
123
124
	if (rtstatic_len > sizeof(imsg.rtstatic))
125
		return;
126
127
	imsg.rtstatic_len = rtstatic_len;
128
	memcpy(&imsg.rtstatic, rtstatic, rtstatic_len);
129
130
	rslt = imsg_compose(unpriv_ibuf, IMSG_FLUSH_ROUTES, 0, 0, -1, &imsg,
131
	    sizeof(imsg));
132
	if (rslt == -1)
133
		log_warn("%s: imsg_compose(IMSG_FLUSH_ROUTES)", log_procname);
134
}
135
136
void
137
priv_flush_routes(int index, int routefd, int rdomain,
138
    struct imsg_flush_routes *imsg)
139
{
140
	static int			 seqno;
141
	char				*lim, *buf = NULL, *next;
142
	struct rt_msghdr		*rtm;
143
	size_t				 len;
144
	ssize_t				 rlen;
145
	unsigned int			 pos;
146
147
	buf = get_routes(rdomain, &len);
148
	if (buf == NULL)
149
		return;
150
151
	lim = buf + len;
152
	for (next = buf; next < lim; next += rtm->rtm_msglen) {
153
		rtm = (struct rt_msghdr *)next;
154
		if (rtm->rtm_version != RTM_VERSION)
155
			continue;
156
		if (rtm->rtm_index != index)
157
			continue;
158
		if (rtm->rtm_tableid != rdomain)
159
			continue;
160
		if ((rtm->rtm_flags & (RTF_GATEWAY|RTF_STATIC|RTF_LLINFO)) == 0)
161
			continue;
162
		if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0)
163
			continue;
164
165
		/* Don't bother deleting a route we're going to add. */
166
		pos = route_in_rtstatic(rtm, imsg->rtstatic,
167
		    imsg->rtstatic_len);
168
		if (pos < imsg->rtstatic_len)
169
			continue;
170
171
		rtm->rtm_type = RTM_DELETE;
172
		rtm->rtm_seq = seqno++;
173
174
		rlen = write(routefd, (char *)rtm, rtm->rtm_msglen);
175
		if (rlen == -1) {
176
			if (errno != ESRCH)
177
				log_warn("%s: write(RTM_DELETE)", log_procname);
178
		} else if (rlen < (int)rtm->rtm_msglen)
179
			log_warnx("%s: write(RTM_DELETE): %zd of %u bytes",
180
			    log_procname, rlen, rtm->rtm_msglen);
181
	}
182
183
	free(buf);
184
}
185
186
unsigned int
187
extract_classless_route(uint8_t *rtstatic, unsigned int rtstatic_len,
188
    in_addr_t *dest, in_addr_t *netmask, in_addr_t *gateway)
189
{
190
	unsigned int	 bits, bytes, len;
191
192
	if (rtstatic[0] > 32)
193
		return 0;
194
195
	bits = rtstatic[0];
196
	bytes = (bits + 7) / 8;
197
	len = 1 + bytes + sizeof(*gateway);
198
	if (len > rtstatic_len)
199
		return 0;
200
201
	if (dest != NULL)
202
		memcpy(dest, &rtstatic[1], bytes);
203
204
	if (netmask != NULL) {
205
		if (bits == 0)
206
			*netmask = INADDR_ANY;
207
		else
208
			*netmask = htonl(0xffffffff << (32 - bits));
209
		if (dest != NULL)
210
			*dest &= *netmask;
211
	}
212
213
	if (gateway != NULL)
214
		memcpy(gateway, &rtstatic[1 +  bytes], sizeof(*gateway));
215
216
	return len;
217
}
218
219
void
220
set_routes(struct in_addr addr, struct in_addr addrmask, uint8_t *rtstatic,
221
    unsigned int rtstatic_len)
222
{
223
	const struct in_addr	 any = { INADDR_ANY };
224
	struct in_addr		 dest, gateway, netmask;
225
	unsigned int		 i, len;
226
227
	flush_routes(rtstatic, rtstatic_len);
228
229
	/* Add classless static routes. */
230
	i = 0;
231
	while (i < rtstatic_len) {
232
		len = extract_classless_route(&rtstatic[i], rtstatic_len - i,
233
		    &dest.s_addr, &netmask.s_addr, &gateway.s_addr);
234
		if (len == 0)
235
			return;
236
		i += len;
237
238
		if (gateway.s_addr == INADDR_ANY) {
239
			/*
240
			 * DIRECT ROUTE
241
			 *
242
			 * route add -net $dest -netmask $netmask -cloning
243
			 *     -iface $addr
244
			 */
245
			add_route(dest, netmask, addr,
246
			    RTF_STATIC | RTF_CLONING);
247
		} else if (netmask.s_addr == INADDR_ANY) {
248
			/*
249
			 * DEFAULT ROUTE
250
			 */
251
			if (addrmask.s_addr == INADDR_BROADCAST) {
252
				/*
253
				 * DIRECT ROUTE TO DEFAULT GATEWAY
254
				 *
255
				 * To be compatible with ISC DHCP behavior on
256
				 * Linux, if we were given a /32 IP assignment
257
				 * then add a /32 direct route for the gateway
258
				 * to make it routable.
259
				 *
260
				 * route add -net $gateway -netmask $addrmask
261
				 *     -cloning -iface $addr
262
				 */
263
				add_route(gateway, addrmask, addr,
264
				    RTF_STATIC | RTF_CLONING);
265
			}
266
267
			if (memcmp(&gateway, &addr, sizeof(addr)) == 0) {
268
				/*
269
				 * DEFAULT ROUTE IS A DIRECT ROUTE
270
				 *
271
				 * route add default -iface $addr
272
				 */
273
				add_route(any, any, gateway, RTF_STATIC);
274
			} else {
275
				/*
276
				 * DEFAULT ROUTE IS VIA GATEWAY
277
				 *
278
				 * route add default $gateway
279
				 */
280
				add_route(any, any, gateway,
281
				    RTF_STATIC | RTF_GATEWAY);
282
			}
283
		} else {
284
			/*
285
			 * NON-DIRECT, NON-DEFAULT ROUTE
286
			 *
287
			 * route add -net $dest -netmask $netmask $gateway
288
			 */
289
			add_route(dest, netmask, gateway,
290
			    RTF_STATIC | RTF_GATEWAY);
291
		}
292
	}
293
}
294
295
/*
296
 * [priv_]add_route() add a single route to the routing table.
297
 */
298
void
299
add_route(struct in_addr dest, struct in_addr netmask, struct in_addr gateway,
300
    int flags)
301
{
302
	struct imsg_add_route	 imsg;
303
	int			 rslt;
304
305
	imsg.dest = dest;
306
	imsg.gateway = gateway;
307
	imsg.netmask = netmask;
308
	imsg.flags = flags;
309
310
	rslt = imsg_compose(unpriv_ibuf, IMSG_ADD_ROUTE, 0, 0, -1,
311
	    &imsg, sizeof(imsg));
312
	if (rslt == -1)
313
		log_warn("%s: imsg_compose(IMSG_ADD_ROUTE)", log_procname);
314
}
315
316
void
317
priv_add_route(char *name, int rdomain, int routefd,
318
    struct imsg_add_route *imsg)
319
{
320
	char			 destbuf[INET_ADDRSTRLEN];
321
	char			 maskbuf[INET_ADDRSTRLEN];
322
	struct iovec		 iov[5];
323
	struct rt_msghdr	 rtm;
324
	struct sockaddr_in	 dest, gateway, mask;
325
	int			 index, iovcnt = 0;
326
327
	index = if_nametoindex(name);
328
	if (index == 0)
329
		return;
330
331
	/* Build RTM header */
332
333
	memset(&rtm, 0, sizeof(rtm));
334
335
	rtm.rtm_version = RTM_VERSION;
336
	rtm.rtm_type = RTM_ADD;
337
	rtm.rtm_index = index;
338
	rtm.rtm_tableid = rdomain;
339
	rtm.rtm_priority = RTP_NONE;
340
	rtm.rtm_addrs =	RTA_DST | RTA_NETMASK | RTA_GATEWAY;
341
	rtm.rtm_flags = imsg->flags;
342
343
	rtm.rtm_msglen = sizeof(rtm);
344
	iov[iovcnt].iov_base = &rtm;
345
	iov[iovcnt++].iov_len = sizeof(rtm);
346
347
	/* Add the destination address. */
348
	memset(&dest, 0, sizeof(dest));
349
	dest.sin_len = sizeof(dest);
350
	dest.sin_family = AF_INET;
351
	dest.sin_addr.s_addr = imsg->dest.s_addr;
352
353
	rtm.rtm_msglen += sizeof(dest);
354
	iov[iovcnt].iov_base = &dest;
355
	iov[iovcnt++].iov_len = sizeof(dest);
356
357
	/* Add the gateways address. */
358
	memset(&gateway, 0, sizeof(gateway));
359
	gateway.sin_len = sizeof(gateway);
360
	gateway.sin_family = AF_INET;
361
	gateway.sin_addr.s_addr = imsg->gateway.s_addr;
362
363
	rtm.rtm_msglen += sizeof(gateway);
364
	iov[iovcnt].iov_base = &gateway;
365
	iov[iovcnt++].iov_len = sizeof(gateway);
366
367
	/* Add the network mask. */
368
	memset(&mask, 0, sizeof(mask));
369
	mask.sin_len = sizeof(mask);
370
	mask.sin_family = AF_INET;
371
	mask.sin_addr.s_addr = imsg->netmask.s_addr;
372
373
	rtm.rtm_msglen += sizeof(mask);
374
	iov[iovcnt].iov_base = &mask;
375
	iov[iovcnt++].iov_len = sizeof(mask);
376
377
	if (writev(routefd, iov, iovcnt) == -1) {
378
		if (errno != EEXIST || log_getverbose() != 0) {
379
			strlcpy(destbuf, inet_ntoa(imsg->dest),
380
			    sizeof(destbuf));
381
			strlcpy(maskbuf, inet_ntoa(imsg->netmask),
382
			    sizeof(maskbuf));
383
			log_warn("%s: add route %s/%s via %s", log_procname,
384
			    destbuf, maskbuf, inet_ntoa(imsg->gateway));
385
		}
386
	}
387
}
388
389
/*
390
 * delete_addresses() deletes existing inet addresses on the named interface,
391
 * leaving in place newaddr/newnetmask.
392
 *
393
 * Return 1 if newaddr/newnetmask is seen while deleting addresses, 0 otherwise.
394
 */
395
int
396
delete_addresses(char *name, struct in_addr newaddr, struct in_addr newnetmask)
397
{
398
	struct in_addr		 addr, netmask;
399
	struct ifaddrs		*ifap, *ifa;
400
	int			 found = 0;
401
402
	if (getifaddrs(&ifap) != 0)
403
		fatal("getifaddrs");
404
405
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
406
		if ((ifa->ifa_flags & IFF_LOOPBACK) != 0 ||
407
		    (ifa->ifa_flags & IFF_POINTOPOINT) != 0 ||
408
		    ((ifa->ifa_flags & IFF_UP) == 0) ||
409
		    (ifa->ifa_addr->sa_family != AF_INET) ||
410
		    (strcmp(name, ifa->ifa_name) != 0))
411
			continue;
412
413
		memcpy(&addr,
414
		    &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
415
		    sizeof(addr));
416
		memcpy(&netmask,
417
		    &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr,
418
		    sizeof(netmask));
419
420
		if (addr.s_addr == newaddr.s_addr &&
421
		    netmask.s_addr == newnetmask.s_addr)
422
			found = 1;
423
		else
424
			delete_address(addr);
425
	}
426
427
	freeifaddrs(ifap);
428
	return (found);
429
}
430
431
/*
432
 * [priv_]delete_address is the equivalent of
433
 *
434
 *	ifconfig <ifname> inet <addr> delete
435
 */
436
void
437
delete_address(struct in_addr addr)
438
{
439
	struct imsg_delete_address	 imsg;
440
	int				 rslt;
441
442
	imsg.addr = addr;
443
444
	rslt = imsg_compose(unpriv_ibuf, IMSG_DELETE_ADDRESS, 0, 0 , -1, &imsg,
445
	    sizeof(imsg));
446
	if (rslt == -1)
447
		log_warn("%s: imsg_compose(IMSG_DELETE_ADDRESS)", log_procname);
448
}
449
450
void
451
priv_delete_address(char *name, int ioctlfd, struct imsg_delete_address *imsg)
452
{
453
	struct ifaliasreq	 ifaliasreq;
454
	struct sockaddr_in	*in;
455
456
	/*
457
	 * Delete specified address on specified interface.
458
	 */
459
460
	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
461
	strncpy(ifaliasreq.ifra_name, name, sizeof(ifaliasreq.ifra_name));
462
463
	in = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
464
	in->sin_family = AF_INET;
465
	in->sin_len = sizeof(ifaliasreq.ifra_addr);
466
	in->sin_addr.s_addr = imsg->addr.s_addr;
467
468
	/* SIOCDIFADDR will result in a RTM_DELADDR message we must catch! */
469
	if (ioctl(ioctlfd, SIOCDIFADDR, &ifaliasreq) == -1) {
470
		if (errno != EADDRNOTAVAIL)
471
			log_warn("%s: SIOCDIFADDR %s", log_procname,
472
			    inet_ntoa(imsg->addr));
473
	}
474
}
475
476
/*
477
 * [priv_]set_mtu is the equivalent of
478
 *
479
 *      ifconfig <if> mtu <mtu>
480
 */
481
void
482
set_mtu(int inits, uint16_t mtu)
483
{
484
	struct imsg_set_mtu	 imsg;
485
	int			 rslt;
486
487
	if ((inits & RTV_MTU) == 0)
488
		return;
489
490
	if (mtu < 68) {
491
		log_warnx("%s: mtu size %u < 68: ignored", log_procname, mtu);
492
		return;
493
	}
494
	imsg.mtu = mtu;
495
496
	rslt = imsg_compose(unpriv_ibuf, IMSG_SET_MTU, 0, 0, -1,
497
	    &imsg, sizeof(imsg));
498
	if (rslt == -1)
499
		log_warn("%s: imsg_compose(IMSG_SET_MTU)", log_procname);
500
}
501
502
void
503
priv_set_mtu(char *name, int ioctlfd, struct imsg_set_mtu *imsg)
504
{
505
	struct ifreq	 ifr;
506
507
	memset(&ifr, 0, sizeof(ifr));
508
509
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
510
	ifr.ifr_mtu = imsg->mtu;
511
512
	if (ioctl(ioctlfd, SIOCSIFMTU, &ifr) == -1)
513
		log_warn("%s: SIOCSIFMTU %d", log_procname, imsg->mtu);
514
}
515
516
/*
517
 * [priv_]set_address is the equivalent of
518
 *
519
 *	ifconfig <if> inet <addr> netmask <mask> broadcast <addr>
520
 */
521
void
522
set_address(char *name, struct in_addr addr, struct in_addr netmask)
523
{
524
	struct imsg_set_address	 imsg;
525
	int			 rslt;
526
527
	/* Deleting the addresses also clears out arp entries. */
528
	if (delete_addresses(name, addr, netmask) != 0)
529
		return;
530
531
	imsg.addr = addr;
532
	imsg.mask = netmask;
533
534
	rslt = imsg_compose(unpriv_ibuf, IMSG_SET_ADDRESS, 0, 0, -1, &imsg,
535
	    sizeof(imsg));
536
	if (rslt == -1)
537
		log_warn("%s: imsg_compose(IMSG_SET_ADDRESS)", log_procname);
538
}
539
540
void
541
priv_set_address(char *name, int ioctlfd, struct imsg_set_address *imsg)
542
{
543
	struct ifaliasreq	 ifaliasreq;
544
	struct sockaddr_in	*in;
545
546
	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
547
	strncpy(ifaliasreq.ifra_name, name, sizeof(ifaliasreq.ifra_name));
548
549
	/* The actual address in ifra_addr. */
550
	in = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
551
	in->sin_family = AF_INET;
552
	in->sin_len = sizeof(ifaliasreq.ifra_addr);
553
	in->sin_addr.s_addr = imsg->addr.s_addr;
554
555
	/* And the netmask in ifra_mask. */
556
	in = (struct sockaddr_in *)&ifaliasreq.ifra_mask;
557
	in->sin_family = AF_INET;
558
	in->sin_len = sizeof(ifaliasreq.ifra_mask);
559
	memcpy(&in->sin_addr, &imsg->mask, sizeof(in->sin_addr));
560
561
	/* No need to set broadcast address. Kernel can figure it out. */
562
563
	if (ioctl(ioctlfd, SIOCAIFADDR, &ifaliasreq) == -1)
564
		log_warn("%s: SIOCAIFADDR %s", log_procname,
565
		    inet_ntoa(imsg->addr));
566
}
567
568
/*
569
 * [priv_]write_resolv_conf write out a new resolv.conf.
570
 */
571
void
572
write_resolv_conf(void)
573
{
574
	int	 rslt;
575
576
	rslt = imsg_compose(unpriv_ibuf, IMSG_WRITE_RESOLV_CONF,
577
	    0, 0, -1, NULL, 0);
578
	if (rslt == -1)
579
		log_warn("%s: imsg_compose(IMSG_WRITE_RESOLV_CONF)",
580
		    log_procname);
581
}
582
583
void
584
priv_write_resolv_conf(char *contents)
585
{
586
	const char	*path = "/etc/resolv.conf";
587
	ssize_t		 n;
588
	size_t		 sz;
589
	int		 fd;
590
591
	if (contents == NULL)
592
		return;
593
594
	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC,
595
	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
596
597
	if (fd == -1) {
598
		log_warn("%s: open(%s)", log_procname, path);
599
		return;
600
	}
601
602
	sz = strlen(contents);
603
	n = write(fd, contents, sz);
604
	if (n == -1)
605
		log_warn("%s: write(%s)", log_procname, path);
606
	else if ((size_t)n < sz)
607
		log_warnx("%s: write(%s): %zd of %zu bytes", log_procname,
608
		    path, n, sz);
609
610
	close(fd);
611
}
612
613
/*
614
 * default_route_index returns the index of the interface which the
615
 * default route (a.k.a. 0.0.0.0/0) is on.
616
 */
617
int
618
default_route_index(int rdomain, int routefd)
619
{
620
	struct pollfd		 fds[1];
621
	time_t			 start_time, cur_time;
622
	int			 nfds;
623
	struct iovec		 iov[3];
624
	struct sockaddr_in	 sin;
625
	struct {
626
		struct rt_msghdr	m_rtm;
627
		char			m_space[512];
628
	} m_rtmsg;
629
	pid_t			 pid;
630
	ssize_t			 len;
631
	int			 seq;
632
633
	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
634
	m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
635
	m_rtmsg.m_rtm.rtm_type = RTM_GET;
636
	m_rtmsg.m_rtm.rtm_tableid = rdomain;
637
	m_rtmsg.m_rtm.rtm_seq = seq = arc4random();
638
	m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
639
	m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) +
640
	    2 * sizeof(struct sockaddr_in);
641
642
	memset(&sin, 0, sizeof(sin));
643
	sin.sin_len = sizeof(sin);
644
	sin.sin_family = AF_INET;
645
646
	iov[0].iov_base = &m_rtmsg.m_rtm;
647
	iov[0].iov_len = sizeof(m_rtmsg.m_rtm);
648
	iov[1].iov_base = &sin;
649
	iov[1].iov_len = sizeof(sin);
650
	iov[2].iov_base = &sin;
651
	iov[2].iov_len = sizeof(sin);
652
653
	pid = getpid();
654
	if (time(&start_time) == -1)
655
		fatal("start time");
656
657
	if (writev(routefd, iov, 3) == -1) {
658
		log_warn("%s: writev(RTM_GET)", log_procname);
659
		return 0;
660
	}
661
662
	do {
663
		if (time(&cur_time) == -1)
664
			fatal("current time");
665
		fds[0].fd = routefd;
666
		fds[0].events = POLLIN;
667
		nfds = poll(fds, 1, 3);
668
		if (nfds == -1) {
669
			if (errno == EINTR)
670
				continue;
671
			log_warn("%s: poll(routefd)", log_procname);
672
			break;
673
		}
674
		if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
675
			log_warnx("%s: routefd: ERR|HUP|NVAL", log_procname);
676
			break;
677
		}
678
		if (nfds == 0 || (fds[0].revents & POLLIN) == 0)
679
			continue;
680
681
		len = read(routefd, &m_rtmsg, sizeof(m_rtmsg));
682
		if (len == -1) {
683
			log_warn("%s: read(RTM_GET)", log_procname);
684
			break;
685
		} else if (len == 0) {
686
			log_warnx("%s: read(RTM_GET): 0 bytes", log_procname);
687
			break;
688
		}
689
690
		if (m_rtmsg.m_rtm.rtm_version == RTM_VERSION &&
691
		    m_rtmsg.m_rtm.rtm_type == RTM_GET &&
692
		    m_rtmsg.m_rtm.rtm_pid == pid &&
693
		    m_rtmsg.m_rtm.rtm_seq == seq) {
694
			if (m_rtmsg.m_rtm.rtm_errno != 0) {
695
				log_warnx("%s: read(RTM_GET): %s", log_procname,
696
				    strerror(m_rtmsg.m_rtm.rtm_errno));
697
				break;
698
			}
699
			return m_rtmsg.m_rtm.rtm_index;
700
		}
701
	} while ((cur_time - start_time) <= 3);
702
703
	return 0;
704
}
705
706
/*
707
 * set_resolv_conf creates a string that are the resolv.conf contents
708
 * that should be used when the interface is determined to be the one to
709
 * create /etc/resolv.conf
710
 */
711
void
712
set_resolv_conf(char *name, uint8_t *rtsearch, unsigned int rtsearch_len,
713
    uint8_t *rtdns, unsigned int rtdns_len)
714
{
715
	char		*dn, *nss[MAXNS], *contents, *courtesy;
716
	struct in_addr	*addr;
717
	size_t		 len;
718
	unsigned int	 i, servers;
719
	int		 rslt;
720
721
	memset(nss, 0, sizeof(nss));
722
	len = 0;
723
724
	if (rtsearch_len != 0) {
725
		rslt = asprintf(&dn, "search %.*s\n", rtsearch_len,
726
		    rtsearch);
727
		if (rslt == -1)
728
			dn = NULL;
729
	} else
730
		dn = strdup("");
731
	if (dn == NULL)
732
		fatal("domainname");
733
	len += strlen(dn);
734
735
	if (rtdns_len != 0) {
736
		addr = (struct in_addr *)rtdns;
737
		servers = rtdns_len / sizeof(addr->s_addr);
738
		if (servers > MAXNS)
739
			servers = MAXNS;
740
		for (i = 0; i < servers; i++) {
741
			rslt = asprintf(&nss[i], "nameserver %s\n",
742
			    inet_ntoa(*addr));
743
			if (rslt == -1)
744
				fatal("nameserver");
745
			len += strlen(nss[i]);
746
			addr++;
747
		}
748
	}
749
750
	/*
751
	 * XXX historically dhclient-script did not overwrite
752
	 *     resolv.conf when neither search nor dns info
753
	 *     was provided. Is that really what we want?
754
	 */
755
	if (len > 0 && config->resolv_tail != NULL)
756
		len += strlen(config->resolv_tail);
757
758
	if (len == 0) {
759
		free(dn);
760
		contents = NULL;
761
		goto done;
762
	}
763
764
	rslt = asprintf(&courtesy, "# Generated by %s dhclient\n", name);
765
	if (rslt == -1)
766
		fatal("resolv.conf courtesy line");
767
	len += strlen(courtesy);
768
769
	len++; /* Need room for terminating NUL. */
770
	contents = calloc(1, len);
771
	if (contents == NULL)
772
		fatal("resolv.conf contents");
773
774
	strlcat(contents, courtesy, len);
775
	free(courtesy);
776
777
	strlcat(contents, dn, len);
778
	free(dn);
779
780
	for (i = 0; i < MAXNS; i++) {
781
		if (nss[i] != NULL) {
782
			strlcat(contents, nss[i], len);
783
			free(nss[i]);
784
		}
785
	}
786
787
	if (config->resolv_tail != NULL)
788
		strlcat(contents, config->resolv_tail, len);
789
790
done:
791
	rslt = imsg_compose(unpriv_ibuf, IMSG_SET_RESOLV_CONF,
792
	    0, 0, -1, contents, len);
793
	if (rslt == -1)
794
		log_warn("%s: imsg_compose(IMSG_SET_RESOLV_CONF)",
795
		    log_procname);
796
}
797
798
/*
799
 * get_rtaddrs populates the rti_info with pointers to the
800
 * sockaddr's contained in a rtm message.
801
 */
802
void
803
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
804
{
805
	int	i;
806
807
	for (i = 0; i < RTAX_MAX; i++) {
808
		if (addrs & (1 << i)) {
809
			rti_info[i] = sa;
810
			sa = (struct sockaddr *)((char *)(sa) +
811
			    ROUNDUP(sa->sa_len));
812
		} else
813
			rti_info[i] = NULL;
814
	}
815
}
816
817
unsigned int
818
route_in_rtstatic(struct rt_msghdr *rtm, uint8_t *rtstatic,
819
    unsigned int rtstatic_len)
820
{
821
	struct sockaddr		*rti_info[RTAX_MAX];
822
	struct sockaddr		*dst, *netmask, *gateway;
823
	in_addr_t		 dstaddr, netmaskaddr, gatewayaddr;
824
	in_addr_t		 rtstaticdstaddr, rtstaticnetmaskaddr;
825
	in_addr_t		 rtstaticgatewayaddr;
826
	unsigned int		 i, len;
827
828
	get_rtaddrs(rtm->rtm_addrs,
829
	    (struct sockaddr *)((char *)(rtm) + rtm->rtm_hdrlen),
830
	    rti_info);
831
832
	dst = rti_info[RTAX_DST];
833
	netmask = rti_info[RTAX_NETMASK];
834
	gateway = rti_info[RTAX_GATEWAY];
835
836
	if (dst == NULL || netmask == NULL || gateway == NULL)
837
		return rtstatic_len;
838
839
	if (dst->sa_family != AF_INET || netmask->sa_family != AF_INET ||
840
	    gateway->sa_family != AF_INET)
841
		return rtstatic_len;
842
843
	dstaddr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
844
	netmaskaddr = ((struct sockaddr_in *)netmask)->sin_addr.s_addr;
845
	gatewayaddr = ((struct sockaddr_in *)gateway)->sin_addr.s_addr;
846
847
	dstaddr &= netmaskaddr;
848
	i = 0;
849
	while (i < rtstatic_len)  {
850
		len = extract_classless_route(&rtstatic[i], rtstatic_len - i,
851
		    &rtstaticdstaddr, &rtstaticnetmaskaddr,
852
		    &rtstaticgatewayaddr);
853
		if (len == 0)
854
			break;
855
856
		if (dstaddr == rtstaticdstaddr &&
857
		    netmaskaddr == rtstaticnetmaskaddr &&
858
		    gatewayaddr == rtstaticgatewayaddr)
859
			return i;
860
861
		i += len;
862
	}
863
864
	return rtstatic_len;
865
}