GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/pfctl/pfctl_radix.c Lines: 97 316 30.7 %
Date: 2017-11-07 Branches: 51 223 22.9 %

Line Branch Exec Source
1
/*	$OpenBSD: pfctl_radix.c,v 1.34 2017/08/11 22:30:38 benno Exp $ */
2
3
/*
4
 * Copyright (c) 2002 Cedric Berger
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 *    - Redistributions of source code must retain the above copyright
12
 *      notice, this list of conditions and the following disclaimer.
13
 *    - Redistributions in binary form must reproduce the above
14
 *      copyright notice, this list of conditions and the following
15
 *      disclaimer in the documentation and/or other materials provided
16
 *      with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 *
31
 */
32
33
#include <sys/types.h>
34
#include <sys/ioctl.h>
35
#include <sys/socket.h>
36
37
#include <netinet/in.h>
38
#include <net/if.h>
39
#include <net/pfvar.h>
40
41
#include <errno.h>
42
#include <string.h>
43
#include <ctype.h>
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <limits.h>
47
#include <err.h>
48
49
#include "pfctl.h"
50
#include "pfctl_parser.h"
51
52
#define BUF_SIZE 256
53
54
extern int dev;
55
56
static int	 pfr_next_token(char buf[], FILE *);
57
58
59
int
60
pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
61
{
62
	struct pfioc_table io;
63
64
	bzero(&io, sizeof io);
65
	io.pfrio_flags = flags;
66
	if (filter != NULL)
67
		io.pfrio_table = *filter;
68
	if (ioctl(dev, DIOCRCLRTABLES, &io))
69
		return (-1);
70
	if (ndel != NULL)
71
		*ndel = io.pfrio_ndel;
72
	return (0);
73
}
74
75
int
76
pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
77
{
78
	struct pfioc_table io;
79
80
	if (size < 0 || (size && tbl == NULL)) {
81
		errno = EINVAL;
82
		return (-1);
83
	}
84
	bzero(&io, sizeof io);
85
	io.pfrio_flags = flags;
86
	io.pfrio_buffer = tbl;
87
	io.pfrio_esize = sizeof(*tbl);
88
	io.pfrio_size = size;
89
	if (ioctl(dev, DIOCRADDTABLES, &io))
90
		return (-1);
91
	if (nadd != NULL)
92
		*nadd = io.pfrio_nadd;
93
	return (0);
94
}
95
96
int
97
pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
98
{
99
	struct pfioc_table io;
100
101
	if (size < 0 || (size && tbl == NULL)) {
102
		errno = EINVAL;
103
		return (-1);
104
	}
105
	bzero(&io, sizeof io);
106
	io.pfrio_flags = flags;
107
	io.pfrio_buffer = tbl;
108
	io.pfrio_esize = sizeof(*tbl);
109
	io.pfrio_size = size;
110
	if (ioctl(dev, DIOCRDELTABLES, &io))
111
		return (-1);
112
	if (ndel != NULL)
113
		*ndel = io.pfrio_ndel;
114
	return (0);
115
}
116
117
int
118
pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
119
	int flags)
120
{
121
356
	struct pfioc_table io;
122
123

534
	if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
124
		errno = EINVAL;
125
		return (-1);
126
	}
127
178
	bzero(&io, sizeof io);
128
178
	io.pfrio_flags = flags;
129
178
	if (filter != NULL)
130
		io.pfrio_table = *filter;
131
178
	io.pfrio_buffer = tbl;
132
178
	io.pfrio_esize = sizeof(*tbl);
133
178
	io.pfrio_size = *size;
134
178
	if (ioctl(dev, DIOCRGETTABLES, &io))
135
		return (-1);
136
178
	*size = io.pfrio_size;
137
178
	return (0);
138
178
}
139
140
int
141
pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
142
	int flags)
143
{
144
	struct pfioc_table io;
145
146
	if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
147
		errno = EINVAL;
148
		return (-1);
149
	}
150
	bzero(&io, sizeof io);
151
	io.pfrio_flags = flags;
152
	if (filter != NULL)
153
		io.pfrio_table = *filter;
154
	io.pfrio_buffer = tbl;
155
	io.pfrio_esize = sizeof(*tbl);
156
	io.pfrio_size = *size;
157
	if (ioctl(dev, DIOCRGETTSTATS, &io))
