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

Line Branch Exec Source
1
/*	$OpenBSD: kroute.c,v 1.80 2016/07/21 09:58:55 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/sysctl.h>
22
23
#include <arpa/inet.h>
24
25
#include <net/if.h>
26
#include <net/if_types.h>
27
#include <net/route.h>
28
29
#include <netinet/in.h>
30
#include <netinet/if_ether.h>
31
32
#include <errno.h>
33
#include <ifaddrs.h>
34
#include <imsg.h>
35
#include <limits.h>
36
#include <signal.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
42
#include "dhcp.h"
43
#include "dhcpd.h"
44
#include "privsep.h"
45
46
struct in_addr active_addr;
47
48
int	create_route_label(struct sockaddr_rtlabel *);
49
int	check_route_label(struct sockaddr_rtlabel *);
50
void	populate_rti_info(struct sockaddr **, struct rt_msghdr *);
51
void	delete_route(int, struct rt_msghdr *);
52
53
#define	ROUTE_LABEL_NONE		1
54
#define	ROUTE_LABEL_NOT_DHCLIENT	2
55
#define	ROUTE_LABEL_DHCLIENT_OURS	3
56
#define	ROUTE_LABEL_DHCLIENT_UNKNOWN	4
57
#define	ROUTE_LABEL_DHCLIENT_LIVE	5
58
#define	ROUTE_LABEL_DHCLIENT_DEAD	6
59
60
/*
61
 * Do equivalent of
62
 *
63
 *	route -q $rdomain -n flush -inet -iface $interface
64
 *	arp -dan
65
 */
66
void
67
flush_routes(void)
68
{
69
	struct imsg_flush_routes imsg;
70
	int			 rslt;
71
72
	imsg.zapzombies = 1;
73
74
	rslt = imsg_compose(unpriv_ibuf, IMSG_FLUSH_ROUTES, 0, 0, -1,
75
	    &imsg, sizeof(imsg));
76
	if (rslt == -1)
77
		warning("flush_routes: imsg_compose: %s", strerror(errno));
78
79
	flush_unpriv_ibuf("flush_routes");
80
}
81
82
void
83
priv_flush_routes(struct imsg_flush_routes *imsg)
84
{
85
	char ifname[IF_NAMESIZE];
86
	struct sockaddr *rti_info[RTAX_MAX];
87
	int mib[7];
88
	size_t needed;
89
	char *lim, *buf = NULL, *bufp, *next, *errmsg = NULL;
90
	struct rt_msghdr *rtm;
91
	struct sockaddr_in *sa_in;
92
	struct sockaddr_rtlabel *sa_rl;
93
	int s;
94
95
	mib[0] = CTL_NET;
96
	mib[1] = PF_ROUTE;
97
	mib[2] = 0;
98
	mib[3] = AF_INET;
99
	mib[4] = NET_RT_FLAGS;
100
	mib[5] = RTF_GATEWAY;
101
	mib[6] = ifi->rdomain;
102
103
	while (1) {
104
		if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) {
105
			errmsg = "sysctl size of routes:";
106
			break;
107
		}
108
		if (needed == 0) {
109
			free(buf);
110
			return;
111
		}
112
		if ((bufp = realloc(buf, needed)) == NULL) {
113
			errmsg = "routes buf realloc:";
114
			break;
115
		}
116
		buf = bufp;
117
		if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) {
118
			if (errno == ENOMEM)
119
				continue;
120
			errmsg = "sysctl retrieval of routes:";
121
			break;
122
		}
123
		break;
124
	}
125
126
	if (errmsg) {
127
		warning("route cleanup failed - %s %s (msize=%zu)",
128
		    errmsg, strerror(errno), needed);
129
		free(buf);
130
		return;
131
	}
