1d8aa10ccSGleb Smirnoff /*-
2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
43b3a8eb9SGleb Smirnoff * Copyright (c) 2001 Daniel Hartmeier
53b3a8eb9SGleb Smirnoff * Copyright (c) 2002,2003 Henning Brauer
63b3a8eb9SGleb Smirnoff * All rights reserved.
73b3a8eb9SGleb Smirnoff *
83b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without
93b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions
103b3a8eb9SGleb Smirnoff * are met:
113b3a8eb9SGleb Smirnoff *
123b3a8eb9SGleb Smirnoff * - Redistributions of source code must retain the above copyright
133b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer.
143b3a8eb9SGleb Smirnoff * - Redistributions in binary form must reproduce the above
153b3a8eb9SGleb Smirnoff * copyright notice, this list of conditions and the following
163b3a8eb9SGleb Smirnoff * disclaimer in the documentation and/or other materials provided
173b3a8eb9SGleb Smirnoff * with the distribution.
183b3a8eb9SGleb Smirnoff *
193b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
203b3a8eb9SGleb Smirnoff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
213b3a8eb9SGleb Smirnoff * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
223b3a8eb9SGleb Smirnoff * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
233b3a8eb9SGleb Smirnoff * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
243b3a8eb9SGleb Smirnoff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
253b3a8eb9SGleb Smirnoff * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
263b3a8eb9SGleb Smirnoff * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
273b3a8eb9SGleb Smirnoff * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
283b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
293b3a8eb9SGleb Smirnoff * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
303b3a8eb9SGleb Smirnoff * POSSIBILITY OF SUCH DAMAGE.
313b3a8eb9SGleb Smirnoff *
323b3a8eb9SGleb Smirnoff * Effort sponsored in part by the Defense Advanced Research Projects
333b3a8eb9SGleb Smirnoff * Agency (DARPA) and Air Force Research Laboratory, Air Force
343b3a8eb9SGleb Smirnoff * Materiel Command, USAF, under agreement number F30602-01-2-0537.
353b3a8eb9SGleb Smirnoff *
36d8aa10ccSGleb Smirnoff * $OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $
373b3a8eb9SGleb Smirnoff */
383b3a8eb9SGleb Smirnoff
393b3a8eb9SGleb Smirnoff #include <sys/param.h>
403b3a8eb9SGleb Smirnoff #include <sys/socket.h>
413b3a8eb9SGleb Smirnoff #include <sys/systm.h>
423b3a8eb9SGleb Smirnoff #include <sys/refcount.h>
433b3a8eb9SGleb Smirnoff #include <sys/mbuf.h>
443b3a8eb9SGleb Smirnoff
453b3a8eb9SGleb Smirnoff #include <netinet/in.h>
463b3a8eb9SGleb Smirnoff #include <netinet/in_systm.h>
473b3a8eb9SGleb Smirnoff #include <netinet/ip.h>
483b3a8eb9SGleb Smirnoff #include <netinet/tcp.h>
493b3a8eb9SGleb Smirnoff
503b3a8eb9SGleb Smirnoff #include <net/if.h>
51eedc7fd9SGleb Smirnoff #include <net/vnet.h>
523b3a8eb9SGleb Smirnoff #include <net/pfvar.h>
533b3a8eb9SGleb Smirnoff
543b3a8eb9SGleb Smirnoff #ifdef INET6
553b3a8eb9SGleb Smirnoff #include <netinet/ip6.h>
563b3a8eb9SGleb Smirnoff #endif /* INET6 */
573b3a8eb9SGleb Smirnoff
58fda7daf0SKristof Provost #ifndef _KERNEL
59fda7daf0SKristof Provost #error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead."
60fda7daf0SKristof Provost #endif
61fda7daf0SKristof Provost
623b3a8eb9SGleb Smirnoff #define DPFPRINTF(format, x...) \
633b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_NOISY) \
643b3a8eb9SGleb Smirnoff printf(format , ##x)
653b3a8eb9SGleb Smirnoff #define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
663b3a8eb9SGleb Smirnoff #define rs_free(x) free(x, M_TEMP)
673b3a8eb9SGleb Smirnoff
68e86bddeaSKristof Provost VNET_DEFINE(struct pf_kanchor_global, pf_anchors);
69e86bddeaSKristof Provost VNET_DEFINE(struct pf_kanchor, pf_main_anchor);
70c5131afeSKristof Provost VNET_DEFINE(struct pf_keth_ruleset*, pf_keth);
71c5131afeSKristof Provost VNET_DEFINE(struct pf_keth_anchor, pf_main_keth_anchor);
72c5131afeSKristof Provost VNET_DEFINE(struct pf_keth_anchor_global, pf_keth_anchors);
733b3a8eb9SGleb Smirnoff
74e86bddeaSKristof Provost static __inline int pf_kanchor_compare(struct pf_kanchor *,
75e86bddeaSKristof Provost struct pf_kanchor *);
76c5131afeSKristof Provost static __inline int pf_keth_anchor_compare(struct pf_keth_anchor *,
77c5131afeSKristof Provost struct pf_keth_anchor *);
78e86bddeaSKristof Provost static struct pf_kanchor *pf_find_kanchor(const char *);
79e86bddeaSKristof Provost
80e86bddeaSKristof Provost RB_GENERATE(pf_kanchor_global, pf_kanchor, entry_global, pf_kanchor_compare);
81e86bddeaSKristof Provost RB_GENERATE(pf_kanchor_node, pf_kanchor, entry_node, pf_kanchor_compare);
82c5131afeSKristof Provost RB_GENERATE(pf_keth_anchor_global, pf_keth_anchor, entry_global,
83c5131afeSKristof Provost pf_keth_anchor_compare);
84c5131afeSKristof Provost RB_GENERATE(pf_keth_anchor_node, pf_keth_anchor, entry_node,
85c5131afeSKristof Provost pf_keth_anchor_compare);
863b3a8eb9SGleb Smirnoff
87e86bddeaSKristof Provost static __inline int
pf_kanchor_compare(struct pf_kanchor * a,struct pf_kanchor * b)88e86bddeaSKristof Provost pf_kanchor_compare(struct pf_kanchor *a, struct pf_kanchor *b)
89e86bddeaSKristof Provost {
90e86bddeaSKristof Provost int c = strcmp(a->path, b->path);
91e86bddeaSKristof Provost
92e86bddeaSKristof Provost return (c ? (c < 0 ? -1 : 1) : 0);
93e86bddeaSKristof Provost }
943b3a8eb9SGleb Smirnoff
95c5131afeSKristof Provost static __inline int
pf_keth_anchor_compare(struct pf_keth_anchor * a,struct pf_keth_anchor * b)96c5131afeSKristof Provost pf_keth_anchor_compare(struct pf_keth_anchor *a, struct pf_keth_anchor *b)
97c5131afeSKristof Provost {
98c5131afeSKristof Provost int c = strcmp(a->path, b->path);
99c5131afeSKristof Provost
100c5131afeSKristof Provost return (c ? (c < 0 ? -1 : 1) : 0);
101c5131afeSKristof Provost }
102c5131afeSKristof Provost
1033b3a8eb9SGleb Smirnoff int
pf_get_ruleset_number(u_int8_t action)1043b3a8eb9SGleb Smirnoff pf_get_ruleset_number(u_int8_t action)
1053b3a8eb9SGleb Smirnoff {
1063b3a8eb9SGleb Smirnoff switch (action) {
1073b3a8eb9SGleb Smirnoff case PF_SCRUB:
1083b3a8eb9SGleb Smirnoff case PF_NOSCRUB:
1093b3a8eb9SGleb Smirnoff return (PF_RULESET_SCRUB);
1103b3a8eb9SGleb Smirnoff break;
1113b3a8eb9SGleb Smirnoff case PF_PASS:
112ef950daaSKristof Provost case PF_MATCH:
1133b3a8eb9SGleb Smirnoff case PF_DROP:
1143b3a8eb9SGleb Smirnoff return (PF_RULESET_FILTER);
1153b3a8eb9SGleb Smirnoff break;
1163b3a8eb9SGleb Smirnoff case PF_NAT:
1173b3a8eb9SGleb Smirnoff case PF_NONAT:
1183b3a8eb9SGleb Smirnoff return (PF_RULESET_NAT);
1193b3a8eb9SGleb Smirnoff break;
1203b3a8eb9SGleb Smirnoff case PF_BINAT:
1213b3a8eb9SGleb Smirnoff case PF_NOBINAT:
1223b3a8eb9SGleb Smirnoff return (PF_RULESET_BINAT);
1233b3a8eb9SGleb Smirnoff break;
1243b3a8eb9SGleb Smirnoff case PF_RDR:
1253b3a8eb9SGleb Smirnoff case PF_NORDR:
1263b3a8eb9SGleb Smirnoff return (PF_RULESET_RDR);
1273b3a8eb9SGleb Smirnoff break;
1283b3a8eb9SGleb Smirnoff default:
1293b3a8eb9SGleb Smirnoff return (PF_RULESET_MAX);
1303b3a8eb9SGleb Smirnoff break;
1313b3a8eb9SGleb Smirnoff }
1323b3a8eb9SGleb Smirnoff }
1333b3a8eb9SGleb Smirnoff
134e86bddeaSKristof Provost static struct pf_kanchor *
pf_find_kanchor(const char * path)135e86bddeaSKristof Provost pf_find_kanchor(const char *path)
136e86bddeaSKristof Provost {
137e86bddeaSKristof Provost struct pf_kanchor *key, *found;
138e86bddeaSKristof Provost
139e86bddeaSKristof Provost key = (struct pf_kanchor *)rs_malloc(sizeof(*key));
140e86bddeaSKristof Provost if (key == NULL)
141e86bddeaSKristof Provost return (NULL);
142e86bddeaSKristof Provost strlcpy(key->path, path, sizeof(key->path));
143e86bddeaSKristof Provost found = RB_FIND(pf_kanchor_global, &V_pf_anchors, key);
144e86bddeaSKristof Provost rs_free(key);
145e86bddeaSKristof Provost return (found);
146e86bddeaSKristof Provost }
147e86bddeaSKristof Provost
148e86bddeaSKristof Provost void
pf_init_kruleset(struct pf_kruleset * ruleset)149e86bddeaSKristof Provost pf_init_kruleset(struct pf_kruleset *ruleset)
150e86bddeaSKristof Provost {
151e86bddeaSKristof Provost int i;
152e86bddeaSKristof Provost
153e86bddeaSKristof Provost memset(ruleset, 0, sizeof(struct pf_kruleset));
154e86bddeaSKristof Provost for (i = 0; i < PF_RULESET_MAX; i++) {
155e86bddeaSKristof Provost TAILQ_INIT(&ruleset->rules[i].queues[0]);
156e86bddeaSKristof Provost TAILQ_INIT(&ruleset->rules[i].queues[1]);
157e86bddeaSKristof Provost ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
158e86bddeaSKristof Provost ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
159e86bddeaSKristof Provost }
160e86bddeaSKristof Provost }
161e86bddeaSKristof Provost
162e732e742SKristof Provost void
pf_init_keth(struct pf_keth_ruleset * rs)163c5131afeSKristof Provost pf_init_keth(struct pf_keth_ruleset *rs)
164e732e742SKristof Provost {
165e732e742SKristof Provost
166c5131afeSKristof Provost bzero(rs, sizeof(*rs));
167c5131afeSKristof Provost TAILQ_INIT(&rs->rules[0]);
168c5131afeSKristof Provost TAILQ_INIT(&rs->rules[1]);
169c5131afeSKristof Provost rs->active.rules = &rs->rules[0];
170c5131afeSKristof Provost rs->active.open = 0;
171c5131afeSKristof Provost rs->inactive.rules = &rs->rules[1];
172c5131afeSKristof Provost rs->inactive.open = 0;
173c5131afeSKristof Provost
174c5131afeSKristof Provost rs->vnet = curvnet;
175e732e742SKristof Provost }
176e732e742SKristof Provost
177e86bddeaSKristof Provost struct pf_kruleset *
pf_find_kruleset(const char * path)178e86bddeaSKristof Provost pf_find_kruleset(const char *path)
179e86bddeaSKristof Provost {
180e86bddeaSKristof Provost struct pf_kanchor *anchor;
181e86bddeaSKristof Provost
182e86bddeaSKristof Provost while (*path == '/')
183e86bddeaSKristof Provost path++;
184e86bddeaSKristof Provost if (!*path)
185e86bddeaSKristof Provost return (&pf_main_ruleset);
186e86bddeaSKristof Provost anchor = pf_find_kanchor(path);
187e86bddeaSKristof Provost if (anchor == NULL)
188e86bddeaSKristof Provost return (NULL);
189e86bddeaSKristof Provost else
190e86bddeaSKristof Provost return (&anchor->ruleset);
191e86bddeaSKristof Provost }
192e86bddeaSKristof Provost
193e86bddeaSKristof Provost struct pf_kruleset *
pf_find_or_create_kruleset(const char * path)194e86bddeaSKristof Provost pf_find_or_create_kruleset(const char *path)
195e86bddeaSKristof Provost {
196e86bddeaSKristof Provost char *p, *q, *r;
197e86bddeaSKristof Provost struct pf_kruleset *ruleset;
198e86bddeaSKristof Provost struct pf_kanchor *anchor = NULL, *dup, *parent = NULL;
199e86bddeaSKristof Provost
200e86bddeaSKristof Provost if (path[0] == 0)
201e86bddeaSKristof Provost return (&pf_main_ruleset);
202e86bddeaSKristof Provost while (*path == '/')
203e86bddeaSKristof Provost path++;
204e86bddeaSKristof Provost ruleset = pf_find_kruleset(path);
205e86bddeaSKristof Provost if (ruleset != NULL)
206e86bddeaSKristof Provost return (ruleset);
207e86bddeaSKristof Provost p = (char *)rs_malloc(MAXPATHLEN);
208e86bddeaSKristof Provost if (p == NULL)
209e86bddeaSKristof Provost return (NULL);
210e86bddeaSKristof Provost strlcpy(p, path, MAXPATHLEN);
211e86bddeaSKristof Provost while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
212e86bddeaSKristof Provost *q = 0;
213e86bddeaSKristof Provost if ((ruleset = pf_find_kruleset(p)) != NULL) {
214e86bddeaSKristof Provost parent = ruleset->anchor;
215e86bddeaSKristof Provost break;
216e86bddeaSKristof Provost }
217e86bddeaSKristof Provost }
218e86bddeaSKristof Provost if (q == NULL)
219e86bddeaSKristof Provost q = p;
220e86bddeaSKristof Provost else
221e86bddeaSKristof Provost q++;
222e86bddeaSKristof Provost strlcpy(p, path, MAXPATHLEN);
223e86bddeaSKristof Provost if (!*q) {
224e86bddeaSKristof Provost rs_free(p);
225e86bddeaSKristof Provost return (NULL);
226e86bddeaSKristof Provost }
227e86bddeaSKristof Provost while ((r = strchr(q, '/')) != NULL || *q) {
228e86bddeaSKristof Provost if (r != NULL)
229e86bddeaSKristof Provost *r = 0;
230e86bddeaSKristof Provost if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
231e86bddeaSKristof Provost (parent != NULL && strlen(parent->path) >=
232e86bddeaSKristof Provost MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
233e86bddeaSKristof Provost rs_free(p);
234e86bddeaSKristof Provost return (NULL);
235e86bddeaSKristof Provost }
236e86bddeaSKristof Provost anchor = (struct pf_kanchor *)rs_malloc(sizeof(*anchor));
237e86bddeaSKristof Provost if (anchor == NULL) {
238e86bddeaSKristof Provost rs_free(p);
239e86bddeaSKristof Provost return (NULL);
240e86bddeaSKristof Provost }
241e86bddeaSKristof Provost RB_INIT(&anchor->children);
242e86bddeaSKristof Provost strlcpy(anchor->name, q, sizeof(anchor->name));
243e86bddeaSKristof Provost if (parent != NULL) {
244e86bddeaSKristof Provost strlcpy(anchor->path, parent->path,
245e86bddeaSKristof Provost sizeof(anchor->path));
246e86bddeaSKristof Provost strlcat(anchor->path, "/", sizeof(anchor->path));
247e86bddeaSKristof Provost }
248e86bddeaSKristof Provost strlcat(anchor->path, anchor->name, sizeof(anchor->path));
249e86bddeaSKristof Provost if ((dup = RB_INSERT(pf_kanchor_global, &V_pf_anchors, anchor)) !=
250e86bddeaSKristof Provost NULL) {
251e86bddeaSKristof Provost printf("pf_find_or_create_ruleset: RB_INSERT1 "
252e86bddeaSKristof Provost "'%s' '%s' collides with '%s' '%s'\n",
253e86bddeaSKristof Provost anchor->path, anchor->name, dup->path, dup->name);
254e86bddeaSKristof Provost rs_free(anchor);
255e86bddeaSKristof Provost rs_free(p);
256e86bddeaSKristof Provost return (NULL);
257e86bddeaSKristof Provost }
258e86bddeaSKristof Provost if (parent != NULL) {
259e86bddeaSKristof Provost anchor->parent = parent;
260e86bddeaSKristof Provost if ((dup = RB_INSERT(pf_kanchor_node, &parent->children,
261e86bddeaSKristof Provost anchor)) != NULL) {
262e86bddeaSKristof Provost printf("pf_find_or_create_ruleset: "
263e86bddeaSKristof Provost "RB_INSERT2 '%s' '%s' collides with "
264e86bddeaSKristof Provost "'%s' '%s'\n", anchor->path, anchor->name,
265e86bddeaSKristof Provost dup->path, dup->name);
266e86bddeaSKristof Provost RB_REMOVE(pf_kanchor_global, &V_pf_anchors,
267e86bddeaSKristof Provost anchor);
268e86bddeaSKristof Provost rs_free(anchor);
269e86bddeaSKristof Provost rs_free(p);
270e86bddeaSKristof Provost return (NULL);
271e86bddeaSKristof Provost }
272e86bddeaSKristof Provost }
273e86bddeaSKristof Provost pf_init_kruleset(&anchor->ruleset);
274e86bddeaSKristof Provost anchor->ruleset.anchor = anchor;
275e86bddeaSKristof Provost parent = anchor;
276e86bddeaSKristof Provost if (r != NULL)
277e86bddeaSKristof Provost q = r + 1;
278e86bddeaSKristof Provost else
279e86bddeaSKristof Provost *q = 0;
280e86bddeaSKristof Provost }
281e86bddeaSKristof Provost rs_free(p);
282e86bddeaSKristof Provost return (&anchor->ruleset);
283e86bddeaSKristof Provost }
284e86bddeaSKristof Provost
285e86bddeaSKristof Provost void
pf_remove_if_empty_kruleset(struct pf_kruleset * ruleset)286e86bddeaSKristof Provost pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
287e86bddeaSKristof Provost {
288e86bddeaSKristof Provost struct pf_kanchor *parent;
289e86bddeaSKristof Provost int i;
290e86bddeaSKristof Provost
291e86bddeaSKristof Provost while (ruleset != NULL) {
292e86bddeaSKristof Provost if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
293e86bddeaSKristof Provost !RB_EMPTY(&ruleset->anchor->children) ||
294e86bddeaSKristof Provost ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
295e86bddeaSKristof Provost ruleset->topen)
296e86bddeaSKristof Provost return;
297e86bddeaSKristof Provost for (i = 0; i < PF_RULESET_MAX; ++i)
298e86bddeaSKristof Provost if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
299e86bddeaSKristof Provost !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
300e86bddeaSKristof Provost ruleset->rules[i].inactive.open)
301e86bddeaSKristof Provost return;
302e86bddeaSKristof Provost RB_REMOVE(pf_kanchor_global, &V_pf_anchors, ruleset->anchor);
303e86bddeaSKristof Provost if ((parent = ruleset->anchor->parent) != NULL)
304e86bddeaSKristof Provost RB_REMOVE(pf_kanchor_node, &parent->children,
305e86bddeaSKristof Provost ruleset->anchor);
306e86bddeaSKristof Provost rs_free(ruleset->anchor);
307e86bddeaSKristof Provost if (parent == NULL)
308e86bddeaSKristof Provost return;
309e86bddeaSKristof Provost ruleset = &parent->ruleset;
310e86bddeaSKristof Provost }
311e86bddeaSKristof Provost }
312e86bddeaSKristof Provost
313e86bddeaSKristof Provost int
pf_kanchor_setup(struct pf_krule * r,const struct pf_kruleset * s,const char * name)314e86bddeaSKristof Provost pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
315e86bddeaSKristof Provost const char *name)
316e86bddeaSKristof Provost {
317e86bddeaSKristof Provost char *p, *path;
318e86bddeaSKristof Provost struct pf_kruleset *ruleset;
319e86bddeaSKristof Provost
320e86bddeaSKristof Provost r->anchor = NULL;
321e86bddeaSKristof Provost r->anchor_relative = 0;
322e86bddeaSKristof Provost r->anchor_wildcard = 0;
323e86bddeaSKristof Provost if (!name[0])
324e86bddeaSKristof Provost return (0);
325e86bddeaSKristof Provost path = (char *)rs_malloc(MAXPATHLEN);
326e86bddeaSKristof Provost if (path == NULL)
327e86bddeaSKristof Provost return (1);
328e86bddeaSKristof Provost if (name[0] == '/')
329e86bddeaSKristof Provost strlcpy(path, name + 1, MAXPATHLEN);
330e86bddeaSKristof Provost else {
331e86bddeaSKristof Provost /* relative path */
332e86bddeaSKristof Provost r->anchor_relative = 1;
333e86bddeaSKristof Provost if (s->anchor == NULL || !s->anchor->path[0])
334e86bddeaSKristof Provost path[0] = 0;
335e86bddeaSKristof Provost else
336e86bddeaSKristof Provost strlcpy(path, s->anchor->path, MAXPATHLEN);
337e86bddeaSKristof Provost while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
338e86bddeaSKristof Provost if (!path[0]) {
33986b653edSKristof Provost DPFPRINTF("pf_anchor_setup: .. beyond root\n");
340e86bddeaSKristof Provost rs_free(path);
341e86bddeaSKristof Provost return (1);
342e86bddeaSKristof Provost }
343e86bddeaSKristof Provost if ((p = strrchr(path, '/')) != NULL)
344e86bddeaSKristof Provost *p = 0;
345e86bddeaSKristof Provost else
346e86bddeaSKristof Provost path[0] = 0;
347e86bddeaSKristof Provost r->anchor_relative++;
348e86bddeaSKristof Provost name += 3;
349e86bddeaSKristof Provost }
350e86bddeaSKristof Provost if (path[0])
351e86bddeaSKristof Provost strlcat(path, "/", MAXPATHLEN);
352e86bddeaSKristof Provost strlcat(path, name, MAXPATHLEN);
353e86bddeaSKristof Provost }
354e86bddeaSKristof Provost if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
355e86bddeaSKristof Provost r->anchor_wildcard = 1;
356e86bddeaSKristof Provost *p = 0;
357e86bddeaSKristof Provost }
358e86bddeaSKristof Provost ruleset = pf_find_or_create_kruleset(path);
359e86bddeaSKristof Provost rs_free(path);
360e86bddeaSKristof Provost if (ruleset == NULL || ruleset->anchor == NULL) {
36186b653edSKristof Provost DPFPRINTF("pf_anchor_setup: ruleset\n");
362e86bddeaSKristof Provost return (1);
363e86bddeaSKristof Provost }
364e86bddeaSKristof Provost r->anchor = ruleset->anchor;
365e86bddeaSKristof Provost r->anchor->refcnt++;
366e86bddeaSKristof Provost return (0);
367e86bddeaSKristof Provost }
368e86bddeaSKristof Provost
369e86bddeaSKristof Provost int
pf_kanchor_copyout(const struct pf_kruleset * rs,const struct pf_krule * r,char * anchor_call,size_t anchor_call_len)370777a4702SKristof Provost pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
371*6ee3e376SKristof Provost char *anchor_call, size_t anchor_call_len)
372d710367dSKristof Provost {
373777a4702SKristof Provost anchor_call[0] = 0;
374d710367dSKristof Provost
375d710367dSKristof Provost if (r->anchor == NULL)
376d710367dSKristof Provost goto done;
377d710367dSKristof Provost if (!r->anchor_relative) {
378*6ee3e376SKristof Provost strlcpy(anchor_call, "/", anchor_call_len);
379d710367dSKristof Provost strlcat(anchor_call, r->anchor->path,
380*6ee3e376SKristof Provost anchor_call_len);
381d710367dSKristof Provost } else {
382d710367dSKristof Provost char a[MAXPATHLEN];
383d710367dSKristof Provost char *p;
384d710367dSKristof Provost int i;
385d710367dSKristof Provost if (rs->anchor == NULL)
386d710367dSKristof Provost a[0] = 0;
387d710367dSKristof Provost else
388d710367dSKristof Provost strlcpy(a, rs->anchor->path, MAXPATHLEN);
389d710367dSKristof Provost for (i = 1; i < r->anchor_relative; ++i) {
390d710367dSKristof Provost if ((p = strrchr(a, '/')) == NULL)
391d710367dSKristof Provost p = a;
392d710367dSKristof Provost *p = 0;
393d710367dSKristof Provost strlcat(anchor_call, "../",
394*6ee3e376SKristof Provost anchor_call_len);
395d710367dSKristof Provost }
396d710367dSKristof Provost if (strncmp(a, r->anchor->path, strlen(a))) {
397d710367dSKristof Provost printf("pf_anchor_copyout: '%s' '%s'\n", a,
398d710367dSKristof Provost r->anchor->path);
399d710367dSKristof Provost return (1);
400d710367dSKristof Provost }
401d710367dSKristof Provost if (strlen(r->anchor->path) > strlen(a))
402d710367dSKristof Provost strlcat(anchor_call, r->anchor->path + (a[0] ?
403*6ee3e376SKristof Provost strlen(a) + 1 : 0), anchor_call_len);
404d710367dSKristof Provost
405d710367dSKristof Provost }
406d710367dSKristof Provost if (r->anchor_wildcard)
407d710367dSKristof Provost strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
408*6ee3e376SKristof Provost anchor_call_len);
409d710367dSKristof Provost
410d710367dSKristof Provost done:
411d710367dSKristof Provost
412d710367dSKristof Provost return (0);
413d710367dSKristof Provost }
414d710367dSKristof Provost
415d710367dSKristof Provost int
pf_kanchor_nvcopyout(const struct pf_kruleset * rs,const struct pf_krule * r,nvlist_t * nvl)416777a4702SKristof Provost pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
417777a4702SKristof Provost nvlist_t *nvl)
418777a4702SKristof Provost {
419777a4702SKristof Provost char anchor_call[MAXPATHLEN] = { 0 };
420777a4702SKristof Provost int ret;
421777a4702SKristof Provost
422*6ee3e376SKristof Provost ret = pf_kanchor_copyout(rs, r, anchor_call, sizeof(anchor_call));
423777a4702SKristof Provost MPASS(ret == 0);
424777a4702SKristof Provost
425777a4702SKristof Provost nvlist_add_string(nvl, "anchor_call", anchor_call);
426777a4702SKristof Provost
427777a4702SKristof Provost return (ret);
428777a4702SKristof Provost }
429777a4702SKristof Provost
430777a4702SKristof Provost int
pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset * rs,const struct pf_keth_rule * r,nvlist_t * nvl)431c5131afeSKristof Provost pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
432c5131afeSKristof Provost const struct pf_keth_rule *r, nvlist_t *nvl)
433c5131afeSKristof Provost {
434c5131afeSKristof Provost char anchor_call[MAXPATHLEN] = { 0 };
435c5131afeSKristof Provost
436c5131afeSKristof Provost if (r->anchor == NULL)
437c5131afeSKristof Provost goto done;
438c5131afeSKristof Provost if (!r->anchor_relative) {
439c5131afeSKristof Provost strlcpy(anchor_call, "/", sizeof(anchor_call));
440c5131afeSKristof Provost strlcat(anchor_call, r->anchor->path,
441c5131afeSKristof Provost sizeof(anchor_call));
442c5131afeSKristof Provost } else {
443c5131afeSKristof Provost char a[MAXPATHLEN];
444c5131afeSKristof Provost char *p;
445c5131afeSKristof Provost int i;
446c5131afeSKristof Provost if (rs->anchor == NULL)
447c5131afeSKristof Provost a[0] = 0;
448c5131afeSKristof Provost else
449c5131afeSKristof Provost strlcpy(a, rs->anchor->path, MAXPATHLEN);
450c5131afeSKristof Provost for (i = 1; i < r->anchor_relative; ++i) {
451c5131afeSKristof Provost if ((p = strrchr(a, '/')) == NULL)
452c5131afeSKristof Provost p = a;
453c5131afeSKristof Provost *p = 0;
454c5131afeSKristof Provost strlcat(anchor_call, "../",
455c5131afeSKristof Provost sizeof(anchor_call));
456c5131afeSKristof Provost }
457c5131afeSKristof Provost if (strncmp(a, r->anchor->path, strlen(a))) {
458c5131afeSKristof Provost printf("%s(): '%s' '%s'\n", __func__, a,
459c5131afeSKristof Provost r->anchor->path);
460c5131afeSKristof Provost return (1);
461c5131afeSKristof Provost }
462c5131afeSKristof Provost if (strlen(r->anchor->path) > strlen(a))
463c5131afeSKristof Provost strlcat(anchor_call, r->anchor->path + (a[0] ?
464c5131afeSKristof Provost strlen(a) + 1 : 0), sizeof(anchor_call));
465c5131afeSKristof Provost
466c5131afeSKristof Provost }
467c5131afeSKristof Provost if (r->anchor_wildcard)
468c5131afeSKristof Provost strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
469c5131afeSKristof Provost sizeof(anchor_call));
470c5131afeSKristof Provost
471c5131afeSKristof Provost done:
472c5131afeSKristof Provost nvlist_add_string(nvl, "anchor_call", anchor_call);
473c5131afeSKristof Provost
474c5131afeSKristof Provost return (0);
475c5131afeSKristof Provost }
476c5131afeSKristof Provost
477e86bddeaSKristof Provost void
pf_kanchor_remove(struct pf_krule * r)478e86bddeaSKristof Provost pf_kanchor_remove(struct pf_krule *r)
479e86bddeaSKristof Provost {
480e86bddeaSKristof Provost if (r->anchor == NULL)
481e86bddeaSKristof Provost return;
482e86bddeaSKristof Provost if (r->anchor->refcnt <= 0) {
483e86bddeaSKristof Provost printf("pf_anchor_remove: broken refcount\n");
484e86bddeaSKristof Provost r->anchor = NULL;
485e86bddeaSKristof Provost return;
486e86bddeaSKristof Provost }
487e86bddeaSKristof Provost if (!--r->anchor->refcnt)
488e86bddeaSKristof Provost pf_remove_if_empty_kruleset(&r->anchor->ruleset);
489e86bddeaSKristof Provost r->anchor = NULL;
490e86bddeaSKristof Provost }
491c5131afeSKristof Provost
492c5131afeSKristof Provost struct pf_keth_ruleset *
pf_find_keth_ruleset(const char * path)493c5131afeSKristof Provost pf_find_keth_ruleset(const char *path)
494c5131afeSKristof Provost {
495c5131afeSKristof Provost struct pf_keth_anchor *anchor;
496c5131afeSKristof Provost
497c5131afeSKristof Provost while (*path == '/')
498c5131afeSKristof Provost path++;
499c5131afeSKristof Provost if (!*path)
500c5131afeSKristof Provost return (V_pf_keth);
501c5131afeSKristof Provost anchor = pf_find_keth_anchor(path);
502c5131afeSKristof Provost if (anchor == NULL)
503c5131afeSKristof Provost return (NULL);
504c5131afeSKristof Provost else
505c5131afeSKristof Provost return (&anchor->ruleset);
506c5131afeSKristof Provost }
507c5131afeSKristof Provost
508c5131afeSKristof Provost static struct pf_keth_anchor *
_pf_find_keth_anchor(struct pf_keth_ruleset * rs,const char * path)509c5131afeSKristof Provost _pf_find_keth_anchor(struct pf_keth_ruleset *rs, const char *path)
510c5131afeSKristof Provost {
511c5131afeSKristof Provost struct pf_keth_anchor *key, *found;
512c5131afeSKristof Provost
513c5131afeSKristof Provost key = (struct pf_keth_anchor *)rs_malloc(sizeof(*key));
514c5131afeSKristof Provost if (key == NULL)
515c5131afeSKristof Provost return (NULL);
516c5131afeSKristof Provost strlcpy(key->path, path, sizeof(key->path));
517c5131afeSKristof Provost found = RB_FIND(pf_keth_anchor_global, &V_pf_keth_anchors, key);
518c5131afeSKristof Provost rs_free(key);
519c5131afeSKristof Provost return (found);
520c5131afeSKristof Provost }
521c5131afeSKristof Provost
522c5131afeSKristof Provost struct pf_keth_anchor *
pf_find_keth_anchor(const char * path)523c5131afeSKristof Provost pf_find_keth_anchor(const char *path)
524c5131afeSKristof Provost {
525c5131afeSKristof Provost return (_pf_find_keth_anchor(V_pf_keth, path));
526c5131afeSKristof Provost }
527c5131afeSKristof Provost
528c5131afeSKristof Provost struct pf_keth_ruleset *
pf_find_or_create_keth_ruleset(const char * path)529c5131afeSKristof Provost pf_find_or_create_keth_ruleset(const char *path)
530c5131afeSKristof Provost {
531c5131afeSKristof Provost char *p, *q, *r;
532c5131afeSKristof Provost struct pf_keth_anchor *anchor = NULL, *dup = NULL, *parent = NULL;
533c5131afeSKristof Provost struct pf_keth_ruleset *ruleset;
534c5131afeSKristof Provost
535c5131afeSKristof Provost if (path[0] == 0)
536c5131afeSKristof Provost return (V_pf_keth);
537c5131afeSKristof Provost while (*path == '/')
538c5131afeSKristof Provost path++;
539c5131afeSKristof Provost ruleset = pf_find_keth_ruleset(path);
540c5131afeSKristof Provost if (ruleset != NULL)
541c5131afeSKristof Provost return (ruleset);
542c5131afeSKristof Provost p = (char *)rs_malloc(MAXPATHLEN);
543c5131afeSKristof Provost if (p == NULL)
544c5131afeSKristof Provost return (NULL);
545c5131afeSKristof Provost strlcpy(p, path, MAXPATHLEN);
546c5131afeSKristof Provost while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
547c5131afeSKristof Provost *q = 0;
548c5131afeSKristof Provost if ((ruleset = pf_find_keth_ruleset(p)) != NULL) {
549c5131afeSKristof Provost parent = ruleset->anchor;
550c5131afeSKristof Provost break;
551c5131afeSKristof Provost }
552c5131afeSKristof Provost }
553c5131afeSKristof Provost if (q == NULL)
554c5131afeSKristof Provost q = p;
555c5131afeSKristof Provost else
556c5131afeSKristof Provost q++;
557c5131afeSKristof Provost strlcpy(p, path, MAXPATHLEN);
558c5131afeSKristof Provost if (!*q) {
559c5131afeSKristof Provost rs_free(p);
560c5131afeSKristof Provost return (NULL);
561c5131afeSKristof Provost }
562c5131afeSKristof Provost while ((r = strchr(q, '/')) != NULL || *q) {
563c5131afeSKristof Provost if (r != NULL)
564c5131afeSKristof Provost *r = 0;
565c5131afeSKristof Provost if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
566c5131afeSKristof Provost (parent != NULL && strlen(parent->path) >=
567c5131afeSKristof Provost MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
568c5131afeSKristof Provost rs_free(p);
569c5131afeSKristof Provost return (NULL);
570c5131afeSKristof Provost }
571c5131afeSKristof Provost anchor = (struct pf_keth_anchor *)rs_malloc(sizeof(*anchor));
572c5131afeSKristof Provost if (anchor == NULL) {
573c5131afeSKristof Provost rs_free(p);
574c5131afeSKristof Provost return (NULL);
575c5131afeSKristof Provost }
576c5131afeSKristof Provost RB_INIT(&anchor->children);
577c5131afeSKristof Provost strlcpy(anchor->name, q, sizeof(anchor->name));
578c5131afeSKristof Provost if (parent != NULL) {
579c5131afeSKristof Provost strlcpy(anchor->path, parent->path,
580c5131afeSKristof Provost sizeof(anchor->path));
581c5131afeSKristof Provost strlcat(anchor->path, "/", sizeof(anchor->path));
582c5131afeSKristof Provost }
583c5131afeSKristof Provost strlcat(anchor->path, anchor->name, sizeof(anchor->path));
584c5131afeSKristof Provost if ((dup = RB_INSERT(pf_keth_anchor_global, &V_pf_keth_anchors, anchor)) !=
585c5131afeSKristof Provost NULL) {
586c5131afeSKristof Provost printf("%s: RB_INSERT1 "
587c5131afeSKristof Provost "'%s' '%s' collides with '%s' '%s'\n", __func__,
588c5131afeSKristof Provost anchor->path, anchor->name, dup->path, dup->name);
589c5131afeSKristof Provost rs_free(anchor);
590c5131afeSKristof Provost rs_free(p);
591c5131afeSKristof Provost return (NULL);
592c5131afeSKristof Provost }
593c5131afeSKristof Provost if (parent != NULL) {
594c5131afeSKristof Provost anchor->parent = parent;
595c5131afeSKristof Provost if ((dup = RB_INSERT(pf_keth_anchor_node, &parent->children,
596c5131afeSKristof Provost anchor)) != NULL) {
597c5131afeSKristof Provost printf("%s: "
598c5131afeSKristof Provost "RB_INSERT2 '%s' '%s' collides with "
599c5131afeSKristof Provost "'%s' '%s'\n", __func__, anchor->path,
600c5131afeSKristof Provost anchor->name, dup->path, dup->name);
601c5131afeSKristof Provost RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors,
602c5131afeSKristof Provost anchor);
603c5131afeSKristof Provost rs_free(anchor);
604c5131afeSKristof Provost rs_free(p);
605c5131afeSKristof Provost return (NULL);
606c5131afeSKristof Provost }
607c5131afeSKristof Provost }
608c5131afeSKristof Provost pf_init_keth(&anchor->ruleset);
609c5131afeSKristof Provost anchor->ruleset.anchor = anchor;
610c5131afeSKristof Provost parent = anchor;
611c5131afeSKristof Provost if (r != NULL)
612c5131afeSKristof Provost q = r + 1;
613c5131afeSKristof Provost else
614c5131afeSKristof Provost *q = 0;
615c5131afeSKristof Provost }
616c5131afeSKristof Provost rs_free(p);
617c5131afeSKristof Provost return (&anchor->ruleset);
618c5131afeSKristof Provost }
619c5131afeSKristof Provost
620c5131afeSKristof Provost int
pf_keth_anchor_setup(struct pf_keth_rule * r,const struct pf_keth_ruleset * s,const char * name)621c5131afeSKristof Provost pf_keth_anchor_setup(struct pf_keth_rule *r, const struct pf_keth_ruleset *s,
622c5131afeSKristof Provost const char *name)
623c5131afeSKristof Provost {
624c5131afeSKristof Provost char *p, *path;
625c5131afeSKristof Provost struct pf_keth_ruleset *ruleset;
626c5131afeSKristof Provost
627c5131afeSKristof Provost r->anchor = NULL;
628c5131afeSKristof Provost r->anchor_relative = 0;
629c5131afeSKristof Provost r->anchor_wildcard = 0;
630c5131afeSKristof Provost if (!name[0])
631c5131afeSKristof Provost return (0);
632c5131afeSKristof Provost path = (char *)rs_malloc(MAXPATHLEN);
633c5131afeSKristof Provost if (path == NULL)
634c5131afeSKristof Provost return (1);
635c5131afeSKristof Provost if (name[0] == '/')
636c5131afeSKristof Provost strlcpy(path, name + 1, MAXPATHLEN);
637c5131afeSKristof Provost else {
638c5131afeSKristof Provost /* relative path */
639c5131afeSKristof Provost r->anchor_relative = 1;
640c5131afeSKristof Provost if (s->anchor == NULL || !s->anchor->path[0])
641c5131afeSKristof Provost path[0] = 0;
642c5131afeSKristof Provost else
643c5131afeSKristof Provost strlcpy(path, s->anchor->path, MAXPATHLEN);
644c5131afeSKristof Provost while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
645c5131afeSKristof Provost if (!path[0]) {
646c5131afeSKristof Provost DPFPRINTF("pf_anchor_setup: .. beyond root\n");
647c5131afeSKristof Provost rs_free(path);
648c5131afeSKristof Provost return (1);
649c5131afeSKristof Provost }
650c5131afeSKristof Provost if ((p = strrchr(path, '/')) != NULL)
651c5131afeSKristof Provost *p = 0;
652c5131afeSKristof Provost else
653c5131afeSKristof Provost path[0] = 0;
654c5131afeSKristof Provost r->anchor_relative++;
655c5131afeSKristof Provost name += 3;
656c5131afeSKristof Provost }
657c5131afeSKristof Provost if (path[0])
658c5131afeSKristof Provost strlcat(path, "/", MAXPATHLEN);
659c5131afeSKristof Provost strlcat(path, name, MAXPATHLEN);
660c5131afeSKristof Provost }
661c5131afeSKristof Provost if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
662c5131afeSKristof Provost r->anchor_wildcard = 1;
663c5131afeSKristof Provost *p = 0;
664c5131afeSKristof Provost }
665c5131afeSKristof Provost ruleset = pf_find_or_create_keth_ruleset(path);
666c5131afeSKristof Provost rs_free(path);
667c5131afeSKristof Provost if (ruleset == NULL || ruleset->anchor == NULL) {
668c5131afeSKristof Provost DPFPRINTF("pf_anchor_setup: ruleset\n");
669c5131afeSKristof Provost return (1);
670c5131afeSKristof Provost }
671c5131afeSKristof Provost r->anchor = ruleset->anchor;
672c5131afeSKristof Provost r->anchor->refcnt++;
673c5131afeSKristof Provost return (0);
674c5131afeSKristof Provost }
675c5131afeSKristof Provost
676c5131afeSKristof Provost void
pf_keth_anchor_remove(struct pf_keth_rule * r)677c5131afeSKristof Provost pf_keth_anchor_remove(struct pf_keth_rule *r)
678c5131afeSKristof Provost {
679c5131afeSKristof Provost if (r->anchor == NULL)
680c5131afeSKristof Provost return;
681c5131afeSKristof Provost if (r->anchor->refcnt <= 0) {
682c5131afeSKristof Provost printf("%s: broken refcount\n", __func__);
683c5131afeSKristof Provost r->anchor = NULL;
684c5131afeSKristof Provost return;
685c5131afeSKristof Provost }
686c5131afeSKristof Provost if (!--r->anchor->refcnt)
687c5131afeSKristof Provost pf_remove_if_empty_keth_ruleset(&r->anchor->ruleset);
688c5131afeSKristof Provost r->anchor = NULL;
689c5131afeSKristof Provost }
690c5131afeSKristof Provost
691c5131afeSKristof Provost void
pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset * ruleset)692c5131afeSKristof Provost pf_remove_if_empty_keth_ruleset(struct pf_keth_ruleset *ruleset)
693c5131afeSKristof Provost {
694c5131afeSKristof Provost struct pf_keth_anchor *parent;
695c5131afeSKristof Provost int i;
696c5131afeSKristof Provost
697c5131afeSKristof Provost while (ruleset != NULL) {
698c5131afeSKristof Provost if (ruleset == V_pf_keth || ruleset->anchor == NULL ||
699c5131afeSKristof Provost !RB_EMPTY(&ruleset->anchor->children) ||
700c5131afeSKristof Provost ruleset->anchor->refcnt > 0)
701c5131afeSKristof Provost return;
702c5131afeSKristof Provost for (i = 0; i < PF_RULESET_MAX; ++i)
703c5131afeSKristof Provost if (!TAILQ_EMPTY(ruleset->active.rules) ||
704c5131afeSKristof Provost !TAILQ_EMPTY(ruleset->inactive.rules) ||
705c5131afeSKristof Provost ruleset->inactive.open)
706c5131afeSKristof Provost return;
707c5131afeSKristof Provost RB_REMOVE(pf_keth_anchor_global, &V_pf_keth_anchors, ruleset->anchor);
708c5131afeSKristof Provost if ((parent = ruleset->anchor->parent) != NULL)
709c5131afeSKristof Provost RB_REMOVE(pf_keth_anchor_node, &parent->children,
710c5131afeSKristof Provost ruleset->anchor);
711c5131afeSKristof Provost rs_free(ruleset->anchor);
712c5131afeSKristof Provost if (parent == NULL)
713c5131afeSKristof Provost return;
714c5131afeSKristof Provost ruleset = &parent->ruleset;
715c5131afeSKristof Provost }
716c5131afeSKristof Provost }
717