GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/rtadvd/if.c Lines: 0 166 0.0 %
Date: 2017-11-07 Branches: 0 106 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: if.c,v 1.46 2017/08/12 07:38:26 florian Exp $	*/
2
/*	$KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $	*/
3
4
/*
5
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6
 * 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
 * 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 project nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/socket.h>
34
#include <sys/sysctl.h>
35
#include <sys/queue.h>
36
#include <sys/ioctl.h>
37
#include <net/if.h>
38
#include <net/if_types.h>
39
#include <ifaddrs.h>
40
#include <net/route.h>
41
#include <net/if_dl.h>
42
#include <netinet/in.h>
43
#include <netinet/icmp6.h>
44
#include <netinet/if_ether.h>
45
#include <unistd.h>
46
#include <errno.h>
47
#include <stdlib.h>
48
#include <string.h>
49
#include <event.h>
50
51
#include "rtadvd.h"
52
#include "if.h"
53
#include "log.h"
54
55
#define ROUNDUP(a, size) \
56
	(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
57
58
#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
59
	((char *)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
60
						 sizeof(u_long)) :\
61
			  			 sizeof(u_long)))
62
63
struct if_msghdr **iflist;
64
static void get_iflist(char **buf, size_t *size);
65
static void parse_iflist(struct if_msghdr ***ifmlist_p, char *buf,
66
    size_t bufsize);
67
68
extern int ioctl_sock;
69
70
static void
71
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
72
{
73
	int i;
74
75
	for (i = 0; i < RTAX_MAX; i++) {
76
		if (addrs & (1 << i)) {
77
			rti_info[i] = sa;
78
			NEXT_SA(sa);
79
		}
80
		else
81
			rti_info[i] = NULL;
82
	}
83
}
84
85
struct sockaddr_dl *
86
if_nametosdl(char *name)
87
{
88
	struct ifaddrs *ifap, *ifa;
89
	struct sockaddr_dl *sdl;
90
91
	if (getifaddrs(&ifap) != 0)
92
		return (NULL);
93
94
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
95
		if (strcmp(ifa->ifa_name, name) != 0)
96
			continue;
97
		if (ifa->ifa_addr->sa_family != AF_LINK)
98
			continue;
99
100
		sdl = malloc(ifa->ifa_addr->sa_len);
101
		if (!sdl)
102
			continue;	/*XXX*/
103
104
		memcpy(sdl, ifa->ifa_addr, ifa->ifa_addr->sa_len);
105
		freeifaddrs(ifap);
106
		return (sdl);
107
	}
108
109
	freeifaddrs(ifap);
110
	return (NULL);
111
}
112
113
int
114
if_getmtu(char *name)
115
{
116
	struct ifreq	ifr;
117
	u_long		mtu = 0;
118
119
	memset(&ifr, 0, sizeof(ifr));
120
	ifr.ifr_addr.sa_family = AF_INET6;
121
	if (strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)) >=
122
	    sizeof(ifr.ifr_name))
123
		fatalx("strlcpy");
124
	if (ioctl(ioctl_sock, SIOCGIFMTU, (char *)&ifr) >= 0)
125
		mtu = ifr.ifr_mtu;
126
	else
127
		log_warn("s: %d", ioctl_sock);
128
	return (mtu);
