GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/kroute.c Lines: 0 162 0.0 %
Date: 2017-11-07 Branches: 0 276 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: kroute.c,v 1.14 2017/07/24 11:00:01 friehm Exp $ */
2
3
/*
4
 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
5
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/socket.h>
22
#include <sys/sysctl.h>
23
#include <sys/tree.h>
24
#include <netinet/in.h>
25
#include <arpa/inet.h>
26
#include <net/if.h>
27
#include <net/if_dl.h>
28
#include <net/if_types.h>
29
#include <net/route.h>
30
#include <err.h>
31
#include <errno.h>
32
#include <fcntl.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <unistd.h>
37
38
#include "dvmrp.h"
39
#include "dvmrpd.h"
40
#include "log.h"
41
42
struct {
43
	u_int32_t		rtseq;
44
	pid_t			pid;
45
	struct event		ev;
46
} kr_state;
47
48
struct kif_node {
49
	RB_ENTRY(kif_node)	 entry;
50
	struct kif		 k;
51
};
52
53
int	kif_compare(struct kif_node *, struct kif_node *);
54
55
struct kif_node		*kif_find(int);
56
int			 kif_insert(struct kif_node *);
57
int			 kif_remove(struct kif_node *);
58
void			 kif_clear(void);
59
60
in_addr_t	prefixlen2mask(u_int8_t);
61
void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
62
void		if_change(u_short, int, struct if_data *);
63
void		if_announce(void *);
64
65
int		fetchifs(int);
66
67
RB_HEAD(kif_tree, kif_node)		kit;
68
RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
69
RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
70
71
int
72
kif_init(void)
73
{
74
	RB_INIT(&kit);
75
76
	if (fetchifs(0) == -1)
77
		return (-1);
78
79
	return (0);
80
}
81
82
int
83
kr_init(void)
84
{
85
	int opt, fd;
86
87
	if ((fd = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
88
	    0)) == -1) {
89
		log_warn("kr_init: socket");
90
		return (-1);
91
	}
92
93
	/* not interested in my own messages */
94
	if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK, &opt, sizeof(opt)) == -1)
95
		log_warn("kr_init: setsockopt");	/* not fatal */
96
97
	kr_state.pid = getpid();
98
	kr_state.rtseq = 1;
99
100
	event_set(&kr_state.ev, fd, EV_READ | EV_PERSIST,
101
	    kr_dispatch_msg, NULL);
102
	event_add(&kr_state.ev, NULL);
103
104
	return (0);
105
}
106
107
void
108
kr_shutdown(void)
109
{
110
	kif_clear();
111
	close(EVENT_FD((&kr_state.ev)));
112
}
113
114
void
115
kr_ifinfo(char *ifname)
116
{
117
	struct kif_node	*kif;
118
119
	RB_FOREACH(kif, kif_tree, &kit)
120
		if (!strcmp(ifname, kif->k.ifname)) {
121
			main_imsg_compose_dvmrpe(IMSG_CTL_IFINFO, 0,
122
			    &kif->k, sizeof(kif->k));
123
			return;
124
		}
125
}
126
127
/* rb-tree compare */
128
int
129
kif_compare(struct kif_node *a, struct kif_node *b)
130
{
131
	return (b->k.ifindex - a->k.ifindex);
132
}
133
134
struct kif_node *
135
kif_find(int ifindex)
136
{
137
	struct kif_node	s;
138
139
	memset(&s, 0, sizeof(s));
140
	s.k.ifindex = ifindex;
141
142
	return (RB_FIND(kif_tree, &kit, &s));
143
}
144
145
struct kif *
146
kif_findname(char *ifname)
147
{
148
	struct kif_node	*kif;
149
150
	RB_FOREACH(kif, kif_tree, &kit)
151
		if (!strcmp(ifname, kif->k.ifname))
152
			return (&kif->k);
153
154
	return (NULL);
155
}
156
157
int
158
kif_insert(struct kif_node *kif)
159
{
160
	if (RB_INSERT(kif_tree, &kit, kif) != NULL) {
161
		log_warnx("RB_INSERT(kif_tree, &kit, kif)");
162
		free(kif);
163
		return (-1);
164
	}
165
166
	return (0);
167
}
168
169
int
170
kif_remove(struct kif_node *kif)
171
{
172
	if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
173
		log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
174
		return (-1);
175
	}
