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