132
133
	if ((s = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
134
		error("opening socket to flush routes: %s", strerror(errno));
135
136
	lim = buf + needed;
137
	for (next = buf; next < lim; next += rtm->rtm_msglen) {
138
		rtm = (struct rt_msghdr *)next;
139
		if (rtm->rtm_version != RTM_VERSION)
140
			continue;
141
142
		populate_rti_info(rti_info, rtm);
143
144
		sa_rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL];
145
		sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
146
147
		switch (check_route_label(sa_rl)) {
148
		case ROUTE_LABEL_DHCLIENT_OURS:
149
			/* Always delete routes we labeled. */
150
			delete_route(s, rtm);
151
			break;
152
		case ROUTE_LABEL_DHCLIENT_DEAD:
153
			if (imsg->zapzombies)
154
				delete_route(s, rtm);
155
			break;
156
		case ROUTE_LABEL_DHCLIENT_LIVE:
157
		case ROUTE_LABEL_DHCLIENT_UNKNOWN:
158
			/* Another dhclient's responsibility. */
159
			break;
160
		case ROUTE_LABEL_NONE:
161
		case ROUTE_LABEL_NOT_DHCLIENT:
162
			/* Delete default routes on our interface. */
163
			if (if_indextoname(rtm->rtm_index, ifname) &&
164
			    sa_in &&
165
			    sa_in->sin_addr.s_addr == INADDR_ANY &&
166
			    rtm->rtm_tableid == ifi->rdomain &&
167
			    strcmp(ifi->name, ifname) == 0)
168
				delete_route(s, rtm);
169
			break;
170
		default:
171
			break;
172
		}
173
	}
174
175
	close(s);
176
	free(buf);
177
}
178
179
void
180
add_route(struct in_addr dest, struct in_addr netmask,
181
    struct in_addr gateway, struct in_addr ifa, int addrs, int flags)