176
177
	free(kif);
178
	return (0);
179
}
180
181
void
182
kif_clear(void)
183
{
184
	struct kif_node	*kif;
185
186
	while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
187
		kif_remove(kif);
188
}
189
190
/* misc */
191
u_int8_t
192
prefixlen_classful(in_addr_t ina)
193
{
194
	/* it hurt to write this. */
195
196
	if (ina >= 0xf0000000U)		/* class E */
197
		return (32);
198
	else if (ina >= 0xe0000000U)	/* class D */
199
		return (4);
200
	else if (ina >= 0xc0000000U)	/* class C */
201
		return (24);
202
	else if (ina >= 0x80000000U)	/* class B */
203
		return (16);
204
	else				/* class A */
205
		return (8);
206
}
207
208
u_int8_t
209
mask2prefixlen(in_addr_t ina)
210
{
211
	if (ina == 0)
212
		return (0);
213
	else
214
		return (33 - ffs(ntohl(ina)));
215
}
216
217
in_addr_t
218
prefixlen2mask(u_int8_t prefixlen)
219
{
220
	if (prefixlen == 0)
221
		return (0);
222
223
	return (0xffffffff << (32 - prefixlen));
224
}
225
226
void
227
if_change(u_short ifindex, int flags, struct if_data *ifd)
228
{
229
	struct kif_node		*kif;
230
	u_int8_t		 reachable;
231
232
	if ((kif = kif_find(ifindex)) == NULL) {
233
		log_warnx("interface with index %u not found",
234
		    ifindex);
235
		return;
236
	}
237
238
	kif->k.flags = flags;
239
	kif->k.link_state = ifd->ifi_link_state;
240
	kif->k.if_type = ifd->ifi_type;
241
	kif->k.baudrate = ifd->ifi_baudrate;
242
243
	if ((reachable = (flags & IFF_UP) &&
244
	    LINK_STATE_IS_UP(ifd->ifi_link_state)) == kif->k.nh_reachable)
245
		return;		/* nothing changed wrt nexthop validity */
246
247
	kif->k.nh_reachable = reachable;
248
	main_imsg_compose_dvmrpe(IMSG_IFINFO, 0, &kif->k, sizeof(kif->k));
249
}
250
251
void
252
if_announce(void *msg)
253
{
254
	struct if_announcemsghdr	*ifan;
255
	struct kif_node			*kif;
256
257
	ifan = msg;
258
259
	switch (ifan->ifan_what) {
260
	case IFAN_ARRIVAL:
261
		if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) {
262
			log_warn("if_announce");
263
			return;
264
		}
265
266
		kif->k.ifindex = ifan->ifan_index;
267
		strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname));
268
		kif_insert(kif);
269
		break;
270
	case IFAN_DEPARTURE:
271
		kif = kif_find(ifan->ifan_index);
272
		kif_remove(kif);
273
		break;
274
	}
275
}
276
277
/* rtsock */
278
#define ROUNDUP(a) \
279
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
280
281
void
282
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
283
{
284
	int	i;
285
286
	for (i = 0; i < RTAX_MAX; i++) {
287
		if (addrs & (1 << i)) {
288
			rti_info[i] = sa;
289
			sa = (struct sockaddr *)((char *)(sa) +
290
			    ROUNDUP(sa->sa_len));
291
		} else
292
			rti_info[i] = NULL;
293
	}
294
}
295
296
int
297
fetchifs(int ifindex)
298
{
299
	size_t			 len;
300
	int			 mib[6];
301
	char			*buf, *next, *lim;
302
	struct if_msghdr	 ifm;
303
	struct kif_node		*kif;
304
	struct sockaddr		*sa, *rti_info[RTAX_MAX];
305
	struct sockaddr_dl	*sdl;
306
307
	mib[0] = CTL_NET;
308
	mib[1] = PF_ROUTE;
309
	mib[2] = 0;
310
	mib[3] = AF_INET;
311
	mib[4] = NET_RT_IFLIST;
312
	mib[5] = ifindex;
313
314
	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
315
		log_warn("sysctl");
316
		return (-1);
317
	}