129
}
130
131
/* give interface index and its old flags, then new flags returned */
132
int
133
if_getflags(int ifindex, int oifflags)
134
{
135
	struct ifreq ifr;
136
137
	if_indextoname(ifindex, ifr.ifr_name);
138
	if (ioctl(ioctl_sock, SIOCGIFFLAGS, (char *)&ifr) < 0) {
139
		log_warn("ioctl:SIOCGIFFLAGS: failed for %s", ifr.ifr_name);
140
		return (oifflags & ~IFF_UP);
141
	}
142
	return (ifr.ifr_flags);
143
}
144
145
#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
146
int
147
lladdropt_length(struct sockaddr_dl *sdl)
148
{
149
	switch (sdl->sdl_type) {
150
	case IFT_CARP:
151
	case IFT_ETHER:
152
		return(ROUNDUP8(ETHER_ADDR_LEN + 2));
153
	default:
154
		return(0);
155
	}
156
}
157
158
void
159
lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
160
{
161
	char *addr;
162
163
	ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
164
165
	switch (sdl->sdl_type) {
166
	case IFT_CARP:
167
	case IFT_ETHER:
168
		ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
169
		addr = (char *)(ndopt + 1);
170
		memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
171
		break;
172
	default:
173
		fatalx("unsupported link type(%d)", sdl->sdl_type);
174
	}
175
}
176
177
#define SIN6(s) ((struct sockaddr_in6 *)(s))
178
int
179
validate_msg(char *buf)
180
{
181
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
182
	struct ifa_msghdr *ifam;
183
	struct sockaddr *sa, *dst, *ifa, *rti_info[RTAX_MAX];
184
185
	/* just for safety */
186
	if (!rtm->rtm_msglen) {
187
		log_warnx("rtm_msglen is 0 (rtm=%p)", rtm);
188
		return -1;
189
	}
190
	if (rtm->rtm_version != RTM_VERSION)
191
		return -1;
192
193
	switch (rtm->rtm_type) {
194
	case RTM_ADD:
195
	case RTM_DELETE:
196
		if (rtm->rtm_tableid != 0)
197
			return -1;
198
199
		/* address related checks */
200
		sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen);
201
		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
202
		if ((dst = rti_info[RTAX_DST]) == NULL ||
203
		    dst->sa_family != AF_INET6)
204
			return -1;
205
206
		if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
207
		    IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
208
			return -1;
209
210
		if (rti_info[RTAX_NETMASK] == NULL)
211
			return -1;
212
213
		/* found */
214
		return 0;
215
		/* NOTREACHED */
216
	case RTM_NEWADDR:
217
	case RTM_DELADDR:
218
		ifam = (struct ifa_msghdr *)rtm;
219
220
		/* address related checks */
221
		sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen);
222
		get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
223
		if ((ifa = rti_info[RTAX_IFA]) == NULL ||
224
		    (ifa->sa_family != AF_INET &&
225
		    ifa->sa_family != AF_INET6))
226
			return -1;
227
228
		if (ifa->sa_family == AF_INET6 &&
229
		    (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
230
		    IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
231
			return -1;
232
233
		/* found */
234
		return 0;
235
		/* NOTREACHED */
236
	case RTM_IFINFO:
237
		/* found */
238
		return 0;
239
		/* NOTREACHED */
240
	}
241
	return -1;
242
}
243
244
struct in6_addr *
245
get_addr(char *buf)
246
{
247
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
248
	struct sockaddr *sa, *rti_info[RTAX_MAX];
249
250
	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
251
	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
252
253
	return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
254
}
255
256
int
257
get_rtm_ifindex(char *buf)
258
{
259
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
260
261
	return rtm->rtm_index;
262
}
263
264
int
265
get_ifm_ifindex(char *buf)
266
{
267
	struct if_msghdr *ifm = (struct if_msghdr *)buf;
268
269
	return ((int)ifm->ifm_index);
270
}
271
272
int
273
get_ifam_ifindex(char *buf)
274
{
275
	struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf;
276
277
	return ((int)ifam->ifam_index);
278
}
279
280
int
281
get_ifm_flags(char *buf)
282
{
283
	struct if_msghdr *ifm = (struct if_msghdr *)buf;
284
285
	return (ifm->ifm_flags);
286
}
287
288
int
289
get_prefixlen(char *buf)
290
{
291
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
292
	struct sockaddr *sa, *rti_info[RTAX_MAX];
293
	u_char *p, *lim;
294
295
	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
296
	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
297
	sa = rti_info[RTAX_NETMASK];
298
299
	p = (u_char *)(&SIN6(sa)->sin6_addr);
300
	lim = (u_char *)sa + sa->sa_len;
301
	return prefixlen(p, lim);
302
}
303
304
int
305
prefixlen(u_char *p, u_char *lim)
306
{
307
	int masklen;
308
309
	for (masklen = 0; p < lim; p++) {
310
		switch (*p) {
311
		case 0xff:
312
			masklen += 8;
313
			break;
314
		case 0xfe:
315
			masklen += 7;
316
			break;
317
		case 0xfc:
318
			masklen += 6;
319
			break;
320
		case 0xf8:
321
			masklen += 5;
322
			break;
323
		case 0xf0:
324
			masklen += 4;
325
			break;
326
		case 0xe0:
327
			masklen += 3;
328
			break;
329
		case 0xc0:
330
			masklen += 2;
331
			break;
332
		case 0x80:
333
			masklen += 1;
334
			break;
335
		case 0x00:
336
			break;
337
		default:
338
			return(-1);
339
		}
340
	}
341
342
	return(masklen);
343
}
344
345
int
346
rtmsg_type(char *buf)
347
{
348
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
349
350
	return(rtm->rtm_type);
351
}
352
353
int
354
rtmsg_len(char *buf)
355
{
356
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
357
358
	return(rtm->rtm_msglen);
359
}
360
361
/*
362
 * alloc buffer and get if_msghdrs block from kernel,
363
 * and put them into the buffer
364
 */