182
{
183
	struct imsg_add_route	 imsg;
184
	int			 rslt;
185
186
	imsg.dest = dest;
187
	imsg.gateway = gateway;
188
	imsg.netmask = netmask;
189
	imsg.ifa = ifa;
190
	imsg.addrs = addrs;
191
	imsg.flags = flags;
192
193
	rslt = imsg_compose(unpriv_ibuf, IMSG_ADD_ROUTE, 0, 0, -1,
194
	    &imsg, sizeof(imsg));
195
	if (rslt == -1)
196
		warning("add_route: imsg_compose: %s", strerror(errno));
197
198
	flush_unpriv_ibuf("add_route");
199
}
200
201
void
202
priv_add_route(struct imsg_add_route *imsg)
203
{
204
	char destbuf[INET_ADDRSTRLEN], gatewaybuf[INET_ADDRSTRLEN];
205
	char maskbuf[INET_ADDRSTRLEN], ifabuf[INET_ADDRSTRLEN];
206
	struct rt_msghdr rtm;
207
	struct sockaddr_in dest, gateway, mask, ifa;
208
	struct sockaddr_rtlabel label;
209
	struct iovec iov[6];
210
	int s, i, iovcnt = 0;
211
212
	if ((s = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
213
		error("Routing Socket open failed: %s", strerror(errno));
214
215
	memset(destbuf, 0, sizeof(destbuf));
216
	memset(maskbuf, 0, sizeof(maskbuf));
217
	memset(gatewaybuf, 0, sizeof(gatewaybuf));
218
	memset(ifabuf, 0, sizeof(ifabuf));
219
220
	/* Build RTM header */
221
222
	memset(&rtm, 0, sizeof(rtm));
223
224
	rtm.rtm_version = RTM_VERSION;
225
	rtm.rtm_type = RTM_ADD;
226
	rtm.rtm_tableid = ifi->rdomain;
227
	rtm.rtm_priority = RTP_NONE;
228
	rtm.rtm_msglen = sizeof(rtm);
229
	rtm.rtm_addrs = imsg->addrs;
230
	rtm.rtm_flags = imsg->flags;
231
232
	iov[iovcnt].iov_base = &rtm;
233
	iov[iovcnt++].iov_len = sizeof(rtm);
234
235
	if (imsg->addrs & RTA_DST) {
236
		strlcpy(destbuf, inet_ntoa(imsg->dest), sizeof(destbuf));
237
		memset(&dest, 0, sizeof(dest));
238
239
		dest.sin_len = sizeof(dest);
240
		dest.sin_family = AF_INET;
241
		dest.sin_addr.s_addr = imsg->dest.s_addr;
242
243
		rtm.rtm_msglen += sizeof(dest);
244
245
		iov[iovcnt].iov_base = &dest;
246
		iov[iovcnt++].iov_len = sizeof(dest);
247
	}
248
249
	if (imsg->addrs & RTA_GATEWAY) {
250
		strlcpy(gatewaybuf, inet_ntoa(imsg->gateway),
251
		    sizeof(gatewaybuf));
252
		memset(&gateway, 0, sizeof(gateway));
253
254
		gateway.sin_len = sizeof(gateway);
255
		gateway.sin_family = AF_INET;
256
		gateway.sin_addr.s_addr = imsg->gateway.s_addr;
257
258
		rtm.rtm_msglen += sizeof(gateway);
259
260
		iov[iovcnt].iov_base = &gateway;
261
		iov[iovcnt++].iov_len = sizeof(gateway);
262
	}
263
264
	if (imsg->addrs & RTA_NETMASK) {
265
		strlcpy(maskbuf, inet_ntoa(imsg->netmask), sizeof(maskbuf));
266
		memset(&mask, 0, sizeof(mask));
267
268
		mask.sin_len = sizeof(mask);
269
		mask.sin_family = AF_INET;
270
		mask.sin_addr.s_addr = imsg->netmask.s_addr;
271
272
		rtm.rtm_msglen += sizeof(mask);
273
274
		iov[iovcnt].iov_base = &mask;
275
		iov[iovcnt++].iov_len = sizeof(mask);
276
	}
277
278
	if (imsg->addrs & RTA_IFA) {
279
		strlcpy(ifabuf, inet_ntoa(imsg->ifa), sizeof(ifabuf));
280
		memset(&ifa, 0, sizeof(ifa));
281
282
		ifa.sin_len = sizeof(ifa);
283
		ifa.sin_family = AF_INET;
284
		ifa.sin_addr.s_addr = imsg->ifa.s_addr;
285
286
		rtm.rtm_msglen += sizeof(ifa);
287
288
		iov[iovcnt].iov_base = &ifa;
289
		iov[iovcnt++].iov_len = sizeof(ifa);
290
	}
291
292
	/* Add our label so we can identify the route as our creation. */
293
	if (create_route_label(&label) == 0) {
294
		rtm.rtm_addrs |= RTA_LABEL;
295
		rtm.rtm_msglen += sizeof(label);
296
		iov[iovcnt].iov_base = &label;
297
		iov[iovcnt++].iov_len = sizeof(label);
298
	}
299
300
	/* Check for EEXIST since other dhclient may not be done. */
301
	for (i = 0; i < 5; i++) {
302
		if (writev(s, iov, iovcnt) != -1)
303
			break;
304
		if (i == 4)
305
			warning("failed to add route (%s/%s via %s/%s): %s",
306
			    destbuf, maskbuf, gatewaybuf, ifabuf,
307
			    strerror(errno));
308
		else if (errno == EEXIST || errno == ENETUNREACH)
309
			sleep(1);
310
	}
311
312
	close(s);
313
}
314
315
/*
316
 * Delete all existing inet addresses on interface.
317
 */
318
void
319
delete_addresses(void)
320
{
321
	struct in_addr addr;
322
	struct ifaddrs *ifap, *ifa;
323
324
	if (getifaddrs(&ifap) != 0)
325
		error("delete_addresses getifaddrs: %s", strerror(errno));
326
327
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
328
		if ((ifa->ifa_flags & IFF_LOOPBACK) ||
329
		    (ifa->ifa_flags & IFF_POINTOPOINT) ||
330
		    (!(ifa->ifa_flags & IFF_UP)) ||
331
		    (ifa->ifa_addr->sa_family != AF_INET) ||
332
		    (strcmp(ifi->name, ifa->ifa_name) != 0))
333
			continue;
334
335
		memcpy(&addr, &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
336
		    sizeof(addr));
337
338
		delete_address(addr);
339
	}
340
341
	freeifaddrs(ifap);
342
}
343
344
/*
345
 * [priv_]delete_address is the equivalent of
346
 *
347
 *	ifconfig <ifname> inet <addr> delete
348
 */
349
void
350
delete_address(struct in_addr addr)
351
{
352
	struct imsg_delete_address	 imsg;
353
	int				 rslt;
354
355
	/* Note the address we are deleting for RTM_DELADDR filtering! */
356
	deleting.s_addr = addr.s_addr;
357
358
	imsg.addr = addr;
359
360
	rslt = imsg_compose(unpriv_ibuf, IMSG_DELETE_ADDRESS, 0, 0 , -1, &imsg,
361
	    sizeof(imsg));
362
	if (rslt == -1)
363
		warning("delete_address: imsg_compose: %s", strerror(errno));
364
365
	flush_unpriv_ibuf("delete_address");
366
}
367
368
void
369
priv_delete_address(struct imsg_delete_address *imsg)
370
{
371
	struct ifaliasreq ifaliasreq;
372
	struct sockaddr_in *in;
373
	int s;
374
375
	/*
376
	 * Delete specified address on specified interface.
377
	 */
378
379
	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
380
		error("socket open failed: %s", strerror(errno));
381
382
	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
383
	strncpy(ifaliasreq.ifra_name, ifi->name, sizeof(ifaliasreq.ifra_name));
384
385
	in = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
386
	in->sin_family = AF_INET;
387
	in->sin_len = sizeof(ifaliasreq.ifra_addr);
388
	in->sin_addr.s_addr = imsg->addr.s_addr;
389
390
	/* SIOCDIFADDR will result in a RTM_DELADDR message we must catch! */
391
	if (ioctl(s, SIOCDIFADDR, &ifaliasreq) == -1) {
392
		if (errno != EADDRNOTAVAIL)
393
			warning("SIOCDIFADDR failed (%s): %s",
394
			    inet_ntoa(imsg->addr), strerror(errno));
395
	}
396
397
	close(s);
398
}
399
400
/*
401
 * [priv_]set_interface_mtu is the equivalent of
402
 *
403
 *      ifconfig <if> mtu <mtu>
404
 */
405
void
406
set_interface_mtu(int mtu)
407
{
408
	struct imsg_set_interface_mtu imsg;
409
	int rslt;
410
411
	imsg.mtu = mtu;
412
413
	rslt = imsg_compose(unpriv_ibuf, IMSG_SET_INTERFACE_MTU, 0, 0, -1,
414
	    &imsg, sizeof(imsg));
415
	if (rslt == -1)
416
		warning("set_interface_mtu: imsg_compose: %s", strerror(errno));
417
418
	flush_unpriv_ibuf("set_interface_mtu");
419
}
420
421
void
422
priv_set_interface_mtu(struct imsg_set_interface_mtu *imsg)
423
{
424
	struct ifreq ifr;
425
	int s;
426
427
	memset(&ifr, 0, sizeof(ifr));
428
429
	strlcpy(ifr.ifr_name, ifi->name, sizeof(ifr.ifr_name));
430
	ifr.ifr_mtu = imsg->mtu;
431
432
	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
433
		error("socket open failed: %s", strerror(errno));
434
	if (ioctl(s, SIOCSIFMTU, &ifr) == -1)
435
		warning("SIOCSIFMTU failed (%d): %s", imsg->mtu,
436
		    strerror(errno));
437
	close(s);
438
}
439
440
/*
441
 * [priv_]add_address is the equivalent of
442
 *
443
 *	ifconfig <if> inet <addr> netmask <mask> broadcast <addr>
444
 */
445
void
446
add_address(struct in_addr addr, struct in_addr mask)
447
{
448
	struct imsg_add_address imsg;
449
	int			rslt;
450
451
	/* Note the address we are adding for RTM_NEWADDR filtering! */
452
	adding = addr;
453
454
	imsg.addr = addr;
455
	imsg.mask = mask;
456
457
	rslt = imsg_compose(unpriv_ibuf, IMSG_ADD_ADDRESS, 0, 0, -1, &imsg,
458
	    sizeof(imsg));
459
	if (rslt == -1)
460
		warning("add_address: imsg_compose: %s", strerror(errno));
461
462
	flush_unpriv_ibuf("add_address");
463
}
464
465
void
466
priv_add_address(struct imsg_add_address *imsg)
467
{
468
	struct ifaliasreq ifaliasreq;
469
	struct sockaddr_in *in;
470
	int s;
471
472
	if (imsg->addr.s_addr == INADDR_ANY) {
473
		/* Notification that the active_addr has been deleted. */
474
		active_addr.s_addr = INADDR_ANY;
475
		quit = INTERNALSIG;
476
		return;
477
	}
478
479
	/*
480
	 * Add specified address on specified interface.
481
	 */
482
483
	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
484
		error("socket open failed: %s", strerror(errno));
485
486
	memset(&ifaliasreq, 0, sizeof(ifaliasreq));
487
	strncpy(ifaliasreq.ifra_name, ifi->name, sizeof(ifaliasreq.ifra_name));
488
489
	/* The actual address in ifra_addr. */
490
	in = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
491
	in->sin_family = AF_INET;
492
	in->sin_len = sizeof(ifaliasreq.ifra_addr);
493
	in->sin_addr.s_addr = imsg->addr.s_addr;
494
495
	/* And the netmask in ifra_mask. */
496
	in = (struct sockaddr_in *)&ifaliasreq.ifra_mask;
497
	in->sin_family = AF_INET;
498
	in->sin_len = sizeof(ifaliasreq.ifra_mask);
499
	memcpy(&in->sin_addr, &imsg->mask, sizeof(in->sin_addr));
500
501
	/* No need to set broadcast address. Kernel can figure it out. */
502
503
	if (ioctl(s, SIOCAIFADDR, &ifaliasreq) == -1)
504
		warning("SIOCAIFADDR failed (%s): %s", inet_ntoa(imsg->addr),
505
		    strerror(errno));
506
507
	close(s);
508
509
	active_addr = imsg->addr;
510
}
511
512
/*
513
 * Inform the [priv] process a HUP was received and it should restart.
514
 */
515
void
516
sendhup(struct client_lease *active)
517
{
518
	struct imsg_hup imsg;
519
	int rslt;
520
521
	if (active)
522
		imsg.addr = active->address;
523
	else
524
		imsg.addr.s_addr = INADDR_ANY;
525
526
	rslt = imsg_compose(unpriv_ibuf, IMSG_HUP, 0, 0, -1,
527
	    &imsg, sizeof(imsg));
528
	if (rslt == -1)
529
		warning("sendhup: imsg_compose: %s", strerror(errno));
530
531
	flush_unpriv_ibuf("sendhup");
532
}
533
534
/*
535
 * priv_cleanup removes dhclient installed routes and address.
536
 */
537
void
538
priv_cleanup(struct imsg_hup *imsg)
539
{
540
	struct imsg_flush_routes fimsg;
541
	struct imsg_delete_address dimsg;
542
543
	fimsg.zapzombies = 0;	/* Only zapzombies when binding a lease. */
544
	priv_flush_routes(&fimsg);
545
546
	if (imsg->addr.s_addr == INADDR_ANY)
547
		return;
548
549
	dimsg.addr = imsg->addr;
550
	priv_delete_address(&dimsg);
551
}
552
553
int
554
resolv_conf_priority(void)
555
{
556
	struct iovec iov[3];
557
	struct {
558
		struct rt_msghdr	m_rtm;
559
		char			m_space[512];
560
	} m_rtmsg;
561
	struct sockaddr *rti_info[RTAX_MAX];
562
	struct sockaddr_in sin;
563
	struct sockaddr_rtlabel *sa_rl;
564
	pid_t pid;
565
	ssize_t len;
566
	u_int32_t seq;
567
	int s, rslt, iovcnt = 0;
568
569
	rslt = 0;
570
571
	s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
572
	if (s == -1) {
573
		warning("default route socket: %s", strerror(errno));
574
		return (0);
575
	}
576
577
	/* Build RTM header */
578
579
	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
580
581
	m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
582
	m_rtmsg.m_rtm.rtm_type = RTM_GET;
583
	m_rtmsg.m_rtm.rtm_msglen = sizeof(m_rtmsg.m_rtm);
584
	m_rtmsg.m_rtm.rtm_flags = RTF_STATIC | RTF_GATEWAY | RTF_UP;
585
	m_rtmsg.m_rtm.rtm_seq = seq = arc4random();
586
	m_rtmsg.m_rtm.rtm_tableid = ifi->rdomain;
587
588
	iov[iovcnt].iov_base = &m_rtmsg.m_rtm;
589
	iov[iovcnt++].iov_len = sizeof(m_rtmsg.m_rtm);
590
591
	/* Set destination & netmask addresses of all zeros. */
592
593
	m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
594
595
	memset(&sin, 0, sizeof(sin));
596
	sin.sin_len = sizeof(sin);
597
	sin.sin_family = AF_INET;
598
599
	iov[iovcnt].iov_base = &sin;
600
	iov[iovcnt++].iov_len = sizeof(sin);
601
	iov[iovcnt].iov_base = &sin;
602
	iov[iovcnt++].iov_len = sizeof(sin);
603
604
	m_rtmsg.m_rtm.rtm_msglen += 2 * sizeof(sin);
605
606
	if (writev(s, iov, iovcnt) == -1) {
607
		if (errno != ESRCH)
608
			warning("RTM_GET of default route: %s",
609
			    strerror(errno));
610
		goto done;
611
	}
612
613
	pid = getpid();
614
615
	do {
616
		len = read(s, &m_rtmsg, sizeof(m_rtmsg));
617
		if (len == -1) {
618
			warning("get default route read: %s", strerror(errno));
619
			break;
620
		} else if (len == 0) {
621
			warning("no data from default route read");
622
			break;
623
		}
624
		if (m_rtmsg.m_rtm.rtm_version != RTM_VERSION)
625
			continue;
626
		if (m_rtmsg.m_rtm.rtm_type == RTM_GET &&
627
		    m_rtmsg.m_rtm.rtm_pid == pid &&
628
		    m_rtmsg.m_rtm.rtm_seq == seq) {
629
			if (m_rtmsg.m_rtm.rtm_errno) {
630
				warning("default route read rtm: %s",
631
				    strerror(m_rtmsg.m_rtm.rtm_errno));
632
				goto done;
633
			}
634
			break;
635
		}
636
	} while (1);
637
638
	populate_rti_info(rti_info, &m_rtmsg.m_rtm);
639
640
	sa_rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL];
641
	if (check_route_label(sa_rl) == ROUTE_LABEL_DHCLIENT_OURS)
642
		rslt = 1;
643
644
done:
645
	close(s);
646
	return (rslt);
647
}
648
649
int
650
create_route_label(struct sockaddr_rtlabel *label)
651
{
652
	int len;
653
654
	memset(label, 0, sizeof(*label));
655
656
	label->sr_len = sizeof(label);
657
	label->sr_family = AF_UNSPEC;
658
659
	len = snprintf(label->sr_label, sizeof(label->sr_label), "DHCLIENT %d",
660
	    (int)getpid());
661
662
	if (len == -1) {
663
		warning("creating route label: %s", strerror(errno));
664
		return (1);
665
	}
666
667
	if (len >= sizeof(label->sr_label)) {
668
		warning("creating route label: label too long (%d vs %zu)", len,
669
		    sizeof(label->sr_label));
670
		return (1);
671
	}
672
673
	return (0);
674
}
675
676
int
677
check_route_label(struct sockaddr_rtlabel *label)
678
{
679
	pid_t pid;
680
681
	if (!label)
682
		return (ROUTE_LABEL_NONE);
683
684
	if (strncmp("DHCLIENT ", label->sr_label, 9) != 0)
685
		return (ROUTE_LABEL_NOT_DHCLIENT);
686
687
	pid = (pid_t)strtonum(label->sr_label + 9, 1, INT_MAX, NULL);
688
	if (pid <= 0)
689
		return (ROUTE_LABEL_DHCLIENT_UNKNOWN);
690
691
	if (pid == getpid())
692
		return (ROUTE_LABEL_DHCLIENT_OURS);
693
694
	if (kill(pid, 0) == -1) {
695
		if (errno == ESRCH)
696
			return (ROUTE_LABEL_DHCLIENT_DEAD);
697
		else
698
			return (ROUTE_LABEL_DHCLIENT_UNKNOWN);
699
	}
700
701
	return (ROUTE_LABEL_DHCLIENT_LIVE);
702
}
703
704
void
705
populate_rti_info(struct sockaddr **rti_info, struct rt_msghdr *rtm)
706
{
707
	struct sockaddr *sa;
708
	int i;
709
710
#define ROUNDUP(a) \
711
    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
712
713
	sa = (struct sockaddr *)((char *)(rtm) + rtm->rtm_hdrlen);
714
715
	for (i = 0; i < RTAX_MAX; i++) {
716
		if (rtm->rtm_addrs & (1 << i)) {
717
			rti_info[i] = sa;
718
			sa = (struct sockaddr *)((char *)(sa) +
719
			    ROUNDUP(sa->sa_len));
720
		} else
721
			rti_info[i] = NULL;
722
	}
723
}
724
725
void
726
delete_route(int s, struct rt_msghdr *rtm)
727
{
728
	static int seqno;
729
	ssize_t rlen;
730
731
	rtm->rtm_type = RTM_DELETE;
732
	rtm->rtm_tableid = ifi->rdomain;
733
	rtm->rtm_seq = seqno++;
734
735
	rlen = write(s, (char *)rtm, rtm->rtm_msglen);
736
	if (rlen == -1) {
737
		if (errno != ESRCH)
738
			error("RTM_DELETE write: %s", strerror(errno));
739
	} else if (rlen < (int)rtm->rtm_msglen)
740
		error("short RTM_DELETE write (%zd)\n", rlen);
741
}
742
743
void
744
flush_unpriv_ibuf(const char *who)
745
{
746
	while (unpriv_ibuf->w.queued) {
747
		if (msgbuf_write(&unpriv_ibuf->w) <= 0) {
748
			if (errno == EAGAIN)
749
				break;
750
			if (quit == 0)
751
				quit = INTERNALSIG;
752
			if (errno != EPIPE && errno != 0)
753
				warning("%s: msgbuf_write: %s", who,
754
				    strerror(errno));
755
			break;
756
		}
757
	}
758
}