158
		return (-1);
159
	*size = io.pfrio_size;
160
	return (0);
161
}
162
163
int
164
pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
165
{
166
	struct pfioc_table io;
167
168
	if (tbl == NULL) {
169
		errno = EINVAL;
170
		return (-1);
171
	}
172
	bzero(&io, sizeof io);
173
	io.pfrio_flags = flags;
174
	io.pfrio_table = *tbl;
175
	if (ioctl(dev, DIOCRCLRADDRS, &io))
176
		return (-1);
177
	if (ndel != NULL)
178
		*ndel = io.pfrio_ndel;
179
	return (0);
180
}
181
182
int
183
pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
184
    int *nadd, int flags)
185
{
186
	struct pfioc_table io;
187
188
	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
189
		errno = EINVAL;
190
		return (-1);
191
	}
192
	bzero(&io, sizeof io);
193
	io.pfrio_flags = flags;
194
	io.pfrio_table = *tbl;
195
	io.pfrio_buffer = addr;
196
	io.pfrio_esize = sizeof(*addr);
197
	io.pfrio_size = size;
198
	if (ioctl(dev, DIOCRADDADDRS, &io))
199
		return (-1);
200
	if (nadd != NULL)
201
		*nadd = io.pfrio_nadd;
202
	return (0);
203
}
204
205
int
206
pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
207
    int *ndel, int flags)
208
{
209
	struct pfioc_table io;
210
211
	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
212
		errno = EINVAL;
213
		return (-1);
214
	}
215
	bzero(&io, sizeof io);
216
	io.pfrio_flags = flags;
217
	io.pfrio_table = *tbl;
218
	io.pfrio_buffer = addr;
219
	io.pfrio_esize = sizeof(*addr);
220
	io.pfrio_size = size;
221
	if (ioctl(dev, DIOCRDELADDRS, &io))
222
		return (-1);
223
	if (ndel != NULL)
224
		*ndel = io.pfrio_ndel;
225
	return (0);
226
}
227
228
int
229
pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
230
    int *size2, int *nadd, int *ndel, int *nchange, int flags)
231
{
232
	struct pfioc_table io;
233
234
	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
235
		errno = EINVAL;
236
		return (-1);
237
	}
238
	bzero(&io, sizeof io);
239
	io.pfrio_flags = flags;
240
	io.pfrio_table = *tbl;
241
	io.pfrio_buffer = addr;
242
	io.pfrio_esize = sizeof(*addr);
243
	io.pfrio_size = size;
244
	io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
245
	if (ioctl(dev, DIOCRSETADDRS, &io))
246
		return (-1);
247
	if (nadd != NULL)
248
		*nadd = io.pfrio_nadd;
249
	if (ndel != NULL)
250
		*ndel = io.pfrio_ndel;
251
	if (nchange != NULL)
252
		*nchange = io.pfrio_nchange;
253
	if (size2 != NULL)
254
		*size2 = io.pfrio_size2;
255
	return (0);
256
}
257
258
int
259
pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
260
    int flags)
261
{
262
60
	struct pfioc_table io;
263
264

60
	if (tbl == NULL || size == NULL || *size < 0 ||
265
30
	    (*size && addr == NULL)) {
266
		errno = EINVAL;
267
		return (-1);
268
	}
269
30
	bzero(&io, sizeof io);
270
30
	io.pfrio_flags = flags;
271
30
	io.pfrio_table = *tbl;
272
30
	io.pfrio_buffer = addr;
273
30
	io.pfrio_esize = sizeof(*addr);
274
30
	io.pfrio_size = *size;
275
30
	if (ioctl(dev, DIOCRGETADDRS, &io))
276
		return (-1);
277
30
	*size = io.pfrio_size;
278
30
	return (0);
279
30
}
280
281
int
282
pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
283
    int flags)
