GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bgpd/pftable.c Lines: 0 98 0.0 %
Date: 2016-12-06 Branches: 0 68 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: pftable.c,v 1.9 2015/12/23 20:42:20 mmcc Exp $ */
2
3
/*
4
 * Copyright (c) 2004 Damien Miller <djm@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/ioctl.h>
21
#include <sys/socket.h>
22
23
#include <netinet/in.h>
24
#include <net/if.h>
25
#include <net/pfvar.h>
26
27
#include <stdlib.h>
28
#include <string.h>
29
#include <errno.h>
30
#include <fcntl.h>
31
32
/* Namespace collision: these are defined in both bgpd.h and pfvar.h */
33
#undef v4
34
#undef v6
35
#undef addr8
36
#undef addr16
37
#undef addr32
38
39
#include "bgpd.h"
40
41
static int devpf = -1;
42
43
struct pf_table {
44
	LIST_ENTRY(pf_table)	entry;
45
	char			name[PFTABLE_LEN];
46
	unsigned long		what;
47
	struct pfr_addr		*worklist;
48
	int			naddrs;
49
	int			nalloc;
50
};
51
52
/* List of tables under management */
53
LIST_HEAD(, pf_table) tables = LIST_HEAD_INITIALIZER(tables);
54
55
static int
56
pftable_change(struct pf_table *pft)
57
{
58
	struct pfioc_table tio;
59
	int ret;
60
61
	if (pft->naddrs == 0 || pft->what == 0)
62
		return (0);
63
64
	if (devpf == -1 && ((devpf = open("/dev/pf", O_RDWR)) == -1))
65
		fatal("open(/dev/pf)");
66
67
	bzero(&tio, sizeof(tio));
68
	strlcpy(tio.pfrio_table.pfrt_name, pft->name,
69
	    sizeof(tio.pfrio_table.pfrt_name));
70
	tio.pfrio_buffer = pft->worklist;
71
	tio.pfrio_esize = sizeof(*pft->worklist);
72
	tio.pfrio_size = pft->naddrs;
73
74
	ret = ioctl(devpf, pft->what, &tio);
75
76
	/* bad prefixes shouldn't cause us to die */
77
	if (ret == -1) {
78
		if (errno == EINVAL)
79
			return (0);
80
		log_warn("pftable_change ioctl");
81
	}
82
83
	return (ret);
84
}
85
86
static int
87
pftable_clear(const char *name)
88
{
89
	struct pfioc_table tio;
90
91
	if (devpf == -1 && ((devpf = open("/dev/pf", O_RDWR)) == -1))
92
		fatal("open(/dev/pf)");
93
94
	bzero(&tio, sizeof(tio));
95
	strlcpy(tio.pfrio_table.pfrt_name, name,
96
	    sizeof(tio.pfrio_table.pfrt_name));
97
98
	if (ioctl(devpf, DIOCRCLRADDRS, &tio) != 0) {
99
		log_warn("pftable_clear ioctl");
100
		return (-1);
101
	}
102
103
	return (0);
104
}
105
106
int
107
pftable_exists(const char *name)
108
{
109
	struct pfioc_table tio;
110
	struct pfr_astats dummy;
111
112
	if (devpf == -1 && ((devpf = open("/dev/pf", O_RDWR)) == -1))
113
		fatal("open(/dev/pf)");
114
115
	bzero(&tio, sizeof(tio));
116
	strlcpy(tio.pfrio_table.pfrt_name, name,
117
	    sizeof(tio.pfrio_table.pfrt_name));
118
	tio.pfrio_buffer = &dummy;
119
	tio.pfrio_esize = sizeof(dummy);
120
	tio.pfrio_size = 1;
121
122
	if (ioctl(devpf, DIOCRGETASTATS, &tio) != 0)
123
		return (-1);
124
125
	return (0);
126
}
127
128
int
129
pftable_add(const char *name)
130
{
131
	struct pf_table *pft;
132
133
	/* Ignore duplicates */
134
	LIST_FOREACH(pft, &tables, entry)
135
		if (strcmp(pft->name, name) == 0)
136
			return (0);
137
138
	if ((pft = malloc(sizeof(*pft))) == NULL) {
139
		log_warn("pftable malloc");
140
		return (-1);
141
	}
142
143
	bzero(pft, sizeof(*pft));
144
	if (strlcpy(pft->name, name, sizeof(pft->name)) >= sizeof(pft->name)) {
145
		log_warn("pf_table name too long");
146
		free(pft);
147
		return (-1);
148
	}
149
150
	LIST_INSERT_HEAD(&tables, pft, entry);
151
152
	return (0);
153
}
154
155
int
156
pftable_clear_all(void)
157
{
158
	struct pf_table *pft;
159
160
	LIST_FOREACH(pft, &tables, entry) {
161
		if (pftable_clear(pft->name) != 0)
162
			return (-1);
163
		free(pft->worklist);
164
		pft->worklist = NULL;
165
		pft->nalloc = pft->naddrs = 0;
166
		pft->what = 0;
167
	}
168
169
	return (0);
170
}
171
172
static int
173
pftable_add_work(const char *table, struct bgpd_addr *addr,
174
    u_int8_t len, int del)
