1/*	$OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning 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/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include <sys/types.h>
37#include <sys/ioctl.h>
38#include <sys/socket.h>
39
40#include <net/if.h>
41#include <net/pfvar.h>
42
43#include <errno.h>
44#include <string.h>
45#include <ctype.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <limits.h>
49#include <err.h>
50
51#include "pfctl.h"
52
53#define BUF_SIZE 256
54
55extern int dev;
56
57static int	 pfr_next_token(char buf[], FILE *);
58
59
60int
61pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
62{
63	struct pfioc_table io;
64
65	bzero(&io, sizeof io);
66	io.pfrio_flags = flags;
67	if (filter != NULL)
68		io.pfrio_table = *filter;
69	if (ioctl(dev, DIOCRCLRTABLES, &io))
70		return (-1);
71	if (ndel != NULL)
72		*ndel = io.pfrio_ndel;
73	return (0);
74}
75
76int
77pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
78{
79	struct pfioc_table io;
80
81	if (size < 0 || (size && tbl == NULL)) {
82		errno = EINVAL;
83		return (-1);
84	}
85	bzero(&io, sizeof io);
86	io.pfrio_flags = flags;
87	io.pfrio_buffer = tbl;
88	io.pfrio_esize = sizeof(*tbl);
89	io.pfrio_size = size;
90	if (ioctl(dev, DIOCRADDTABLES, &io))
91		return (-1);
92	if (nadd != NULL)
93		*nadd = io.pfrio_nadd;
94	return (0);
95}
96
97int
98pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
99{
100	struct pfioc_table io;
101
102	if (size < 0 || (size && tbl == NULL)) {
103		errno = EINVAL;
104		return (-1);
105	}
106	bzero(&io, sizeof io);
107	io.pfrio_flags = flags;
108	io.pfrio_buffer = tbl;
109	io.pfrio_esize = sizeof(*tbl);
110	io.pfrio_size = size;
111	if (ioctl(dev, DIOCRDELTABLES, &io))
112		return (-1);
113	if (ndel != NULL)
114		*ndel = io.pfrio_ndel;
115	return (0);
116}
117
118int
119pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
120	int flags)
121{
122	struct pfioc_table io;
123
124	if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
125		errno = EINVAL;
126		return (-1);
127	}
128	bzero(&io, sizeof io);
129	io.pfrio_flags = flags;
130	if (filter != NULL)
131		io.pfrio_table = *filter;
132	io.pfrio_buffer = tbl;
133	io.pfrio_esize = sizeof(*tbl);
134	io.pfrio_size = *size;
135	if (ioctl(dev, DIOCRGETTABLES, &io))
136		return (-1);
137	*size = io.pfrio_size;
138	return (0);
139}
140
141int
142pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
143	int flags)
144{
145	struct pfioc_table io;
146
147	if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
148		errno = EINVAL;
149		return (-1);
150	}
151	bzero(&io, sizeof io);
152	io.pfrio_flags = flags;
153	if (filter != NULL)
154		io.pfrio_table = *filter;
155	io.pfrio_buffer = tbl;
156	io.pfrio_esize = sizeof(*tbl);
157	io.pfrio_size = *size;
158	if (ioctl(dev, DIOCRGETTSTATS, &io))
159		return (-1);
160	*size = io.pfrio_size;
161	return (0);
162}
163
164int
165pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
166{
167	struct pfioc_table io;
168
169	if (tbl == NULL) {
170		errno = EINVAL;
171		return (-1);
172	}
173	bzero(&io, sizeof io);
174	io.pfrio_flags = flags;
175	io.pfrio_table = *tbl;
176	if (ioctl(dev, DIOCRCLRADDRS, &io))
177		return (-1);
178	if (ndel != NULL)
179		*ndel = io.pfrio_ndel;
180	return (0);
181}
182
183int
184pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
185    int *nadd, int flags)
186{
187	struct pfioc_table io;
188
189	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
190		errno = EINVAL;
191		return (-1);
192	}
193	bzero(&io, sizeof io);
194	io.pfrio_flags = flags;
195	io.pfrio_table = *tbl;
196	io.pfrio_buffer = addr;
197	io.pfrio_esize = sizeof(*addr);
198	io.pfrio_size = size;
199	if (ioctl(dev, DIOCRADDADDRS, &io))
200		return (-1);
201	if (nadd != NULL)
202		*nadd = io.pfrio_nadd;
203	return (0);
204}
205
206int
207pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
208    int *ndel, int flags)
209{
210	struct pfioc_table io;
211
212	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
213		errno = EINVAL;
214		return (-1);
215	}
216	bzero(&io, sizeof io);
217	io.pfrio_flags = flags;
218	io.pfrio_table = *tbl;
219	io.pfrio_buffer = addr;
220	io.pfrio_esize = sizeof(*addr);
221	io.pfrio_size = size;
222	if (ioctl(dev, DIOCRDELADDRS, &io))
223		return (-1);
224	if (ndel != NULL)
225		*ndel = io.pfrio_ndel;
226	return (0);
227}
228
229int
230pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
231    int *size2, int *nadd, int *ndel, int *nchange, int flags)
232{
233	struct pfioc_table io;
234
235	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
236		errno = EINVAL;
237		return (-1);
238	}
239	bzero(&io, sizeof io);
240	io.pfrio_flags = flags;
241	io.pfrio_table = *tbl;
242	io.pfrio_buffer = addr;
243	io.pfrio_esize = sizeof(*addr);
244	io.pfrio_size = size;
245	io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
246	if (ioctl(dev, DIOCRSETADDRS, &io))
247		return (-1);
248	if (nadd != NULL)
249		*nadd = io.pfrio_nadd;
250	if (ndel != NULL)
251		*ndel = io.pfrio_ndel;
252	if (nchange != NULL)
253		*nchange = io.pfrio_nchange;
254	if (size2 != NULL)
255		*size2 = io.pfrio_size2;
256	return (0);
257}
258
259int
260pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
261    int flags)
262{
263	struct pfioc_table io;
264
265	if (tbl == NULL || size == NULL || *size < 0 ||
266	    (*size && addr == NULL)) {
267		errno = EINVAL;
268		return (-1);
269	}
270	bzero(&io, sizeof io);
271	io.pfrio_flags = flags;
272	io.pfrio_table = *tbl;
273	io.pfrio_buffer = addr;
274	io.pfrio_esize = sizeof(*addr);
275	io.pfrio_size = *size;
276	if (ioctl(dev, DIOCRGETADDRS, &io))
277		return (-1);
278	*size = io.pfrio_size;
279	return (0);
280}
281
282int
283pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
284    int flags)
285{
286	struct pfioc_table io;
287
288	if (tbl == NULL || size == NULL || *size < 0 ||
289	    (*size && addr == NULL)) {
290		errno = EINVAL;
291		return (-1);
292	}
293	bzero(&io, sizeof io);
294	io.pfrio_flags = flags;
295	io.pfrio_table = *tbl;
296	io.pfrio_buffer = addr;
297	io.pfrio_esize = sizeof(*addr);
298	io.pfrio_size = *size;
299	if (ioctl(dev, DIOCRGETASTATS, &io))
300		return (-1);
301	*size = io.pfrio_size;
302	return (0);
303}
304
305int
306pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
307{
308	struct pfioc_table io;
309
310	if (size < 0 || (size && !tbl)) {
311		errno = EINVAL;
312		return (-1);
313	}
314	bzero(&io, sizeof io);
315	io.pfrio_flags = flags;
316	io.pfrio_buffer = tbl;
317	io.pfrio_esize = sizeof(*tbl);
318	io.pfrio_size = size;
319	if (ioctl(dev, DIOCRCLRTSTATS, &io))
320		return (-1);
321	if (nzero)
322		*nzero = io.pfrio_nzero;
323	return (0);
324}
325
326int
327pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
328    int *nmatch, int flags)
329{
330	struct pfioc_table io;
331
332	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
333		errno = EINVAL;
334		return (-1);
335	}
336	bzero(&io, sizeof io);
337	io.pfrio_flags = flags;
338	io.pfrio_table = *tbl;
339	io.pfrio_buffer = addr;
340	io.pfrio_esize = sizeof(*addr);
341	io.pfrio_size = size;
342	if (ioctl(dev, DIOCRTSTADDRS, &io))
343		return (-1);
344	if (nmatch)
345		*nmatch = io.pfrio_nmatch;
346	return (0);
347}
348
349int
350pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
351    int *nadd, int *naddr, int ticket, int flags)
352{
353	struct pfioc_table io;
354
355	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
356		errno = EINVAL;
357		return (-1);
358	}
359	bzero(&io, sizeof io);
360	io.pfrio_flags = flags;
361	io.pfrio_table = *tbl;
362	io.pfrio_buffer = addr;
363	io.pfrio_esize = sizeof(*addr);
364	io.pfrio_size = size;
365	io.pfrio_ticket = ticket;
366	if (ioctl(dev, DIOCRINADEFINE, &io))
367		return (-1);
368	if (nadd != NULL)
369		*nadd = io.pfrio_nadd;
370	if (naddr != NULL)
371		*naddr = io.pfrio_naddr;
372	return (0);
373}
374
375/* interface management code */
376
377int
378pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
379{
380	struct pfioc_iface io;
381
382	if (size == NULL || *size < 0 || (*size && buf == NULL)) {
383		errno = EINVAL;
384		return (-1);
385	}
386	bzero(&io, sizeof io);
387	if (filter != NULL)
388		if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
389		    sizeof(io.pfiio_name)) {
390			errno = EINVAL;
391			return (-1);
392		}
393	io.pfiio_buffer = buf;
394	io.pfiio_esize = sizeof(*buf);
395	io.pfiio_size = *size;
396	if (ioctl(dev, DIOCIGETIFACES, &io))
397		return (-1);
398	*size = io.pfiio_size;
399	return (0);
400}
401
402/* buffer management code */
403
404size_t buf_esize[PFRB_MAX] = { 0,
405	sizeof(struct pfr_table), sizeof(struct pfr_tstats),
406	sizeof(struct pfr_addr), sizeof(struct pfr_astats),
407	sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
408};
409
410/*
411 * add one element to the buffer
412 */
413int
414pfr_buf_add(struct pfr_buffer *b, const void *e)
415{
416	size_t bs;
417
418	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
419	    e == NULL) {
420		errno = EINVAL;
421		return (-1);
422	}
423	bs = buf_esize[b->pfrb_type];
424	if (b->pfrb_size == b->pfrb_msize)
425		if (pfr_buf_grow(b, 0))
426			return (-1);
427	memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
428	b->pfrb_size++;
429	return (0);
430}
431
432/*
433 * return next element of the buffer (or first one if prev is NULL)
434 * see PFRB_FOREACH macro
435 */
436void *
437pfr_buf_next(struct pfr_buffer *b, const void *prev)
438{
439	size_t bs;
440
441	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
442		return (NULL);
443	if (b->pfrb_size == 0)
444		return (NULL);
445	if (prev == NULL)
446		return (b->pfrb_caddr);
447	bs = buf_esize[b->pfrb_type];
448	if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
449		return (NULL);
450	return (((caddr_t)prev) + bs);
451}
452
453/*
454 * minsize:
455 *    0: make the buffer somewhat bigger
456 *    n: make room for "n" entries in the buffer
457 */
458int
459pfr_buf_grow(struct pfr_buffer *b, int minsize)
460{
461	caddr_t p;
462	size_t bs;
463
464	if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
465		errno = EINVAL;
466		return (-1);
467	}
468	if (minsize != 0 && minsize <= b->pfrb_msize)
469		return (0);
470	bs = buf_esize[b->pfrb_type];
471	if (!b->pfrb_msize) {
472		if (minsize < 64)
473			minsize = 64;
474		b->pfrb_caddr = calloc(bs, minsize);
475		if (b->pfrb_caddr == NULL)
476			return (-1);
477		b->pfrb_msize = minsize;
478	} else {
479		if (minsize == 0)
480			minsize = b->pfrb_msize * 2;
481		if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
482			/* msize overflow */
483			errno = ENOMEM;
484			return (-1);
485		}
486		p = realloc(b->pfrb_caddr, minsize * bs);
487		if (p == NULL)
488			return (-1);
489		bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
490		b->pfrb_caddr = p;
491		b->pfrb_msize = minsize;
492	}
493	return (0);
494}
495
496/*
497 * reset buffer and free memory.
498 */
499void
500pfr_buf_clear(struct pfr_buffer *b)
501{
502	if (b == NULL)
503		return;
504	if (b->pfrb_caddr != NULL)
505		free(b->pfrb_caddr);
506	b->pfrb_caddr = NULL;
507	b->pfrb_size = b->pfrb_msize = 0;
508}
509
510int
511pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
512    int (*append_addr)(struct pfr_buffer *, char *, int))
513{
514	FILE	*fp;
515	char	 buf[BUF_SIZE];
516	int	 rv;
517
518	if (file == NULL)
519		return (0);
520	if (!strcmp(file, "-"))
521		fp = stdin;
522	else {
523		fp = pfctl_fopen(file, "r");
524		if (fp == NULL)
525			return (-1);
526	}
527	while ((rv = pfr_next_token(buf, fp)) == 1)
528		if (append_addr(b, buf, nonetwork)) {
529			rv = -1;
530			break;
531		}
532	if (fp != stdin)
533		fclose(fp);
534	return (rv);
535}
536
537int
538pfr_next_token(char buf[BUF_SIZE], FILE *fp)
539{
540	static char	next_ch = ' ';
541	int		i = 0;
542
543	for (;;) {
544		/* skip spaces */
545		while (isspace(next_ch) && !feof(fp))
546			next_ch = fgetc(fp);
547		/* remove from '#' until end of line */
548		if (next_ch == '#')
549			while (!feof(fp)) {
550				next_ch = fgetc(fp);
551				if (next_ch == '\n')
552					break;
553			}
554		else
555			break;
556	}
557	if (feof(fp)) {
558		next_ch = ' ';
559		return (0);
560	}
561	do {
562		if (i < BUF_SIZE)
563			buf[i++] = next_ch;
564		next_ch = fgetc(fp);
565	} while (!feof(fp) && !isspace(next_ch));
566	if (i >= BUF_SIZE) {
567		errno = EINVAL;
568		return (-1);
569	}
570	buf[i] = '\0';
571	return (1);
572}
573
574char *
575pfr_strerror(int errnum)
576{
577	switch (errnum) {
578	case ESRCH:
579		return "Table does not exist";
580	case ENOENT:
581		return "Anchor or Ruleset does not exist";
582	default:
583		return strerror(errnum);
584	}
585}
586