318
	if ((buf = malloc(len)) == NULL) {
319
		log_warn("fetchif");
320
		return (-1);
321
	}
322
	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
323
		log_warn("sysctl");
324
		free(buf);
325
		return (-1);
326
	}
327
328
	lim = buf + len;
329
	for (next = buf; next < lim; next += ifm.ifm_msglen) {
330
		memcpy(&ifm, next, sizeof(ifm));
331
		sa = (struct sockaddr *)(next + sizeof(ifm));
332
		get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
333
334
		if (ifm.ifm_version != RTM_VERSION)
335
			continue;
336
		if (ifm.ifm_type != RTM_IFINFO)
337
			continue;
338
339
		if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) {
340
			log_warn("fetchifs");
341
			free(buf);
342
			return (-1);
343
		}
344
345
		kif->k.ifindex = ifm.ifm_index;
346
		kif->k.flags = ifm.ifm_flags;
347
		kif->k.link_state = ifm.ifm_data.ifi_link_state;
348
		kif->k.if_type = ifm.ifm_data.ifi_type;
349
		kif->k.baudrate = ifm.ifm_data.ifi_baudrate;
350
		kif->k.mtu = ifm.ifm_data.ifi_mtu;
351
		kif->k.nh_reachable = (kif->k.flags & IFF_UP) &&
352
		    LINK_STATE_IS_UP(ifm.ifm_data.ifi_link_state);
353
		if ((sa = rti_info[RTAX_IFP]) != NULL)
354
			if (sa->sa_family == AF_LINK) {
355
				sdl = (struct sockaddr_dl *)sa;
356
				if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
357
					memcpy(kif->k.ifname, sdl->sdl_data,
358
					    sizeof(kif->k.ifname) - 1);
359
				else if (sdl->sdl_nlen > 0)
360
					memcpy(kif->k.ifname, sdl->sdl_data,
361
					    sdl->sdl_nlen);
362
				/* string already terminated via calloc() */
363
			}
364
365
		kif_insert(kif);
366
	}
367
	free(buf);
368
	return (0);
369
}
370
371
void
372
kr_dispatch_msg(int fd, short event, void *bula)
373
{
374
	char			 buf[RT_BUF_SIZE];
375
	ssize_t			 n;
376
	char			*next, *lim;
377
	struct rt_msghdr	*rtm;
378
	struct if_msghdr	 ifm;
379
380
	if ((n = read(fd, &buf, sizeof(buf))) == -1) {
381
		if (errno == EAGAIN || errno == EINTR)
382
			return;
383
		fatal("dispatch_rtmsg: read error");
384
	}
385
386
	if (n == 0)
387
		fatalx("routing socket closed");
388
389
	lim = buf + n;
390
	for (next = buf; next < lim; next += rtm->rtm_msglen) {
391
		rtm = (struct rt_msghdr *)next;
392
		if (lim < next + sizeof(u_short) ||
393
		    lim < next + rtm->rtm_msglen)
394
			fatalx("dispatch_rtmsg: partial rtm in buffer");
395
		if (rtm->rtm_version != RTM_VERSION)
396
			continue;
397
398
		switch (rtm->rtm_type) {
399
		case RTM_IFINFO:
400
			memcpy(&ifm, next, sizeof(ifm));
401
			if_change(ifm.ifm_index, ifm.ifm_flags,
402
			    &ifm.ifm_data);
403
			break;
404
		case RTM_IFANNOUNCE:
405
			if_announce(next);
406
			break;
407
		default:
408
			/* ignore for now */
409
			break;
410
		}
411
	}
412
}