365
static void
366
get_iflist(char **buf, size_t *size)
367
{
368
	int mib[6];
369
370
	mib[0] = CTL_NET;
371
	mib[1] = PF_ROUTE;
372
	mib[2] = 0;
373
	mib[3] = AF_INET6;
374
	mib[4] = NET_RT_IFLIST;
375
	mib[5] = 0;
376
	while (1) {
377
		if (sysctl(mib, 6, NULL, size, NULL, 0) == -1)
378
			fatal("sysctl: iflist size get failed");
379
		if (*size == 0)
380
			break;
381
		if ((*buf = realloc(*buf, *size)) == NULL)
382
			fatal(NULL);
383
		if (sysctl(mib, 6, *buf, size, NULL, 0) == -1) {
384
			if (errno == ENOMEM)
385
				continue;
386
			fatal("sysctl: iflist get failed");
387
		}
388
		break;
389
	}
390
}
391
392
/*
393
 * alloc buffer and parse if_msghdrs block passed as arg,
394
 * and init the buffer as list of pointers ot each of the if_msghdr.
395
 */
396
static void
397
parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
398
{
399
	int iflentry_size, malloc_size;
400
	struct if_msghdr *ifm;
401
	struct ifa_msghdr *ifam;
402
	char *lim;
403
404
	/*
405
	 * Estimate least size of an iflist entry, to be obtained from kernel.
406
	 * Should add sizeof(sockaddr) ??
407
	 */
408
	iflentry_size = sizeof(struct if_msghdr);
409
	/* roughly estimate max list size of pointers to each if_msghdr */
410
	malloc_size = (bufsize/iflentry_size) * sizeof(size_t);
411
	if ((*ifmlist_p = malloc(malloc_size)) == NULL)
412
		fatal(NULL);
413
414
	lim = buf + bufsize;
415
	for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
416
		if (ifm->ifm_msglen == 0) {
417
			log_warnx("ifm_msglen is 0 (buf=%p lim=%p ifm=%p)",
418
			    buf, lim, ifm);
419
			return;
420
		}
421
		if (ifm->ifm_type == RTM_IFINFO) {
422
			if (ifm->ifm_version == RTM_VERSION)
423
				(*ifmlist_p)[ifm->ifm_index] = ifm;
424
		} else {
425
			fatalx("out of sync parsing NET_RT_IFLIST,"
426
			    " expected %d, got %d, msglen = %d,"
427
			    " buf:%p, ifm:%p, lim:%p",
428
			    RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
429
			    buf, ifm, lim);
430
		}
431
		for (ifam = (struct ifa_msghdr *)
432
			((char *)ifm + ifm->ifm_msglen);
433
		     ifam < (struct ifa_msghdr *)lim;
434
		     ifam = (struct ifa_msghdr *)
435
		     	((char *)ifam + ifam->ifam_msglen)) {
436
			/* just for safety */
437
			if (!ifam->ifam_msglen) {
438
				log_warnx("ifa_msglen is 0 "
439
				    "(buf=%p lim=%p ifam=%p)",
440
				    buf, lim, ifam);
441
				return;
442
			}
443
			if (ifam->ifam_type != RTM_NEWADDR)
444
				break;
445
		}
446
		ifm = (struct if_msghdr *)ifam;
447
	}
448
}
449
450
void
451
init_iflist(void)
452
{
453
	static size_t ifblock_size;
454
	static char *ifblock;
455
456
	if (ifblock) {
457
		free(ifblock);
458
		ifblock_size = 0;
459
	}
460
	free(iflist);
461
	/* get iflist block from kernel */
462
	get_iflist(&ifblock, &ifblock_size);
463
464
	/* make list of pointers to each if_msghdr */
465
	parse_iflist(&iflist, ifblock, ifblock_size);
466
}