284
{
285
	struct pfioc_table io;
286
287
	if (tbl == NULL || size == NULL || *size < 0 ||
288
	    (*size && addr == NULL)) {
289
		errno = EINVAL;
290
		return (-1);
291
	}
292
	bzero(&io, sizeof io);
293
	io.pfrio_flags = flags;
294
	io.pfrio_table = *tbl;
295
	io.pfrio_buffer = addr;
296
	io.pfrio_esize = sizeof(*addr);
297
	io.pfrio_size = *size;
298
	if (ioctl(dev, DIOCRGETASTATS, &io))
299
		return (-1);
300
	*size = io.pfrio_size;
301
	return (0);
302
}
303
304
int
305
pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
306
{
307
	struct pfioc_table io;
308
309
	if (size < 0 || (size && !tbl)) {
310
		errno = EINVAL;
311
		return (-1);
312
	}
313
	bzero(&io, sizeof io);
314
	io.pfrio_flags = flags;
315
	io.pfrio_buffer = tbl;
316
	io.pfrio_esize = sizeof(*tbl);
317
	io.pfrio_size = size;
318
	if (ioctl(dev, DIOCRCLRTSTATS, &io))
319
		return (-1);
320
	if (nzero)
321
		*nzero = io.pfrio_nzero;
322
	return (0);
323
}
324
325
int
326
pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
327
    int *nmatch, int flags)
328
{
329
	struct pfioc_table io;
330
331
	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
332
		errno = EINVAL;
333
		return (-1);
334
	}
335
	bzero(&io, sizeof io);
336
	io.pfrio_flags = flags;
337
	io.pfrio_table = *tbl;
338
	io.pfrio_buffer = addr;
339
	io.pfrio_esize = sizeof(*addr);
340
	io.pfrio_size = size;
341
	if (ioctl(dev, DIOCRTSTADDRS, &io))
342
		return (-1);
343
	if (nmatch)
344
		*nmatch = io.pfrio_nmatch;
345
	return (0);
346
}
347
348
int
349
pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
350
    int *nadd, int *naddr, int ticket, int flags)
351
{
352
60
	struct pfioc_table io;
353
354

60
	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
355
		errno = EINVAL;
356
		return (-1);
357
	}
358
30
	bzero(&io, sizeof io);
359
30
	io.pfrio_flags = flags;
360
30
	io.pfrio_table = *tbl;
361
30
	io.pfrio_buffer = addr;
362
30
	io.pfrio_esize = sizeof(*addr);
363
30
	io.pfrio_size = size;
364
30
	io.pfrio_ticket = ticket;
365
30
	if (ioctl(dev, DIOCRINADEFINE, &io))
366
		return (-1);
367
30
	if (nadd != NULL)
368
		*nadd = io.pfrio_nadd;
369
30
	if (naddr != NULL)
370
		*naddr = io.pfrio_naddr;
371
30
	return (0);
372
30
}
373
374
/* interface management code */
375
376
int
377
pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
378
{
379
	struct pfioc_iface io;
380
381
	if (size == NULL || *size < 0 || (*size && buf == NULL)) {
382
		errno = EINVAL;
383
		return (-1);
384
	}
385
	bzero(&io, sizeof io);
386
	if (filter != NULL)
387
		if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
388
		    sizeof(io.pfiio_name)) {
389
			errno = EINVAL;
390
			return (-1);
391
		}
392
	io.pfiio_buffer = buf;
393
	io.pfiio_esize = sizeof(*buf);
394
	io.pfiio_size = *size;
395
	if (ioctl(dev, DIOCIGETIFACES, &io))
396
		return (-1);
397
	*size = io.pfiio_size;
398
	return (0);
399
}
400
401
/* buffer management code */
402
403
size_t buf_esize[PFRB_MAX] = { 0,
404
	sizeof(struct pfr_table), sizeof(struct pfr_tstats),
405
	sizeof(struct pfr_addr), sizeof(struct pfr_astats),
406
	sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
407
};
408
409
/*
410
 * add one element to the buffer
411
 */
412
int
413
pfr_buf_add(struct pfr_buffer *b, const void *e)
414
{
415
	size_t bs;
416
417

4065
	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
418
813
	    e == NULL) {
419
		errno = EINVAL;
420
		return (-1);
421
	}
422
813
	bs = buf_esize[b->pfrb_type];
423
813
	if (b->pfrb_size == b->pfrb_msize)
424
436
		if (pfr_buf_grow(b, 0))
425
			return (-1);
426
813
	memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
427
813
	b->pfrb_size++;
428
813
	return (0);
429
813
}
430
431
/*
432
 * return next element of the buffer (or first one if prev is NULL)
433
 * see PFRB_FOREACH macro
434
 */
