GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/snmpd/pf.c Lines: 2 222 0.9 %
Date: 2017-11-07 Branches: 1 150 0.7 %

Line Branch Exec Source
1
/*	$OpenBSD: pf.c,v 1.10 2015/02/06 23:21:59 millert Exp $	*/
2
3
/*
4
 * Copyright (c) 2012 Joel Knight <joel@openbsd.org>
5
 * Copyright (c) 2002 Cedric Berger
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
 *
12
 *    - Redistributions of source code must retain the above copyright
13
 *      notice, this list of conditions and the following disclaimer.
14
 *    - Redistributions in binary form must reproduce the above
15
 *      copyright notice, this list of conditions and the following
16
 *      disclaimer in the documentation and/or other materials provided
17
 *      with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
 * POSSIBILITY OF SUCH DAMAGE.
31
 *
32
 */
33
34
#include <sys/types.h>
35
#include <sys/socket.h>
36
#include <sys/ioctl.h>
37
38
#include <netinet/in.h>
39
#include <arpa/inet.h>
40
#include <net/if.h>
41
#include <net/pfvar.h>
42
43
#include <err.h>
44
#include <errno.h>
45
#include <fcntl.h>
46
#include <stdint.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <unistd.h>
51
#include <event.h>
52
53
#include "snmpd.h"
54
55
int	 devpf = 0;
56
57
size_t 	 buf_esize[PFRB_MAX] = { 0,
58
	sizeof(struct pfr_table), sizeof(struct pfr_tstats),
59
	sizeof(struct pfr_addr), sizeof(struct pfr_astats),
60
	sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
61
};
62
63
void
64
pf_init(void)
65
{
66
32
	if ((devpf = open("/dev/pf", O_RDONLY)) == -1)
67
		fatal("pf_init");
68
16
}
69
70
int
71
pf_get_stats(struct pf_status *s)
72
{
73
	extern int	 devpf;
74
75
	memset(s, 0, sizeof(*s));
76
	if (ioctl(devpf, DIOCGETSTATUS, s)) {
77
		log_warn("DIOCGETSTATUS");
78
		return (-1);
79
	}
80
81
	return (0);
82
}
83
84
int
85
pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
86
		int flags)
87
{
88
	struct pfioc_table	 io;
89
	extern int		 devpf;
90
91
	if (tbl == NULL || size == NULL || *size < 0 ||
92
	    (*size && addr == NULL))
93
		return (-1);
94
95
	bzero(&io, sizeof io);
96
	io.pfrio_flags = flags;
97
	io.pfrio_table = *tbl;
98
	io.pfrio_buffer = addr;
99
	io.pfrio_esize = sizeof(*addr);
100
	io.pfrio_size = *size;
101
	if (ioctl(devpf, DIOCRGETASTATS, &io))
102
		return (-1);
103
	*size = io.pfrio_size;
104
	return (0);
105
}
106
107
int
108
pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
109
	int flags)
110
{
111
	struct pfioc_table	 io;
112
	extern int		 devpf;
113
114
	if (size == NULL || *size < 0 || (*size && tbl == NULL))
115
		return (-1);
116
	bzero(&io, sizeof io);
117
	io.pfrio_flags = flags;
118
	if (filter != NULL)
119
		io.pfrio_table = *filter;
120
	io.pfrio_buffer = tbl;
121
	io.pfrio_esize = sizeof(*tbl);
122
	io.pfrio_size = *size;
123
	if (ioctl(devpf, DIOCRGETTSTATS, &io))
124
		return (-1);
125
	*size = io.pfrio_size;
126
	return (0);
127
}
128
129
int
130
pfr_buf_grow(struct pfr_buffer *b, int minsize)
131
{
132
	caddr_t	 p;
133
	size_t 	 bs;
134
135
	if (minsize != 0 && minsize <= b->pfrb_msize)
136
		return (0);
137
	bs = buf_esize[b->pfrb_type];
138
	if (!b->pfrb_msize) {
139
		if (minsize < 64)
140
			minsize = 64;
141
		b->pfrb_caddr = calloc(bs, minsize);
142
		if (b->pfrb_caddr == NULL)
143
			return (-1);
144
		b->pfrb_msize = minsize;
145
	} else {
146
		if (minsize == 0)
147
			minsize = b->pfrb_msize * 2;
148
		if (minsize < 0 || (size_t)minsize >= SIZE_MAX / bs) {
149
			/* msize overflow */
150
			return (-1);
151
		}
152
		p = reallocarray(b->pfrb_caddr, minsize, bs);
153
		if (p == NULL)
154
			return (-1);
155
		bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
156
		b->pfrb_caddr = p;
157
		b->pfrb_msize = minsize;
158
	}
159
	return (0);
160
}
161
162
const void *
163
pfr_buf_next(struct pfr_buffer *b, const void *prev)
164
{
165
	size_t	 bs;
166
167
	if (b == NULL)
168
		return (NULL);
169
	if (b->pfrb_size == 0)
170
		return (NULL);
171
	if (prev == NULL)
172
		return (b->pfrb_caddr);
173
	bs = buf_esize[b->pfrb_type];
174
	if ((((const char *)prev)-((char *)b->pfrb_caddr)) / bs >=
175
	    (size_t)b->pfrb_size-1)
176
		return (NULL);
177
178
	return (((const char *)prev) + bs);
179
}
180
181
int
182
pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
183
{
184
	struct pfioc_iface	 io;
185
	extern int		 devpf;
186
187
	if (size == NULL || *size < 0 || (*size && buf == NULL)) {
188
		errno = EINVAL;
189
		return (-1);
190
	}
191
	bzero(&io, sizeof io);
192
	if (filter != NULL)
193
		if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
194
		    sizeof(io.pfiio_name)) {
195
			errno = EINVAL;
196
			return (-1);
197
		}