175
{
176
	struct pf_table *pft;
177
	struct pfr_addr *pfa, *tmp;
178
	unsigned long what;
179
180
	if (*table == '\0' || len > 128)
181
		fatal("pftable_add_work: insane");
182
183
	/* Find table */
184
	LIST_FOREACH(pft, &tables, entry)
185
		if (strcmp(pft->name, table) == 0)
186
			break;
187
188
	if (pft == NULL) {
189
		log_warn("pf table %s not found", table);
190
		return (-1);
191
	}
192
193
	/* Only one type of work on the list at a time */
194
	what = del ? DIOCRDELADDRS : DIOCRADDADDRS;
195
	if (pft->naddrs != 0 && pft->what != what)
196
		fatal("attempt to mix pf table additions/deletions");
197
198
	if (pft->nalloc <= pft->naddrs)
199
		pft->nalloc = pft->nalloc == 0 ? 1 : pft->nalloc * 2;
200
	tmp = reallocarray(pft->worklist, pft->nalloc, sizeof(*tmp));
201
	if (tmp == NULL) {
202
		if (pft->worklist != NULL) {
203
			log_warn("pftable_add_work: malloc");
204
			free(pft->worklist);
205
			pft->worklist = NULL;
206
		}
207
		pft->nalloc = pft->naddrs = 0;
208
		pft->what = 0;
209
		return (-1);
210
	}
211
	pft->worklist = tmp;
212
	pfa = &pft->worklist[pft->naddrs];
213
214
	bzero(pfa, sizeof(*pfa));
215
	memcpy(&pfa->pfra_u, &addr->ba, (len + 7U) / 8);
216
	pfa->pfra_af = aid2af(addr->aid);
217
	pfa->pfra_net = len;
218
219
	pft->naddrs++;
220
	pft->what = what;
221
222
	/* Don't let the list grow too large */
223
	if (pft->naddrs >= 1024)
224
		pftable_commit();
225
226
	return (0);
227
}
228
229
/* imsg handlers */
230
int
231
pftable_addr_add(struct pftable_msg *m)
232
{
233
	return (pftable_add_work(m->pftable, &m->addr, m->len, 0));
234
}
235
236
int
237
pftable_addr_remove(struct pftable_msg *m)
238
{
239
	return (pftable_add_work(m->pftable, &m->addr, m->len, 1));
240
}
241
242
int
243
pftable_commit(void)
244
{
245
	struct pf_table *pft;
246
	int ret = 0;
247
248
	LIST_FOREACH(pft, &tables, entry) {
249
		if (pft->what != 0 && pftable_change(pft) != 0)
250
			ret = -1;
251
		free(pft->worklist);
252
		pft->worklist = NULL;
253
		pft->nalloc = pft->naddrs = 0;
254
		pft->what = 0;
255
	}
256
257
	return (ret);
258
}
259