pf_if.c revision 1.13 1 /* $NetBSD: pf_if.c,v 1.13 2007/12/05 01:11:24 dyoung Exp $ */
2 /* $OpenBSD: pf_if.c,v 1.23 2004/12/22 17:17:55 dhartmei Exp $ */
3
4 /*
5 * Copyright (c) 2001 Daniel Hartmeier
6 * Copyright (c) 2003 Cedric Berger
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #ifdef _KERNEL_OPT
35 #include "opt_inet.h"
36 #endif
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41 #include <sys/filio.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/time.h>
47
48 #include <net/if.h>
49 #include <net/if_types.h>
50
51 #include <netinet/in.h>
52 #include <netinet/in_var.h>
53 #include <netinet/in_systm.h>
54 #include <netinet/ip.h>
55 #include <netinet/ip_var.h>
56
57 #include <net/pfvar.h>
58
59 #ifdef INET6
60 #include <netinet/ip6.h>
61 #endif /* INET6 */
62
63 #define ACCEPT_FLAGS(oklist) \
64 do { \
65 if ((flags & ~(oklist)) & \
66 PFI_FLAG_ALLMASK) \
67 return (EINVAL); \
68 } while (0)
69
70 #define senderr(e) do { rv = (e); goto _bad; } while (0)
71
72 struct pfi_kif **pfi_index2kif;
73 struct pfi_kif *pfi_self;
74 int pfi_indexlim;
75 struct pfi_ifhead pfi_ifs;
76 struct pfi_statehead pfi_statehead;
77 int pfi_ifcnt;
78 struct pool pfi_addr_pl;
79 long pfi_update = 1;
80 struct pfr_addr *pfi_buffer;
81 int pfi_buffer_cnt;
82 int pfi_buffer_max;
83
84 void pfi_dynaddr_update(void *);
85 void pfi_kifaddr_update(void *);
86 #ifdef __NetBSD__
87 void pfi_kifaddr_update_if(struct ifnet *);
88 #endif
89 void pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
90 int, int);
91 void pfi_instance_add(struct ifnet *, int, int);
92 void pfi_address_add(struct sockaddr *, int, int);
93 int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
94 struct pfi_kif *pfi_if_create(const char *, struct pfi_kif *, int);
95 void pfi_copy_group(char *, const char *, int);
96 void pfi_newgroup(const char *, int);
97 int pfi_skip_if(const char *, struct pfi_kif *, int);
98 int pfi_unmask(void *);
99 void pfi_dohooks(struct pfi_kif *);
100
101 RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
102 RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
103
104 #define PFI_BUFFER_MAX 0x10000
105 #define PFI_MTYPE M_IFADDR
106
107 #ifdef __NetBSD__
108 static void *hook_establish(struct hook_desc_head *, int, void (*)(void *),
109 void *);
110 static void hook_disestablish(struct hook_desc_head *, void *);
111 static void dohooks(struct hook_desc_head *, int);
112
113 #define HOOK_REMOVE 0x01
114 #define HOOK_FREE 0x02
115 #endif
116
117 void
118 pfi_initialize(void)
119 {
120 if (pfi_self != NULL) /* already initialized */
121 return;
122
123 TAILQ_INIT(&pfi_statehead);
124 #ifdef __NetBSD__
125 pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
126 "pfiaddrpl", &pool_allocator_nointr, IPL_NONE);
127 #else
128 pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0,
129 "pfiaddrpl", &pool_allocator_nointr);
130 #endif
131 pfi_buffer_max = 64;
132 pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer),
133 PFI_MTYPE, M_WAITOK);
134 pfi_self = pfi_if_create("self", NULL, PFI_IFLAG_GROUP);
135 }
136
137 #ifdef _LKM
138 void
139 pfi_destroy(void)
140 {
141 pool_destroy(&pfi_addr_pl);
142
143 free(pfi_buffer, PFI_MTYPE);
144 }
145 #endif
146
147 void
148 pfi_attach_clone(struct if_clone *ifc)
149 {
150 pfi_initialize();
151 pfi_newgroup(ifc->ifc_name, PFI_IFLAG_CLONABLE);
152 }
153
154 void
155 pfi_attach_ifnet(struct ifnet *ifp)
156 {
157 struct pfi_kif *p, *q, key;
158 int s;
159
160 pfi_initialize();
161 s = splsoftnet();
162 pfi_update++;
163 if (ifp->if_index >= pfi_indexlim) {
164 /*
165 * grow pfi_index2kif, similar to ifindex2ifnet code in if.c
166 */
167 size_t m, n, oldlim;
168 struct pfi_kif **mp, **np;
169
170 oldlim = pfi_indexlim;
171 if (pfi_indexlim == 0)
172 pfi_indexlim = 64;
173 while (ifp->if_index >= pfi_indexlim)
174 pfi_indexlim <<= 1;
175
176 m = oldlim * sizeof(struct pfi_kif *);
177 mp = pfi_index2kif;
178 n = pfi_indexlim * sizeof(struct pfi_kif *);
179 np = malloc(n, PFI_MTYPE, M_DONTWAIT);
180 if (np == NULL)
181 panic("pfi_attach_ifnet: "
182 "cannot allocate translation table");
183 bzero(np, n);
184 if (mp != NULL)
185 bcopy(mp, np, m);
186 pfi_index2kif = np;
187 if (mp != NULL)
188 free(mp, PFI_MTYPE);
189 }
190
191 strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
192 p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
193 if (p == NULL) {
194 /* add group */
195 pfi_copy_group(key.pfik_name, ifp->if_xname,
196 sizeof(key.pfik_name));
197 q = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
198 if (q == NULL)
199 q = pfi_if_create(key.pfik_name, pfi_self, PFI_IFLAG_GROUP);
200 if (q == NULL)
201 panic("pfi_attach_ifnet: "
202 "cannot allocate '%s' group", key.pfik_name);
203
204 /* add interface */
205 p = pfi_if_create(ifp->if_xname, q, PFI_IFLAG_INSTANCE);
206 if (p == NULL)
207 panic("pfi_attach_ifnet: "
208 "cannot allocate '%s' interface", ifp->if_xname);
209 } else
210 q = p->pfik_parent;
211 p->pfik_ifp = ifp;
212 p->pfik_flags |= PFI_IFLAG_ATTACHED;
213 #ifdef __OpenBSD__
214 p->pfik_ah_cookie =
215 hook_establish(ifp->if_addrhooks, 1, pfi_kifaddr_update, p);
216 #else
217 p->pfik_ah_cookie =
218 hook_establish(&p->pfik_ifaddrhooks, 1, pfi_kifaddr_update, p);
219 #endif
220 pfi_index2kif[ifp->if_index] = p;
221 pfi_dohooks(p);
222 splx(s);
223 }
224
225 void
226 pfi_detach_ifnet(struct ifnet *ifp)
227 {
228 struct pfi_kif *p, *q, key;
229 int s;
230
231 strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
232
233 s = splsoftnet();
234 pfi_update++;
235 p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
236 if (p == NULL) {
237 printf("pfi_detach_ifnet: cannot find %s", ifp->if_xname);
238 splx(s);
239 return;
240 }
241 #ifdef __OpenBSD__
242 hook_disestablish(p->pfik_ifp->if_addrhooks, p->pfik_ah_cookie);
243 #else
244 hook_disestablish(&p->pfik_ifaddrhooks, p->pfik_ah_cookie);
245 #endif
246 q = p->pfik_parent;
247 p->pfik_ifp = NULL;
248 p->pfik_flags &= ~PFI_IFLAG_ATTACHED;
249 pfi_index2kif[ifp->if_index] = NULL;
250 pfi_dohooks(p);
251 pfi_maybe_destroy(p);
252 splx(s);
253 }
254
255 struct pfi_kif *
256 pfi_lookup_create(const char *name)
257 {
258 struct pfi_kif *p, *q, key;
259 int s;
260
261 s = splsoftnet();
262 p = pfi_lookup_if(name);
263 if (p == NULL) {
264 pfi_copy_group(key.pfik_name, name, sizeof(key.pfik_name));
265 q = pfi_lookup_if(key.pfik_name);
266 if (q == NULL) {
267 pfi_newgroup(key.pfik_name, PFI_IFLAG_DYNAMIC);
268 q = pfi_lookup_if(key.pfik_name);
269 }
270 p = pfi_lookup_if(name);
271 if (p == NULL && q != NULL)
272 p = pfi_if_create(name, q, PFI_IFLAG_INSTANCE);
273 }
274 splx(s);
275 return (p);
276 }
277
278 struct pfi_kif *
279 pfi_attach_rule(const char *name)
280 {
281 struct pfi_kif *p;
282
283 p = pfi_lookup_create(name);
284 if (p != NULL)
285 p->pfik_rules++;
286 return (p);
287 }
288
289 void
290 pfi_detach_rule(struct pfi_kif *p)
291 {
292 if (p == NULL)
293 return;
294 if (p->pfik_rules > 0)
295 p->pfik_rules--;
296 else
297 printf("pfi_detach_rule: reference count at 0\n");
298 pfi_maybe_destroy(p);
299 }
300
301 void
302 pfi_attach_state(struct pfi_kif *p)
303 {
304 if (!p->pfik_states++)
305 TAILQ_INSERT_TAIL(&pfi_statehead, p, pfik_w_states);
306 }
307
308 void
309 pfi_detach_state(struct pfi_kif *p)
310 {
311 if (p == NULL)
312 return;
313 if (p->pfik_states <= 0) {
314 printf("pfi_detach_state: reference count <= 0\n");
315 return;
316 }
317 if (!--p->pfik_states)
318 TAILQ_REMOVE(&pfi_statehead, p, pfik_w_states);
319 pfi_maybe_destroy(p);
320 }
321
322 int
323 pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
324 {
325 struct pfi_dynaddr *dyn;
326 char tblname[PF_TABLE_NAME_SIZE];
327 struct pf_ruleset *ruleset = NULL;
328 int s, rv = 0;
329
330 if (aw->type != PF_ADDR_DYNIFTL)
331 return (0);
332 dyn = pool_get(&pfi_addr_pl, PR_NOWAIT);
333 if (dyn == NULL)
334 return (1);
335 bzero(dyn, sizeof(*dyn));
336
337 s = splsoftnet();
338 dyn->pfid_kif = pfi_attach_rule(aw->v.ifname);
339 if (dyn->pfid_kif == NULL)
340 senderr(1);
341
342 dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
343 if (af == AF_INET && dyn->pfid_net == 32)
344 dyn->pfid_net = 128;
345 strlcpy(tblname, aw->v.ifname, sizeof(tblname));
346 if (aw->iflags & PFI_AFLAG_NETWORK)
347 strlcat(tblname, ":network", sizeof(tblname));
348 if (aw->iflags & PFI_AFLAG_BROADCAST)
349 strlcat(tblname, ":broadcast", sizeof(tblname));
350 if (aw->iflags & PFI_AFLAG_PEER)
351 strlcat(tblname, ":peer", sizeof(tblname));
352 if (aw->iflags & PFI_AFLAG_NOALIAS)
353 strlcat(tblname, ":0", sizeof(tblname));
354 if (dyn->pfid_net != 128)
355 snprintf(tblname + strlen(tblname),
356 sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
357 ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR);
358 if (ruleset == NULL)
359 senderr(1);
360
361 dyn->pfid_kt = pfr_attach_table(ruleset, tblname);
362 if (dyn->pfid_kt == NULL)
363 senderr(1);
364
365 dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
366 dyn->pfid_iflags = aw->iflags;
367 dyn->pfid_af = af;
368 dyn->pfid_hook_cookie = hook_establish(dyn->pfid_kif->pfik_ah_head, 1,
369 pfi_dynaddr_update, dyn);
370 if (dyn->pfid_hook_cookie == NULL)
371 senderr(1);
372
373 aw->p.dyn = dyn;
374 pfi_dynaddr_update(aw->p.dyn);
375 splx(s);
376 return (0);
377
378 _bad:
379 if (dyn->pfid_kt != NULL)
380 pfr_detach_table(dyn->pfid_kt);
381 if (ruleset != NULL)
382 pf_remove_if_empty_ruleset(ruleset);
383 if (dyn->pfid_kif != NULL)
384 pfi_detach_rule(dyn->pfid_kif);
385 pool_put(&pfi_addr_pl, dyn);
386 splx(s);
387 return (rv);
388 }
389
390 void
391 pfi_dynaddr_update(void *p)
392 {
393 struct pfi_dynaddr *dyn = (struct pfi_dynaddr *)p;
394 struct pfi_kif *kif;
395 struct pfr_ktable *kt;
396
397 if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
398 panic("pfi_dynaddr_update");
399
400 kif = dyn->pfid_kif;
401 kt = dyn->pfid_kt;
402 if (kt->pfrkt_larg != pfi_update) {
403 /* this table needs to be brought up-to-date */
404 pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
405 kt->pfrkt_larg = pfi_update;
406 }
407 pfr_dynaddr_update(kt, dyn);
408 }
409
410 void
411 pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
412 {
413 int e, size2 = 0;
414 struct pfi_kif *p;
415 struct pfr_table t;
416
417 if ((kif->pfik_flags & PFI_IFLAG_INSTANCE) && kif->pfik_ifp == NULL) {
418 pfr_clr_addrs(&kt->pfrkt_t, NULL, 0);
419 return;
420 }
421 pfi_buffer_cnt = 0;
422 if ((kif->pfik_flags & PFI_IFLAG_INSTANCE))
423 pfi_instance_add(kif->pfik_ifp, net, flags);
424 else if (strcmp(kif->pfik_name, "self")) {
425 TAILQ_FOREACH(p, &kif->pfik_grouphead, pfik_instances)
426 pfi_instance_add(p->pfik_ifp, net, flags);
427 } else {
428 RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
429 if (p->pfik_flags & PFI_IFLAG_INSTANCE)
430 pfi_instance_add(p->pfik_ifp, net, flags);
431 }
432 t = kt->pfrkt_t;
433 t.pfrt_flags = 0;
434 if ((e = pfr_set_addrs(&t, pfi_buffer, pfi_buffer_cnt, &size2,
435 NULL, NULL, NULL, 0)))
436 printf("pfi_table_update: cannot set %d new addresses "
437 "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e);
438 }
439
440 void
441 pfi_instance_add(struct ifnet *ifp, int net, int flags)
442 {
443 struct ifaddr *ia;
444 int got4 = 0, got6 = 0;
445 int net2, af;
446
447 if (ifp == NULL)
448 return;
449 IFADDR_FOREACH(ia, ifp) {
450 if (ia->ifa_addr == NULL)
451 continue;
452 af = ia->ifa_addr->sa_family;
453 if (af != AF_INET && af != AF_INET6)
454 continue;
455 if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
456 continue;
457 if ((flags & PFI_AFLAG_BROADCAST) &&
458 !(ifp->if_flags & IFF_BROADCAST))
459 continue;
460 if ((flags & PFI_AFLAG_PEER) &&
461 !(ifp->if_flags & IFF_POINTOPOINT))
462 continue;
463 if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
464 IN6_IS_ADDR_LINKLOCAL(
465 &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
466 continue;
467 if (flags & PFI_AFLAG_NOALIAS) {
468 if (af == AF_INET && got4)
469 continue;
470 if (af == AF_INET6 && got6)
471 continue;
472 }
473 if (af == AF_INET)
474 got4 = 1;
475 else if (af == AF_INET6)
476 got6 = 1;
477 net2 = net;
478 if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
479 if (af == AF_INET) {
480 net2 = pfi_unmask(&((struct sockaddr_in *)
481 ia->ifa_netmask)->sin_addr);
482 } else if (af == AF_INET6) {
483 net2 = pfi_unmask(&((struct sockaddr_in6 *)
484 ia->ifa_netmask)->sin6_addr);
485 }
486 }
487 if (af == AF_INET && net2 > 32)
488 net2 = 32;
489 if (flags & PFI_AFLAG_BROADCAST)
490 pfi_address_add(ia->ifa_broadaddr, af, net2);
491 else if (flags & PFI_AFLAG_PEER)
492 pfi_address_add(ia->ifa_dstaddr, af, net2);
493 else
494 pfi_address_add(ia->ifa_addr, af, net2);
495 }
496 }
497
498 void
499 pfi_address_add(struct sockaddr *sa, int af, int net)
500 {
501 struct pfr_addr *p;
502 int i;
503
504 if (pfi_buffer_cnt >= pfi_buffer_max) {
505 int new_max = pfi_buffer_max * 2;
506
507 if (new_max > PFI_BUFFER_MAX) {
508 printf("pfi_address_add: address buffer full (%d/%d)\n",
509 pfi_buffer_cnt, PFI_BUFFER_MAX);
510 return;
511 }
512 p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE,
513 M_DONTWAIT);
514 if (p == NULL) {
515 printf("pfi_address_add: no memory to grow buffer "
516 "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX);
517 return;
518 }
519 memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
520 /* no need to zero buffer */
521 free(pfi_buffer, PFI_MTYPE);
522 pfi_buffer = p;
523 pfi_buffer_max = new_max;
524 }
525 if (af == AF_INET && net > 32)
526 net = 128;
527 p = pfi_buffer + pfi_buffer_cnt++;
528 bzero(p, sizeof(*p));
529 p->pfra_af = af;
530 p->pfra_net = net;
531 if (af == AF_INET)
532 p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
533 if (af == AF_INET6) {
534 p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
535 if (IN6_IS_ADDR_LINKLOCAL(&p->pfra_ip6addr))
536 p->pfra_ip6addr.s6_addr16[1] = 0;
537 }
538 /* mask network address bits */
539 if (net < 128)
540 ((char *)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
541 for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
542 ((char *)p)[i] = 0;
543 }
544
545 void
546 pfi_dynaddr_remove(struct pf_addr_wrap *aw)
547 {
548 int s;
549
550 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
551 aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
552 return;
553
554 s = splsoftnet();
555 hook_disestablish(aw->p.dyn->pfid_kif->pfik_ah_head,
556 aw->p.dyn->pfid_hook_cookie);
557 pfi_detach_rule(aw->p.dyn->pfid_kif);
558 aw->p.dyn->pfid_kif = NULL;
559 pfr_detach_table(aw->p.dyn->pfid_kt);
560 aw->p.dyn->pfid_kt = NULL;
561 pool_put(&pfi_addr_pl, aw->p.dyn);
562 aw->p.dyn = NULL;
563 splx(s);
564 }
565
566 void
567 pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
568 {
569 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
570 aw->p.dyn->pfid_kif == NULL)
571 return;
572 aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
573 }
574
575 void
576 pfi_kifaddr_update(void *v)
577 {
578 int s;
579
580 s = splsoftnet();
581 pfi_update++;
582 pfi_dohooks(v);
583 splx(s);
584 }
585
586 #ifdef __NetBSD__
587 void
588 pfi_kifaddr_update_if(struct ifnet *ifp)
589 {
590 struct pfi_kif *p;
591
592 p = pfi_lookup_if(ifp->if_xname);
593 if (p == NULL)
594 panic("can't find interface");
595 pfi_kifaddr_update(p);
596 }
597 #endif
598
599 int
600 pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
601 {
602 return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
603 }
604
605 struct pfi_kif *
606 pfi_if_create(const char *name, struct pfi_kif *q, int flags)
607 {
608 struct pfi_kif *p;
609
610 p = malloc(sizeof(*p), PFI_MTYPE, M_DONTWAIT);
611 if (p == NULL)
612 return (NULL);
613 bzero(p, sizeof(*p));
614 p->pfik_ah_head = malloc(sizeof(*p->pfik_ah_head), PFI_MTYPE,
615 M_DONTWAIT);
616 if (p->pfik_ah_head == NULL) {
617 free(p, PFI_MTYPE);
618 return (NULL);
619 }
620 bzero(p->pfik_ah_head, sizeof(*p->pfik_ah_head));
621 TAILQ_INIT(p->pfik_ah_head);
622 TAILQ_INIT(&p->pfik_grouphead);
623 #ifdef __NetBSD__
624 bzero(&p->pfik_ifaddrhooks, sizeof(p->pfik_ifaddrhooks));
625 TAILQ_INIT(&p->pfik_ifaddrhooks);
626 #endif
627 strlcpy(p->pfik_name, name, sizeof(p->pfik_name));
628 RB_INIT(&p->pfik_lan_ext);
629 RB_INIT(&p->pfik_ext_gwy);
630 p->pfik_flags = flags;
631 p->pfik_parent = q;
632 p->pfik_tzero = time_second;
633
634 RB_INSERT(pfi_ifhead, &pfi_ifs, p);
635 if (q != NULL) {
636 q->pfik_addcnt++;
637 TAILQ_INSERT_TAIL(&q->pfik_grouphead, p, pfik_instances);
638 }
639 pfi_ifcnt++;
640 return (p);
641 }
642
643 int
644 pfi_maybe_destroy(struct pfi_kif *p)
645 {
646 int i, j, k, s;
647 struct pfi_kif *q = p->pfik_parent;
648
649 if ((p->pfik_flags & (PFI_IFLAG_ATTACHED | PFI_IFLAG_GROUP)) ||
650 p->pfik_rules > 0 || p->pfik_states > 0)
651 return (0);
652
653 s = splsoftnet();
654 if (q != NULL) {
655 for (i = 0; i < 2; i++)
656 for (j = 0; j < 2; j++)
657 for (k = 0; k < 2; k++) {
658 q->pfik_bytes[i][j][k] +=
659 p->pfik_bytes[i][j][k];
660 q->pfik_packets[i][j][k] +=
661 p->pfik_packets[i][j][k];
662 }
663 q->pfik_delcnt++;
664 TAILQ_REMOVE(&q->pfik_grouphead, p, pfik_instances);
665 }
666 pfi_ifcnt--;
667 RB_REMOVE(pfi_ifhead, &pfi_ifs, p);
668 splx(s);
669
670 free(p->pfik_ah_head, PFI_MTYPE);
671 free(p, PFI_MTYPE);
672 return (1);
673 }
674
675 void
676 pfi_copy_group(char *p, const char *q, int m)
677 {
678 while (m > 1 && *q && !(*q >= '0' && *q <= '9')) {
679 *p++ = *q++;
680 m--;
681 }
682 if (m > 0)
683 *p++ = '\0';
684 }
685
686 void
687 pfi_newgroup(const char *name, int flags)
688 {
689 struct pfi_kif *p;
690
691 p = pfi_lookup_if(name);
692 if (p == NULL)
693 p = pfi_if_create(name, pfi_self, PFI_IFLAG_GROUP);
694 if (p == NULL) {
695 printf("pfi_newgroup: cannot allocate '%s' group", name);
696 return;
697 }
698 p->pfik_flags |= flags;
699 }
700
701 void
702 pfi_fill_oldstatus(struct pf_status *pfs)
703 {
704 struct pfi_kif *p, key;
705 int i, j, k, s;
706
707 strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name));
708 s = splsoftnet();
709 p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
710 if (p == NULL) {
711 splx(s);
712 return;
713 }
714 bzero(pfs->pcounters, sizeof(pfs->pcounters));
715 bzero(pfs->bcounters, sizeof(pfs->bcounters));
716 for (i = 0; i < 2; i++)
717 for (j = 0; j < 2; j++)
718 for (k = 0; k < 2; k++) {
719 pfs->pcounters[i][j][k] =
720 p->pfik_packets[i][j][k];
721 pfs->bcounters[i][j] +=
722 p->pfik_bytes[i][j][k];
723 }
724 splx(s);
725 }
726
727 int
728 pfi_clr_istats(const char *name, int *nzero, int flags)
729 {
730 struct pfi_kif *p;
731 int n = 0, s;
732 long tzero = time_second;
733
734 ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
735 s = splsoftnet();
736 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
737 if (pfi_skip_if(name, p, flags))
738 continue;
739 bzero(p->pfik_packets, sizeof(p->pfik_packets));
740 bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
741 p->pfik_tzero = tzero;
742 n++;
743 }
744 splx(s);
745 if (nzero != NULL)
746 *nzero = n;
747 return (0);
748 }
749
750 int
751 pfi_set_flags(const char *name, int flags)
752 {
753 struct pfi_kif *p;
754 int s;
755
756 if (flags & ~PFI_IFLAG_SETABLE_MASK)
757 return (EINVAL);
758
759 s = splsoftnet();
760 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
761 if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
762 continue;
763 p->pfik_flags |= flags;
764 }
765 splx(s);
766 return (0);
767 }
768
769 int
770 pfi_clear_flags(const char *name, int flags)
771 {
772 struct pfi_kif *p;
773 int s;
774
775 if (flags & ~PFI_IFLAG_SETABLE_MASK)
776 return (EINVAL);
777
778 s = splsoftnet();
779 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
780 if (pfi_skip_if(name, p, PFI_FLAG_GROUP|PFI_FLAG_INSTANCE))
781 continue;
782 p->pfik_flags &= ~flags;
783 }
784 splx(s);
785 return (0);
786 }
787
788 int
789 pfi_get_ifaces(const char *name, struct pfi_if *buf, int *size, int flags)
790 {
791 struct pfi_kif *p;
792 int s, n = 0;
793
794 ACCEPT_FLAGS(PFI_FLAG_GROUP|PFI_FLAG_INSTANCE);
795 s = splsoftnet();
796 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
797 if (pfi_skip_if(name, p, flags))
798 continue;
799 if (*size > n++) {
800 if (!p->pfik_tzero)
801 p->pfik_tzero = time_second;
802 if (copyout(p, buf++, sizeof(*buf))) {
803 splx(s);
804 return (EFAULT);
805 }
806 }
807 }
808 splx(s);
809 *size = n;
810 return (0);
811 }
812
813 struct pfi_kif *
814 pfi_lookup_if(const char *name)
815 {
816 struct pfi_kif *p, key;
817
818 strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
819 p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
820 return (p);
821 }
822
823 int
824 pfi_skip_if(const char *filter, struct pfi_kif *p, int f)
825 {
826 int n;
827
828 if ((p->pfik_flags & PFI_IFLAG_GROUP) && !(f & PFI_FLAG_GROUP))
829 return (1);
830 if ((p->pfik_flags & PFI_IFLAG_INSTANCE) && !(f & PFI_FLAG_INSTANCE))
831 return (1);
832 if (filter == NULL || !*filter)
833 return (0);
834 if (!strcmp(p->pfik_name, filter))
835 return (0); /* exact match */
836 n = strlen(filter);
837 if (n < 1 || n >= IFNAMSIZ)
838 return (1); /* sanity check */
839 if (filter[n-1] >= '0' && filter[n-1] <= '9')
840 return (1); /* only do exact match in that case */
841 if (strncmp(p->pfik_name, filter, n))
842 return (1); /* prefix doesn't match */
843 return (p->pfik_name[n] < '0' || p->pfik_name[n] > '9');
844 }
845
846 /* from pf_print_state.c */
847 int
848 pfi_unmask(void *addr)
849 {
850 struct pf_addr *m = addr;
851 int i = 31, j = 0, b = 0;
852 u_int32_t tmp;
853
854 while (j < 4 && m->addr32[j] == 0xffffffff) {
855 b += 32;
856 j++;
857 }
858 if (j < 4) {
859 tmp = ntohl(m->addr32[j]);
860 for (i = 31; tmp & (1 << i); --i)
861 b++;
862 }
863 return (b);
864 }
865
866 void
867 pfi_dohooks(struct pfi_kif *p)
868 {
869 for (; p != NULL; p = p->pfik_parent)
870 dohooks(p->pfik_ah_head, 0);
871 }
872
873 int
874 pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
875 {
876 switch (af) {
877 #ifdef INET
878 case AF_INET:
879 switch (dyn->pfid_acnt4) {
880 case 0:
881 return (0);
882 case 1:
883 return (PF_MATCHA(0, &dyn->pfid_addr4,
884 &dyn->pfid_mask4, a, AF_INET));
885 default:
886 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
887 }
888 break;
889 #endif /* INET */
890 #ifdef INET6
891 case AF_INET6:
892 switch (dyn->pfid_acnt6) {
893 case 0:
894 return (0);
895 case 1:
896 return (PF_MATCHA(0, &dyn->pfid_addr6,
897 &dyn->pfid_mask6, a, AF_INET6));
898 default:
899 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
900 }
901 break;
902 #endif /* INET6 */
903 default:
904 return (0);
905 }
906 }
907
908 /* from openbsd/sys/kern/kern_subr.c */
909 #ifdef __NetBSD__
910 static void *
911 hook_establish(struct hook_desc_head *head, int tail, void (*fn)(void *),
912 void *arg)
913 {
914 struct hook_desc *hdp;
915
916 hdp = (struct hook_desc *)malloc(sizeof (*hdp), M_DEVBUF, M_NOWAIT);
917 if (hdp == NULL)
918 return (NULL);
919
920 hdp->hd_fn = fn;
921 hdp->hd_arg = arg;
922 if (tail)
923 TAILQ_INSERT_TAIL(head, hdp, hd_list);
924 else
925 TAILQ_INSERT_HEAD(head, hdp, hd_list);
926
927 return (hdp);
928 }
929
930 static void
931 hook_disestablish(struct hook_desc_head *head, void *vhook)
932 {
933 struct hook_desc *hdp;
934
935 #ifdef DIAGNOSTIC
936 for (hdp = TAILQ_FIRST(head); hdp != NULL;
937 hdp = TAILQ_NEXT(hdp, hd_list))
938 if (hdp == vhook)
939 break;
940 if (hdp == NULL)
941 panic("hook_disestablish: hook not established");
942 #endif
943 hdp = vhook;
944 TAILQ_REMOVE(head, hdp, hd_list);
945 free(hdp, M_DEVBUF);
946 }
947
948 static void
949 dohooks(struct hook_desc_head *head, int flags)
950 {
951 struct hook_desc *hdp;
952
953 if ((flags & HOOK_REMOVE) == 0) {
954 TAILQ_FOREACH(hdp, head, hd_list) {
955 (*hdp->hd_fn)(hdp->hd_arg);
956 }
957 } else {
958 while ((hdp = TAILQ_FIRST(head)) != NULL) {
959 TAILQ_REMOVE(head, hdp, hd_list);
960 (*hdp->hd_fn)(hdp->hd_arg);
961 if ((flags & HOOK_FREE) != 0)
962 free(hdp, M_DEVBUF);
963 }
964 }
965 }
966 #endif
967