435
void *
436
pfr_buf_next(struct pfr_buffer *b, const void *prev)
437
{
438
	size_t bs;
439
440

12592
	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
441
		return (NULL);
442
3148
	if (b->pfrb_size == 0)
443
16
		return (NULL);
444
3132
	if (prev == NULL)
445
1898
		return (b->pfrb_caddr);
446
1234
	bs = buf_esize[b->pfrb_type];
447
1234
	if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
448
208
		return (NULL);
449
1026
	return (((caddr_t)prev) + bs);
450
3148
}
451
452
/*
453
 * minsize:
454
 *    0: make the buffer somewhat bigger
455
 *    n: make room for "n" entries in the buffer
456
 */
457
int
458
pfr_buf_grow(struct pfr_buffer *b, int minsize)
459
{
460
	caddr_t p;
461
	size_t bs;
462
463

2576
	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
464
		errno = EINVAL;
465
		return (-1);
466
	}
467

644
	if (minsize != 0 && minsize <= b->pfrb_msize)
468
		return (0);
469
644
	bs = buf_esize[b->pfrb_type];
470
1288
	if (!b->pfrb_msize) {
471
644
		if (minsize < 64)
472
644
			minsize = 64;
473
	}
474
644
	if (minsize == 0)
475
		minsize = b->pfrb_msize * 2;
476
644
	p = reallocarray(b->pfrb_caddr, minsize, bs);
477
644
	if (p == NULL)
478
		return (-1);
479
644
	bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
480
644
	b->pfrb_caddr = p;
481
644
	b->pfrb_msize = minsize;
482
644
	return (0);
483
644
}
484
485
/*
486
 * reset buffer and free memory.
487
 */
488
void
489
pfr_buf_clear(struct pfr_buffer *b)
490
{
491
606
	if (b == NULL)
492
		return;
493
303
	free(b->pfrb_caddr);
494
303
	b->pfrb_caddr = NULL;
495
303
	b->pfrb_size = b->pfrb_msize = 0;
496
606
}
497
498
int
499
pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, int opts)
500
{
501
	FILE	*fp;
502
24
	char	 buf[BUF_SIZE];
503
	int	 rv;
504
	int	 ev = 0;
505
506
12
	if (file == NULL)
507
		return (0);
508
12
	if (!strcmp(file, "-"))
509
		fp = stdin;
510
	else {
511
12
		fp = pfctl_fopen(file, "r");
512
12
		if (fp == NULL)
513
1
			return (-1);
514
	}
515
11
	while ((rv = pfr_next_token(buf, fp)) == 1)
516
		if ((ev = append_addr(b, buf, nonetwork, opts)) == -1) {
517
			rv = -1;
518
			break;
519
		}
520
11
	if (ev == 1) /* expected further append_addr call */
521
		rv = -1;
522
11
	if (fp != stdin)
523
11
		fclose(fp);
524
11
	return (rv);
525
12
}
526
527
int
528
pfr_next_token(char buf[BUF_SIZE], FILE *fp)
529
{
530
	static char	next_ch = ' ';
531
	int		i = 0;
532
533
22
	for (;;) {
534
		/* skip spaces */
535

77
		while (isspace((unsigned char)next_ch) && !feof(fp))
536
11
			next_ch = fgetc(fp);
537
		/* remove from '#' until end of line */
538
11
		if (next_ch == '#')
539
			while (!feof(fp)) {
540
				next_ch = fgetc(fp);
541
				if (next_ch == '\n')
542
					break;
543
			}
544
		else
545
			break;
546
	}
547

22
	if (feof(fp)) {
548
11
		next_ch = ' ';
549
11
		return (0);
550
	}
551
	do {
552
		if (i < BUF_SIZE)
553
			buf[i++] = next_ch;
554
		next_ch = fgetc(fp);
555
	} while (!feof(fp) && !isspace((unsigned char)next_ch));
556
	if (i >= BUF_SIZE) {
557
		errno = EINVAL;
558
		return (-1);
559
	}
560
	buf[i] = '\0';
561
	return (1);
562
11
}
563
564
char *
565
pfr_strerror(int errnum)
566
{
567
	switch (errnum) {
568
	case ESRCH:
569
		return "Table does not exist";
570
	case ENOENT:
571
		return "Anchor or Ruleset does not exist";
572
	default:
573
		return strerror(errnum);
574
	}
575
}