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