198
	io.pfiio_buffer = buf;
199
	io.pfiio_esize = sizeof(*buf);
200
	io.pfiio_size = *size;
201
	if (ioctl(devpf, DIOCIGETIFACES, &io))
202
		return (-1);
203
	*size = io.pfiio_size;
204
	return (0);
205
}
206
207
int
208
pfi_get(struct pfr_buffer *b, const char *filter)
209
{
210
	bzero(b, sizeof(struct pfr_buffer));
211
	b->pfrb_type = PFRB_IFACES;
212
	for (;;) {
213
		pfr_buf_grow(b, b->pfrb_size);
214
		b->pfrb_size = b->pfrb_msize;
215
		if (pfi_get_ifaces(filter, b->pfrb_caddr, &(b->pfrb_size)))
216
			return (1);
217
		if (b->pfrb_size <= b->pfrb_msize)
218
			break;
219
	}
220
221
	return (0);
222
}
223
224
int
225
pfi_count(void)
226
{
227
	struct pfr_buffer 	 b;
228
	const struct pfi_kif 	*p;
229
	int			 c = 0;
230
231
	if (pfi_get(&b, NULL)) {
232
		free(b.pfrb_caddr);
233
		return (-1);
234
	}
235
236
	PFRB_FOREACH(p, &b)
237
		c++;
238
239
	free(b.pfrb_caddr);
240
	return (c);
241
}
242
243
int
244
pfi_get_if(struct pfi_kif *rp, int idx)
245
{
246
	struct pfr_buffer	 b;
247
	const struct pfi_kif	*p;
248
	int			 i = 1;
249
250
	if (pfi_get(&b, NULL)) {
251
		free(b.pfrb_caddr);
252
		return (-1);
253
	}
254
255
	PFRB_FOREACH(p, &b) {
256
		if (i == idx)
257
			break;
258
		i++;
259
	}
260
261
	if (p == NULL) {
262
		free(b.pfrb_caddr);
263
		return (-1);
264
	}
265
266
	bcopy(p, rp, sizeof(struct pfi_kif));
267
	free(b.pfrb_caddr);
268
269
	return (0);
270
}
271
272
int
273
pft_get(struct pfr_buffer *b, struct pfr_table *filter)
274
{
275
	bzero(b, sizeof(struct pfr_buffer));
276
	b->pfrb_type = PFRB_TSTATS;
277
278
	for (;;) {
279
		pfr_buf_grow(b, b->pfrb_size);
280
		b->pfrb_size = b->pfrb_msize;
281
		if (pfr_get_tstats(filter, b->pfrb_caddr, &(b->pfrb_size), 0))
282
			return (1);
283
		if (b->pfrb_size <= b->pfrb_msize)
284
			break;
285
	}
286
287
	return (0);
288
}
289
290
int
291
pft_get_table(struct pfr_tstats *rts, int idx)
292
{
293
	struct pfr_buffer	 b;
294
	const struct pfr_tstats	*ts;
295
	int			 i = 1;
296
297
	if (pft_get(&b, NULL)) {
298
		free(b.pfrb_caddr);
299
		return (-1);
300
	}
301
302
	PFRB_FOREACH(ts, &b) {
303
		if (!(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
304
			continue;
305
		if (i == idx)
306
			break;
307
		i++;
308
	}
309
310
	if (ts == NULL) {
311
		free(b.pfrb_caddr);
312
		return (-1);
313
	}
314
315
	bcopy(ts, rts, sizeof(struct pfr_tstats));
316
	free(b.pfrb_caddr);
317
318
	return (0);
319
}
320
321
int
322
pft_count(void)
323
{
324
	struct pfr_buffer	 b;
325
	const struct pfr_tstats	*ts;
326
	int			 c = 0;
327
328
	if (pft_get(&b, NULL)) {
329
		free(b.pfrb_caddr);
330
		return (-1);
331
	}
332
333
	PFRB_FOREACH(ts, &b) {
334
		if (!(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
335
			continue;
336
		c++;
337
	}
338
339
	free(b.pfrb_caddr);
340
	return (c);
341
}
342
343
int
344
pfta_get(struct pfr_buffer *b, struct pfr_table *filter)
345
{
346
	bzero(b, sizeof(struct pfr_buffer));
347
	b->pfrb_type = PFRB_ASTATS;
348
349
	for (;;) {
350
		pfr_buf_grow(b, b->pfrb_size);
351
		b->pfrb_size = b->pfrb_msize;
352
		if (pfr_get_astats(filter, b->pfrb_caddr, &(b->pfrb_size), 0)) {
353
			return (1);
354
		}
355
		if (b->pfrb_size <= b->pfrb_msize)
356
			break;
357
	}
358
359
	return (0);
360
}
361
362
int
363
pfta_get_addr(struct pfr_astats *ras, int tblidx)
364
{
365
	struct pfr_buffer	 ba;
366
	struct pfr_tstats	 ts;
367
	struct pfr_table	 filter;
368
	const struct pfr_astats	*as;
369
370
	if (pft_get_table(&ts, tblidx))
371
		return (-1);
372
373
	bzero(&filter, sizeof(filter));
374
	if (strlcpy(filter.pfrt_name, ts.pfrts_name,
375
	    sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name)) {
376
		return (-1);
377
	}
378
379
	if (pfta_get(&ba, &filter) || ba.pfrb_size == 0) {
380
		free(ba.pfrb_caddr);
381
		return (-1);
382
	}
383
384
	PFRB_FOREACH(as, &ba) {
385
		if (as->pfras_a.pfra_af != AF_INET)
386
			continue;
387
		if ((memcmp(&as->pfras_a.pfra_ip4addr, &ras->pfras_a.pfra_ip4addr,
388
		    sizeof(as->pfras_a.pfra_ip4addr)) == 0)
389
		    && (as->pfras_a.pfra_net == ras->pfras_a.pfra_net))
390
			break;
391
	}
392
393
	if (as == NULL) {
394
		free(ba.pfrb_caddr);
395
		return (-1);
396
	}
397
398
	bcopy(as, ras, sizeof(struct pfr_astats));
399
	free(ba.pfrb_caddr);
400
401
	return (0);
402
}
403
404
int
405
pfta_get_nextaddr(struct pfr_astats *ras, int *tblidx)
406
{
407
	struct pfr_buffer	 ba;
408
	struct pfr_tstats	 ts;
409
	struct pfr_table	 filter;
410
	const struct pfr_astats	*as;
411
	int			 i, found = 0;
412
413
	ba.pfrb_caddr = NULL;
414
415
	for (i = *tblidx; !pft_get_table(&ts, i); i++) {
416
		bzero(&filter, sizeof(filter));
417
		if (strlcpy(filter.pfrt_name, ts.pfrts_name,
418
		    sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name))
419
			goto fail;
420
421
		if (pfta_get(&ba, &filter) || ba.pfrb_size == 0)
422
			goto fail;
423
424
		PFRB_FOREACH(as, &ba) {
425
			if (found)
426
				goto found;
427
			if (as->pfras_a.pfra_af != AF_INET)
428
				continue;
429
			if ((memcmp(&as->pfras_a.pfra_ip4addr,
430
			    &ras->pfras_a.pfra_ip4addr,
431
			    sizeof(as->pfras_a.pfra_ip4addr)) == 0)
432
			    && (as->pfras_a.pfra_net == ras->pfras_a.pfra_net))
433
				found = 1;
434
		}
435
436
		free(ba.pfrb_caddr);
437
		ba.pfrb_caddr = NULL;
438
	}
439
440
441
 fail:
442
	free(ba.pfrb_caddr);
443
444
	return (-1);
445
446
 found:
447
	bcopy(as, ras, sizeof(struct pfr_astats));
448
	*tblidx = i;
449
450
	free(ba.pfrb_caddr);
451
452
	return (0);
453
}
454
455
int
456
pfta_get_first(struct pfr_astats *ras)
457
{
458
	struct pfr_buffer	 ba;
459
	struct pfr_tstats	 ts;
460
	struct pfr_table	 filter;
461
	const struct pfr_astats	*as;
462
463
	if (pft_get_table(&ts, 1))
464
		return (-1);
465
466
	bzero(&filter, sizeof(filter));
467
	if (strlcpy(filter.pfrt_name, ts.pfrts_name,
468
	    sizeof(filter.pfrt_name)) >= sizeof(filter.pfrt_name)) {
469
		return (-1);
470
	}
471
472
	if (pfta_get(&ba, &filter) || ba.pfrb_size == 0) {
473
		free(ba.pfrb_caddr);
474
		return (-1);
475
	}
476
477
	/* take the first AF_INET addr */
478
	PFRB_FOREACH(as, &ba) {
479
		if (as->pfras_a.pfra_af != AF_INET)
480
			continue;
481
		break;
482
	}
483
484
	if (as == NULL) {
485
		free(ba.pfrb_caddr);
486
		return (-1);
487
	}
488
489
	bcopy(as, ras, sizeof(struct pfr_astats));
490
	free(ba.pfrb_caddr);
491
492
	return (0);
493
}
494