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