1*062cda8bSmvs /* $OpenBSD: pf_if.c,v 1.111 2023/06/30 09:58:30 mvs Exp $ */
23446b247Scedric
33446b247Scedric /*
4c1f13696Shenning * Copyright 2005 Henning Brauer <henning@openbsd.org>
5c1f13696Shenning * Copyright 2005 Ryan McBride <mcbride@openbsd.org>
63446b247Scedric * Copyright (c) 2001 Daniel Hartmeier
7ec359bd5Scedric * Copyright (c) 2003 Cedric Berger
83446b247Scedric * All rights reserved.
93446b247Scedric *
103446b247Scedric * Redistribution and use in source and binary forms, with or without
113446b247Scedric * modification, are permitted provided that the following conditions
123446b247Scedric * are met:
133446b247Scedric *
143446b247Scedric * - Redistributions of source code must retain the above copyright
153446b247Scedric * notice, this list of conditions and the following disclaimer.
163446b247Scedric * - Redistributions in binary form must reproduce the above
173446b247Scedric * copyright notice, this list of conditions and the following
183446b247Scedric * disclaimer in the documentation and/or other materials provided
193446b247Scedric * with the distribution.
203446b247Scedric *
213446b247Scedric * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
223446b247Scedric * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
233446b247Scedric * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
243446b247Scedric * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
253446b247Scedric * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
263446b247Scedric * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
273446b247Scedric * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
283446b247Scedric * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
293446b247Scedric * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303446b247Scedric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
313446b247Scedric * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
323446b247Scedric * POSSIBILITY OF SUCH DAMAGE.
333446b247Scedric */
343446b247Scedric
353446b247Scedric #include <sys/param.h>
363446b247Scedric #include <sys/systm.h>
373446b247Scedric #include <sys/mbuf.h>
383446b247Scedric #include <sys/filio.h>
393446b247Scedric #include <sys/socket.h>
403446b247Scedric #include <sys/socketvar.h>
413446b247Scedric #include <sys/kernel.h>
42ec359bd5Scedric #include <sys/device.h>
433446b247Scedric #include <sys/time.h>
448efe75c5Shenning #include <sys/pool.h>
45a2fdc13dSmcbride #include <sys/syslog.h>
463446b247Scedric
473446b247Scedric #include <net/if.h>
480deb6685Smpi #include <net/if_var.h>
493446b247Scedric
503446b247Scedric #include <netinet/in.h>
513446b247Scedric #include <netinet/ip.h>
523446b247Scedric #include <netinet/ip_var.h>
533446b247Scedric
543446b247Scedric #include <net/pfvar.h>
553446b247Scedric
566c44725cSsashan #include <netinet/ip_icmp.h>
576c44725cSsashan #include <netinet/tcp.h>
586c44725cSsashan #include <netinet/udp.h>
596c44725cSsashan
603446b247Scedric #ifdef INET6
613446b247Scedric #include <netinet/ip6.h>
626c44725cSsashan #include <netinet/icmp6.h>
633446b247Scedric #endif /* INET6 */
643446b247Scedric
656c44725cSsashan #include <net/pfvar_priv.h>
666c44725cSsashan
67840840b0Ssashan #define isupper(c) ((c) >= 'A' && (c) <= 'Z')
68840840b0Ssashan #define islower(c) ((c) >= 'a' && (c) <= 'z')
69840840b0Ssashan #define isalpha(c) (isupper(c)||islower(c))
70840840b0Ssashan
71c1f13696Shenning struct pfi_kif *pfi_all = NULL;
72ec359bd5Scedric struct pool pfi_addr_pl;
73c1f13696Shenning struct pfi_ifhead pfi_ifs;
74ec359bd5Scedric long pfi_update = 1;
75ec359bd5Scedric struct pfr_addr *pfi_buffer;
76ec359bd5Scedric int pfi_buffer_cnt;
77ec359bd5Scedric int pfi_buffer_max;
783446b247Scedric
79aee130d6Shenning void pfi_kif_update(struct pfi_kif *);
8045bdb168Shenning void pfi_dynaddr_update(struct pfi_dynaddr *dyn);
81ec359bd5Scedric void pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
82a17121a6Ssashan u_int8_t, int);
83c1f13696Shenning void pfi_kifaddr_update(void *);
84a17121a6Ssashan void pfi_instance_add(struct ifnet *, u_int8_t, int);
85a17121a6Ssashan void pfi_address_add(struct sockaddr *, sa_family_t, u_int8_t);
86342c264fSdlg int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
87c1f13696Shenning int pfi_skip_if(const char *, struct pfi_kif *);
88ec359bd5Scedric int pfi_unmask(void *);
89840840b0Ssashan void pfi_group_change(const char *);
90ec359bd5Scedric
91342c264fSdlg RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
92342c264fSdlg RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
93ec359bd5Scedric
94ec359bd5Scedric #define PFI_BUFFER_MAX 0x10000
95*062cda8bSmvs #define PFI_MTYPE M_PF
96ec359bd5Scedric
97c97e8838Ssashan struct pfi_kif *
pfi_kif_alloc(const char * kif_name,int mflags)98c97e8838Ssashan pfi_kif_alloc(const char *kif_name, int mflags)
99c97e8838Ssashan {
100c97e8838Ssashan struct pfi_kif *kif;
101c97e8838Ssashan
102c97e8838Ssashan kif = malloc(sizeof(*pfi_all), PFI_MTYPE, mflags|M_ZERO);
103b8dc7befSbluhm if (kif == NULL)
104b8dc7befSbluhm return (NULL);
105c97e8838Ssashan strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
106c97e8838Ssashan kif->pfik_tzero = gettime();
107c97e8838Ssashan TAILQ_INIT(&kif->pfik_dynaddrs);
108c97e8838Ssashan
109c97e8838Ssashan if (!strcmp(kif->pfik_name, "any")) {
110c97e8838Ssashan /* both so it works in the ioctl and the regular case */
111c97e8838Ssashan kif->pfik_flags |= PFI_IFLAG_ANY;
112c97e8838Ssashan kif->pfik_flags_new |= PFI_IFLAG_ANY;
113c97e8838Ssashan }
114c97e8838Ssashan
115c97e8838Ssashan return (kif);
116c97e8838Ssashan }
117c97e8838Ssashan
118c97e8838Ssashan void
pfi_kif_free(struct pfi_kif * kif)119c97e8838Ssashan pfi_kif_free(struct pfi_kif *kif)
120c97e8838Ssashan {
121c97e8838Ssashan if (kif == NULL)
122c97e8838Ssashan return;
123c97e8838Ssashan
124655f9804Ssashan if (kif->pfik_rules || kif->pfik_states || kif->pfik_routes ||
125840840b0Ssashan kif->pfik_srcnodes || kif->pfik_flagrefs)
126c97e8838Ssashan panic("kif is still alive");
127c97e8838Ssashan
128c97e8838Ssashan free(kif, PFI_MTYPE, sizeof(*kif));
129c97e8838Ssashan }
130c97e8838Ssashan
131ec359bd5Scedric void
pfi_initialize(void)132ec359bd5Scedric pfi_initialize(void)
133ec359bd5Scedric {
134c97e8838Ssashan /*
135c97e8838Ssashan * The first time we arrive here is during kernel boot,
136c97e8838Ssashan * when if_attachsetup() for the first time. No locking
137c97e8838Ssashan * is needed in this case, because it's granted there
138c97e8838Ssashan * is a single thread, which sets pfi_all global var.
139c97e8838Ssashan */
140c1f13696Shenning if (pfi_all != NULL) /* already initialized */
141ec359bd5Scedric return;
142ec359bd5Scedric
1431378bae2Sdlg pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, IPL_SOFTNET, 0,
1448a718aebSkettenis "pfiaddrpl", NULL);
145ec359bd5Scedric pfi_buffer_max = 64;
14683bfce96Stedu pfi_buffer = mallocarray(pfi_buffer_max, sizeof(*pfi_buffer),
147ec359bd5Scedric PFI_MTYPE, M_WAITOK);
148c1f13696Shenning
149c97e8838Ssashan pfi_all = pfi_kif_alloc(IFG_ALL, M_WAITOK);
150c97e8838Ssashan
151c97e8838Ssashan if (RB_INSERT(pfi_ifhead, &pfi_ifs, pfi_all) != NULL)
152c97e8838Ssashan panic("IFG_ALL kif found already");
153c1f13696Shenning }
154c1f13696Shenning
155c1f13696Shenning struct pfi_kif *
pfi_kif_find(const char * kif_name)156f4af82b9Smikeb pfi_kif_find(const char *kif_name)
157c1f13696Shenning {
1584a3452fdSpascoe struct pfi_kif_cmp s;
159c1f13696Shenning
160128c3c8cSkn PF_ASSERT_LOCKED();
161128c3c8cSkn
162568ff528Shenning memset(&s, 0, sizeof(s));
163c1f13696Shenning strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name));
164342c264fSdlg return (RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s));
165f4af82b9Smikeb }
166f4af82b9Smikeb
167f4af82b9Smikeb struct pfi_kif *
pfi_kif_get(const char * kif_name,struct pfi_kif ** prealloc)168c97e8838Ssashan pfi_kif_get(const char *kif_name, struct pfi_kif **prealloc)
169f4af82b9Smikeb {
170f4af82b9Smikeb struct pfi_kif *kif;
171f4af82b9Smikeb
172128c3c8cSkn PF_ASSERT_LOCKED();
173128c3c8cSkn
174f4af82b9Smikeb if ((kif = pfi_kif_find(kif_name)))
175c1f13696Shenning return (kif);
176c1f13696Shenning
177c1f13696Shenning /* create new one */
178c97e8838Ssashan if ((prealloc == NULL) || (*prealloc == NULL)) {
179c97e8838Ssashan kif = pfi_kif_alloc(kif_name, M_NOWAIT);
180c97e8838Ssashan if (kif == NULL)
181c1f13696Shenning return (NULL);
182c97e8838Ssashan } else {
183c97e8838Ssashan kif = *prealloc;
184c97e8838Ssashan *prealloc = NULL;
1854be478ceShenning }
1864be478ceShenning
187342c264fSdlg RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
188c1f13696Shenning return (kif);
189ec359bd5Scedric }
190ec359bd5Scedric
191ec359bd5Scedric void
pfi_kif_ref(struct pfi_kif * kif,enum pfi_kif_refs what)192c1f13696Shenning pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
193ec359bd5Scedric {
194128c3c8cSkn PF_ASSERT_LOCKED();
195128c3c8cSkn
196c1f13696Shenning switch (what) {
197c1f13696Shenning case PFI_KIF_REF_RULE:
198c1f13696Shenning kif->pfik_rules++;
199c1f13696Shenning break;
200c1f13696Shenning case PFI_KIF_REF_STATE:
201a4d96804Smarkus kif->pfik_states++;
202c1f13696Shenning break;
20336754172Smcbride case PFI_KIF_REF_ROUTE:
20436754172Smcbride kif->pfik_routes++;
20536754172Smcbride break;
2061c2f8232Syasuoka case PFI_KIF_REF_SRCNODE:
2071c2f8232Syasuoka kif->pfik_srcnodes++;
2081c2f8232Syasuoka break;
209840840b0Ssashan case PFI_KIF_REF_FLAG:
210840840b0Ssashan kif->pfik_flagrefs++;
211840840b0Ssashan break;
212c1f13696Shenning default:
213c1f13696Shenning panic("pfi_kif_ref with unknown type");
214c1f13696Shenning }
215c1f13696Shenning }
216c1f13696Shenning
217c1f13696Shenning void
pfi_kif_unref(struct pfi_kif * kif,enum pfi_kif_refs what)218c1f13696Shenning pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
219c1f13696Shenning {
220c1f13696Shenning if (kif == NULL)
221c1f13696Shenning return;
222c1f13696Shenning
223128c3c8cSkn PF_ASSERT_LOCKED();
224128c3c8cSkn
225c1f13696Shenning switch (what) {
226c1f13696Shenning case PFI_KIF_REF_NONE:
227c1f13696Shenning break;
228c1f13696Shenning case PFI_KIF_REF_RULE:
229c1f13696Shenning if (kif->pfik_rules <= 0) {
230a2fdc13dSmcbride DPFPRINTF(LOG_ERR,
231840840b0Ssashan "pfi_kif_unref (%s): rules refcount <= 0",
232840840b0Ssashan kif->pfik_name);
233c1f13696Shenning return;
234c1f13696Shenning }
235c1f13696Shenning kif->pfik_rules--;
236c1f13696Shenning break;
237c1f13696Shenning case PFI_KIF_REF_STATE:
238c1f13696Shenning if (kif->pfik_states <= 0) {
239a2fdc13dSmcbride DPFPRINTF(LOG_ERR,
240840840b0Ssashan "pfi_kif_unref (%s): state refcount <= 0",
241840840b0Ssashan kif->pfik_name);
242c1f13696Shenning return;
243c1f13696Shenning }
244a4d96804Smarkus kif->pfik_states--;
245c1f13696Shenning break;
24636754172Smcbride case PFI_KIF_REF_ROUTE:
24736754172Smcbride if (kif->pfik_routes <= 0) {
248a2fdc13dSmcbride DPFPRINTF(LOG_ERR,
249840840b0Ssashan "pfi_kif_unref (%s): route refcount <= 0",
250840840b0Ssashan kif->pfik_name);
25136754172Smcbride return;
25236754172Smcbride }
25336754172Smcbride kif->pfik_routes--;
25436754172Smcbride break;
2551c2f8232Syasuoka case PFI_KIF_REF_SRCNODE:
2561c2f8232Syasuoka if (kif->pfik_srcnodes <= 0) {
2571c2f8232Syasuoka DPFPRINTF(LOG_ERR,
258840840b0Ssashan "pfi_kif_unref (%s): src-node refcount <= 0",
259840840b0Ssashan kif->pfik_name);
2601c2f8232Syasuoka return;
2611c2f8232Syasuoka }
2621c2f8232Syasuoka kif->pfik_srcnodes--;
2631c2f8232Syasuoka break;
264840840b0Ssashan case PFI_KIF_REF_FLAG:
265840840b0Ssashan if (kif->pfik_flagrefs <= 0) {
266840840b0Ssashan DPFPRINTF(LOG_ERR,
267840840b0Ssashan "pfi_kif_unref (%s): flags refcount <= 0",
268840840b0Ssashan kif->pfik_name);
269840840b0Ssashan return;
270840840b0Ssashan }
271840840b0Ssashan kif->pfik_flagrefs--;
272840840b0Ssashan break;
273c1f13696Shenning default:
274840840b0Ssashan panic("pfi_kif_unref (%s) with unknown type", kif->pfik_name);
275c1f13696Shenning }
276c1f13696Shenning
277a60c9213Shenning if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
278c1f13696Shenning return;
279c1f13696Shenning
2801c2f8232Syasuoka if (kif->pfik_rules || kif->pfik_states || kif->pfik_routes ||
281840840b0Ssashan kif->pfik_srcnodes || kif->pfik_flagrefs)
282c1f13696Shenning return;
283c1f13696Shenning
284342c264fSdlg RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
2856338263fSderaadt free(kif, PFI_MTYPE, sizeof(*kif));
286c1f13696Shenning }
287c1f13696Shenning
288c1f13696Shenning int
pfi_kif_match(struct pfi_kif * rule_kif,struct pfi_kif * packet_kif)289c1f13696Shenning pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
290c1f13696Shenning {
291a60c9213Shenning struct ifg_list *p;
292a60c9213Shenning
293c1f13696Shenning if (rule_kif == NULL || rule_kif == packet_kif)
294c1f13696Shenning return (1);
295c1f13696Shenning
296a60c9213Shenning if (rule_kif->pfik_group != NULL)
297a60c9213Shenning TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next)
298a60c9213Shenning if (p->ifgl_group == rule_kif->pfik_group)
299a60c9213Shenning return (1);
300c1f13696Shenning
3014be478ceShenning if (rule_kif->pfik_flags & PFI_IFLAG_ANY && packet_kif->pfik_ifp &&
3024be478ceShenning !(packet_kif->pfik_ifp->if_flags & IFF_LOOPBACK))
3034be478ceShenning return (1);
3044be478ceShenning
305c1f13696Shenning return (0);
306ec359bd5Scedric }
307ec359bd5Scedric
308ec359bd5Scedric void
pfi_attach_ifnet(struct ifnet * ifp)309ec359bd5Scedric pfi_attach_ifnet(struct ifnet *ifp)
310ec359bd5Scedric {
311a328f98eShenning struct pfi_kif *kif;
312f22742abSdlg struct task *t;
313ec359bd5Scedric
3146c44725cSsashan PF_LOCK();
315ec359bd5Scedric pfi_initialize();
3165c55b388Shenning pfi_update++;
317c97e8838Ssashan if ((kif = pfi_kif_get(ifp->if_xname, NULL)) == NULL)
31840e42c82Snayden panic("%s: pfi_kif_get failed", __func__);
319ec359bd5Scedric
320c1f13696Shenning kif->pfik_ifp = ifp;
321c1f13696Shenning ifp->if_pf_kif = (caddr_t)kif;
322c1f13696Shenning
323f22742abSdlg t = malloc(sizeof(*t), PFI_MTYPE, M_WAITOK);
324f22742abSdlg task_set(t, pfi_kifaddr_update, kif);
325f22742abSdlg if_addrhook_add(ifp, t);
326f22742abSdlg kif->pfik_ah_cookie = t;
32745bdb168Shenning
328aee130d6Shenning pfi_kif_update(kif);
3296c44725cSsashan PF_UNLOCK();
330ec359bd5Scedric }
331ec359bd5Scedric
332ec359bd5Scedric void
pfi_detach_ifnet(struct ifnet * ifp)333ec359bd5Scedric pfi_detach_ifnet(struct ifnet *ifp)
334ec359bd5Scedric {
335c1f13696Shenning struct pfi_kif *kif;
336f22742abSdlg struct task *t;
337ec359bd5Scedric
338c1f13696Shenning if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
339c1f13696Shenning return;
340ec359bd5Scedric
3416c44725cSsashan PF_LOCK();
3425c55b388Shenning pfi_update++;
343f22742abSdlg t = kif->pfik_ah_cookie;
3443a2a944fSdlg kif->pfik_ah_cookie = NULL;
345f22742abSdlg if_addrhook_del(ifp, t);
3463a2a944fSdlg free(t, PFI_MTYPE, sizeof(*t));
3473a2a944fSdlg
348aee130d6Shenning pfi_kif_update(kif);
349c1f13696Shenning
350c1f13696Shenning kif->pfik_ifp = NULL;
351c1f13696Shenning ifp->if_pf_kif = NULL;
3520036ef99Spascoe pfi_kif_unref(kif, PFI_KIF_REF_NONE);
3536c44725cSsashan PF_UNLOCK();
354ec359bd5Scedric }
355ec359bd5Scedric
356a60c9213Shenning void
pfi_attach_ifgroup(struct ifg_group * ifg)357a60c9213Shenning pfi_attach_ifgroup(struct ifg_group *ifg)
358a60c9213Shenning {
359a60c9213Shenning struct pfi_kif *kif;
360a60c9213Shenning
3616c44725cSsashan PF_LOCK();
362a60c9213Shenning pfi_initialize();
3635c55b388Shenning pfi_update++;
364c97e8838Ssashan if ((kif = pfi_kif_get(ifg->ifg_group, NULL)) == NULL)
36540e42c82Snayden panic("%s: pfi_kif_get failed", __func__);
366a60c9213Shenning
367a60c9213Shenning kif->pfik_group = ifg;
368a60c9213Shenning ifg->ifg_pf_kif = (caddr_t)kif;
3696c44725cSsashan PF_UNLOCK();
370a60c9213Shenning }
371a60c9213Shenning
372a60c9213Shenning void
pfi_detach_ifgroup(struct ifg_group * ifg)373a60c9213Shenning pfi_detach_ifgroup(struct ifg_group *ifg)
374a60c9213Shenning {
375a60c9213Shenning struct pfi_kif *kif;
376a60c9213Shenning
377a60c9213Shenning if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
378a60c9213Shenning return;
379a60c9213Shenning
3806c44725cSsashan PF_LOCK();
3815c55b388Shenning pfi_update++;
382a60c9213Shenning
383a60c9213Shenning kif->pfik_group = NULL;
384a60c9213Shenning ifg->ifg_pf_kif = NULL;
385ef668455Shenning pfi_kif_unref(kif, PFI_KIF_REF_NONE);
3866c44725cSsashan PF_UNLOCK();
387a60c9213Shenning }
388a60c9213Shenning
389679023a4Shenning void
pfi_group_change(const char * group)390fe4396f2Shenning pfi_group_change(const char *group)
391679023a4Shenning {
392679023a4Shenning struct pfi_kif *kif;
393679023a4Shenning
394679023a4Shenning pfi_update++;
395c97e8838Ssashan if ((kif = pfi_kif_get(group, NULL)) == NULL)
39640e42c82Snayden panic("%s: pfi_kif_get failed", __func__);
397679023a4Shenning
398aee130d6Shenning pfi_kif_update(kif);
399679023a4Shenning }
400679023a4Shenning
401625edea1Shenning void
pfi_group_delmember(const char * group)402840840b0Ssashan pfi_group_delmember(const char *group)
403625edea1Shenning {
4046c44725cSsashan PF_LOCK();
405625edea1Shenning pfi_group_change(group);
406840840b0Ssashan pfi_xcommit();
4076c44725cSsashan PF_UNLOCK();
408840840b0Ssashan }
409840840b0Ssashan
410840840b0Ssashan void
pfi_group_addmember(const char * group)411840840b0Ssashan pfi_group_addmember(const char *group)
412840840b0Ssashan {
4136c44725cSsashan PF_LOCK();
414840840b0Ssashan pfi_group_change(group);
415840840b0Ssashan pfi_xcommit();
4166c44725cSsashan PF_UNLOCK();
417625edea1Shenning }
418625edea1Shenning
419c1f13696Shenning int
pfi_match_addr(struct pfi_dynaddr * dyn,struct pf_addr * a,sa_family_t af)420c1f13696Shenning pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
421ec359bd5Scedric {
422c1f13696Shenning switch (af) {
423c1f13696Shenning case AF_INET:
424c1f13696Shenning switch (dyn->pfid_acnt4) {
425c1f13696Shenning case 0:
426c1f13696Shenning return (0);
427c1f13696Shenning case 1:
428492cf661Skn return (pf_match_addr(0, &dyn->pfid_addr4,
429c1f13696Shenning &dyn->pfid_mask4, a, AF_INET));
430c1f13696Shenning default:
431c1f13696Shenning return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
432a880d1fdSmcbride }
433c1f13696Shenning break;
434c1f13696Shenning #ifdef INET6
435c1f13696Shenning case AF_INET6:
436c1f13696Shenning switch (dyn->pfid_acnt6) {
437c1f13696Shenning case 0:
438c1f13696Shenning return (0);
439c1f13696Shenning case 1:
440492cf661Skn return (pf_match_addr(0, &dyn->pfid_addr6,
441c1f13696Shenning &dyn->pfid_mask6, a, AF_INET6));
442c1f13696Shenning default:
443c1f13696Shenning return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
444ec359bd5Scedric }
445c1f13696Shenning break;
446c1f13696Shenning #endif /* INET6 */
447c1f13696Shenning default:
448c1f13696Shenning return (0);
449ec359bd5Scedric }
450ec359bd5Scedric }
4513446b247Scedric
4523446b247Scedric int
pfi_dynaddr_setup(struct pf_addr_wrap * aw,sa_family_t af,int wait)45330d709c8Smbuhl pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af, int wait)
4543446b247Scedric {
455ec359bd5Scedric struct pfi_dynaddr *dyn;
456ec359bd5Scedric char tblname[PF_TABLE_NAME_SIZE];
457ec359bd5Scedric struct pf_ruleset *ruleset = NULL;
458a7d48cecSmpi int rv = 0;
459ec359bd5Scedric
4603446b247Scedric if (aw->type != PF_ADDR_DYNIFTL)
4613446b247Scedric return (0);
46230d709c8Smbuhl if ((dyn = pool_get(&pfi_addr_pl, wait|PR_LIMITFAIL|PR_ZERO)) == NULL)
4633446b247Scedric return (1);
464ec359bd5Scedric
465609bdb9bShenning if (!strcmp(aw->v.ifname, "self"))
466c97e8838Ssashan dyn->pfid_kif = pfi_kif_get(IFG_ALL, NULL);
467609bdb9bShenning else
468c97e8838Ssashan dyn->pfid_kif = pfi_kif_get(aw->v.ifname, NULL);
469c1f13696Shenning if (dyn->pfid_kif == NULL) {
470c1f13696Shenning rv = 1;
471c1f13696Shenning goto _bad;
472c1f13696Shenning }
473c1f13696Shenning pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
474ec359bd5Scedric
475ec359bd5Scedric dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
476ec359bd5Scedric if (af == AF_INET && dyn->pfid_net == 32)
477ec359bd5Scedric dyn->pfid_net = 128;
478ec359bd5Scedric strlcpy(tblname, aw->v.ifname, sizeof(tblname));
479ec359bd5Scedric if (aw->iflags & PFI_AFLAG_NETWORK)
480ec359bd5Scedric strlcat(tblname, ":network", sizeof(tblname));
481ec359bd5Scedric if (aw->iflags & PFI_AFLAG_BROADCAST)
482ec359bd5Scedric strlcat(tblname, ":broadcast", sizeof(tblname));
483ec359bd5Scedric if (aw->iflags & PFI_AFLAG_PEER)
484ec359bd5Scedric strlcat(tblname, ":peer", sizeof(tblname));
485ec359bd5Scedric if (aw->iflags & PFI_AFLAG_NOALIAS)
486ec359bd5Scedric strlcat(tblname, ":0", sizeof(tblname));
487ec359bd5Scedric if (dyn->pfid_net != 128)
488ec359bd5Scedric snprintf(tblname + strlen(tblname),
48905dfa9b9Shenning sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
4906a488485Shenning if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
491c1f13696Shenning rv = 1;
492c1f13696Shenning goto _bad;
493c1f13696Shenning }
494ec359bd5Scedric
49530d709c8Smbuhl if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname, wait)) == NULL) {
496c1f13696Shenning rv = 1;
497c1f13696Shenning goto _bad;
498c1f13696Shenning }
499ec359bd5Scedric
500ec359bd5Scedric dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
501ec359bd5Scedric dyn->pfid_iflags = aw->iflags;
502ec359bd5Scedric dyn->pfid_af = af;
503ec359bd5Scedric
50445bdb168Shenning TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
505ec359bd5Scedric aw->p.dyn = dyn;
506aee130d6Shenning pfi_kif_update(dyn->pfid_kif);
5073446b247Scedric return (0);
508ec359bd5Scedric
509ec359bd5Scedric _bad:
510ec359bd5Scedric if (dyn->pfid_kt != NULL)
511ec359bd5Scedric pfr_detach_table(dyn->pfid_kt);
512ec359bd5Scedric if (ruleset != NULL)
513ec359bd5Scedric pf_remove_if_empty_ruleset(ruleset);
514ec359bd5Scedric if (dyn->pfid_kif != NULL)
515c1f13696Shenning pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
516ec359bd5Scedric pool_put(&pfi_addr_pl, dyn);
517ec359bd5Scedric return (rv);
5183446b247Scedric }
5193446b247Scedric
5203446b247Scedric void
pfi_kif_update(struct pfi_kif * kif)521aee130d6Shenning pfi_kif_update(struct pfi_kif *kif)
522aee130d6Shenning {
523aee130d6Shenning struct ifg_list *ifgl;
524aee130d6Shenning struct pfi_dynaddr *p;
525aee130d6Shenning
526aee130d6Shenning /* update all dynaddr */
527aee130d6Shenning TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
528aee130d6Shenning pfi_dynaddr_update(p);
529aee130d6Shenning
530aee130d6Shenning /* again for all groups kif is member of */
531aee130d6Shenning if (kif->pfik_ifp != NULL)
532aee130d6Shenning TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next)
533aee130d6Shenning pfi_kif_update((struct pfi_kif *)
534aee130d6Shenning ifgl->ifgl_group->ifg_pf_kif);
535aee130d6Shenning }
536aee130d6Shenning
537aee130d6Shenning void
pfi_dynaddr_update(struct pfi_dynaddr * dyn)53845bdb168Shenning pfi_dynaddr_update(struct pfi_dynaddr *dyn)
5393446b247Scedric {
5407d6b74b0Smpf struct pfi_kif *kif;
5417d6b74b0Smpf struct pfr_ktable *kt;
5423446b247Scedric
5437d6b74b0Smpf if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
5443446b247Scedric panic("pfi_dynaddr_update");
5457d6b74b0Smpf
5467d6b74b0Smpf kif = dyn->pfid_kif;
5477d6b74b0Smpf kt = dyn->pfid_kt;
548c1f13696Shenning
549ec359bd5Scedric if (kt->pfrkt_larg != pfi_update) {
55005dfa9b9Shenning /* this table needs to be brought up-to-date */
551ec359bd5Scedric pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
552ec359bd5Scedric kt->pfrkt_larg = pfi_update;
553ec359bd5Scedric }
554ec359bd5Scedric pfr_dynaddr_update(kt, dyn);
555ec359bd5Scedric }
5563446b247Scedric
557ec359bd5Scedric void
pfi_table_update(struct pfr_ktable * kt,struct pfi_kif * kif,u_int8_t net,int flags)558a17121a6Ssashan pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, u_int8_t net, int flags)
559ec359bd5Scedric {
560ec359bd5Scedric int e, size2 = 0;
561507ecb08Shenning struct ifg_member *ifgm;
5623446b247Scedric
563ec359bd5Scedric pfi_buffer_cnt = 0;
564c1f13696Shenning
565c1f13696Shenning if (kif->pfik_ifp != NULL)
566ec359bd5Scedric pfi_instance_add(kif->pfik_ifp, net, flags);
567679023a4Shenning else if (kif->pfik_group != NULL)
568507ecb08Shenning TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
569507ecb08Shenning pfi_instance_add(ifgm->ifgm_ifp, net, flags);
570c1f13696Shenning
57156966508Spascoe if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2,
57256966508Spascoe NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
573a2fdc13dSmcbride DPFPRINTF(LOG_ERR,
574a2fdc13dSmcbride "pfi_table_update: cannot set %d new addresses "
575a2fdc13dSmcbride "into table %s: %d", pfi_buffer_cnt, kt->pfrkt_name, e);
576ec359bd5Scedric }
577ec359bd5Scedric
578ec359bd5Scedric void
pfi_instance_add(struct ifnet * ifp,u_int8_t net,int flags)579a17121a6Ssashan pfi_instance_add(struct ifnet *ifp, u_int8_t net, int flags)
580ec359bd5Scedric {
5813e0567a8Sbluhm struct ifaddr *ifa;
582ec359bd5Scedric int got4 = 0, got6 = 0;
583ec359bd5Scedric int net2, af;
584ec359bd5Scedric
585ec359bd5Scedric if (ifp == NULL)
586ec359bd5Scedric return;
5873e0567a8Sbluhm TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
5883e0567a8Sbluhm if (ifa->ifa_addr == NULL)
589ec359bd5Scedric continue;
5903e0567a8Sbluhm af = ifa->ifa_addr->sa_family;
591ec359bd5Scedric if (af != AF_INET && af != AF_INET6)
592ec359bd5Scedric continue;
593ec359bd5Scedric if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
594ec359bd5Scedric continue;
595ec359bd5Scedric if ((flags & PFI_AFLAG_BROADCAST) &&
596ec359bd5Scedric !(ifp->if_flags & IFF_BROADCAST))
597ec359bd5Scedric continue;
598ec359bd5Scedric if ((flags & PFI_AFLAG_PEER) &&
599ec359bd5Scedric !(ifp->if_flags & IFF_POINTOPOINT))
600ec359bd5Scedric continue;
601ec359bd5Scedric if ((flags & PFI_AFLAG_NETWORK) && af == AF_INET6 &&
602ec359bd5Scedric IN6_IS_ADDR_LINKLOCAL(
6033e0567a8Sbluhm &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr))
604ec359bd5Scedric continue;
605ec359bd5Scedric if (flags & PFI_AFLAG_NOALIAS) {
606ec359bd5Scedric if (af == AF_INET && got4)
607ec359bd5Scedric continue;
608ec359bd5Scedric if (af == AF_INET6 && got6)
609ec359bd5Scedric continue;
610ec359bd5Scedric }
611ec359bd5Scedric if (af == AF_INET)
612ec359bd5Scedric got4 = 1;
6137d37faf6Spb else if (af == AF_INET6)
614ec359bd5Scedric got6 = 1;
615ec359bd5Scedric net2 = net;
616ec359bd5Scedric if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
6176a488485Shenning if (af == AF_INET)
618ec359bd5Scedric net2 = pfi_unmask(&((struct sockaddr_in *)
6193e0567a8Sbluhm ifa->ifa_netmask)->sin_addr);
6206a488485Shenning else if (af == AF_INET6)
621ec359bd5Scedric net2 = pfi_unmask(&((struct sockaddr_in6 *)
6223e0567a8Sbluhm ifa->ifa_netmask)->sin6_addr);
6233446b247Scedric }
624ec359bd5Scedric if (af == AF_INET && net2 > 32)
625ec359bd5Scedric net2 = 32;
626ec359bd5Scedric if (flags & PFI_AFLAG_BROADCAST)
6273e0567a8Sbluhm pfi_address_add(ifa->ifa_broadaddr, af, net2);
628ec359bd5Scedric else if (flags & PFI_AFLAG_PEER)
6293e0567a8Sbluhm pfi_address_add(ifa->ifa_dstaddr, af, net2);
630ec359bd5Scedric else
6313e0567a8Sbluhm pfi_address_add(ifa->ifa_addr, af, net2);
6323446b247Scedric }
633ec359bd5Scedric }
634ec359bd5Scedric
635ec359bd5Scedric void
pfi_address_add(struct sockaddr * sa,sa_family_t af,u_int8_t net)636a17121a6Ssashan pfi_address_add(struct sockaddr *sa, sa_family_t af, u_int8_t net)
637ec359bd5Scedric {
638ec359bd5Scedric struct pfr_addr *p;
639ec359bd5Scedric int i;
640ec359bd5Scedric
641ec359bd5Scedric if (pfi_buffer_cnt >= pfi_buffer_max) {
642ec359bd5Scedric int new_max = pfi_buffer_max * 2;
643ec359bd5Scedric
644ec359bd5Scedric if (new_max > PFI_BUFFER_MAX) {
645a2fdc13dSmcbride DPFPRINTF(LOG_ERR,
646a2fdc13dSmcbride "pfi_address_add: address buffer full (%d/%d)",
64705dfa9b9Shenning pfi_buffer_cnt, PFI_BUFFER_MAX);
648ec359bd5Scedric return;
649ec359bd5Scedric }
65083bfce96Stedu p = mallocarray(new_max, sizeof(*pfi_buffer), PFI_MTYPE,
651ec359bd5Scedric M_DONTWAIT);
652ec359bd5Scedric if (p == NULL) {
653a2fdc13dSmcbride DPFPRINTF(LOG_ERR,
654a2fdc13dSmcbride "pfi_address_add: no memory to grow buffer "
655a2fdc13dSmcbride "(%d/%d)", pfi_buffer_cnt, PFI_BUFFER_MAX);
656ec359bd5Scedric return;
657ec359bd5Scedric }
6582d5543b8Skrw memcpy(p, pfi_buffer, pfi_buffer_max * sizeof(*pfi_buffer));
659ec359bd5Scedric /* no need to zero buffer */
6606338263fSderaadt free(pfi_buffer, PFI_MTYPE, pfi_buffer_max * sizeof(*pfi_buffer));
661ec359bd5Scedric pfi_buffer = p;
662ec359bd5Scedric pfi_buffer_max = new_max;
663ec359bd5Scedric }
664ec359bd5Scedric if (af == AF_INET && net > 32)
665ec359bd5Scedric net = 128;
666ec359bd5Scedric p = pfi_buffer + pfi_buffer_cnt++;
667568ff528Shenning memset(p, 0, sizeof(*p));
668ec359bd5Scedric p->pfra_af = af;
669ec359bd5Scedric p->pfra_net = net;
670ec359bd5Scedric if (af == AF_INET)
671ec359bd5Scedric p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
6726a488485Shenning else if (af == AF_INET6) {
673ec359bd5Scedric p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
67465b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
675ec359bd5Scedric p->pfra_ip6addr.s6_addr16[1] = 0;
676ec359bd5Scedric }
677ec359bd5Scedric /* mask network address bits */
678ec359bd5Scedric if (net < 128)
679ec359bd5Scedric ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
680ec359bd5Scedric for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
681ec359bd5Scedric ((caddr_t)p)[i] = 0;
6823446b247Scedric }
6833446b247Scedric
6843446b247Scedric void
pfi_dynaddr_remove(struct pf_addr_wrap * aw)6853446b247Scedric pfi_dynaddr_remove(struct pf_addr_wrap *aw)
6863446b247Scedric {
687ec359bd5Scedric if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
688ec359bd5Scedric aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
6893446b247Scedric return;
690ec359bd5Scedric
69145bdb168Shenning TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
692c1f13696Shenning pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
693ec359bd5Scedric aw->p.dyn->pfid_kif = NULL;
694ec359bd5Scedric pfr_detach_table(aw->p.dyn->pfid_kt);
695ec359bd5Scedric aw->p.dyn->pfid_kt = NULL;
696ec359bd5Scedric pool_put(&pfi_addr_pl, aw->p.dyn);
6973446b247Scedric aw->p.dyn = NULL;
6983446b247Scedric }
6993446b247Scedric
7003446b247Scedric void
pfi_dynaddr_copyout(struct pf_addr_wrap * aw)7013446b247Scedric pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
7023446b247Scedric {
703ec359bd5Scedric if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
704ec359bd5Scedric aw->p.dyn->pfid_kif == NULL)
7053446b247Scedric return;
706ec359bd5Scedric aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
707ec359bd5Scedric }
708ec359bd5Scedric
709ec359bd5Scedric void
pfi_kifaddr_update(void * v)710ec359bd5Scedric pfi_kifaddr_update(void *v)
711ec359bd5Scedric {
71245bdb168Shenning struct pfi_kif *kif = (struct pfi_kif *)v;
713ec359bd5Scedric
71466736630Smpi NET_ASSERT_LOCKED();
715662d13b1Smpi
7166c44725cSsashan PF_LOCK();
7175c55b388Shenning pfi_update++;
718aee130d6Shenning pfi_kif_update(kif);
7196c44725cSsashan PF_UNLOCK();
720ec359bd5Scedric }
721ec359bd5Scedric
722ec359bd5Scedric int
pfi_if_compare(struct pfi_kif * p,struct pfi_kif * q)723342c264fSdlg pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
724ec359bd5Scedric {
72560b10d66Smcbride return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
726ec359bd5Scedric }
727ec359bd5Scedric
728ec359bd5Scedric void
pfi_update_status(const char * name,struct pf_status * pfs)729372d2a18Smpf pfi_update_status(const char *name, struct pf_status *pfs)
730ec359bd5Scedric {
7314a3452fdSpascoe struct pfi_kif *p;
7324a3452fdSpascoe struct pfi_kif_cmp key;
733372d2a18Smpf struct ifg_member p_member, *ifgm;
734372d2a18Smpf TAILQ_HEAD(, ifg_member) ifg_members;
735a7d48cecSmpi int i, j, k;
736ec359bd5Scedric
737ec55ae92Smcbride if (*name == '\0' && pfs == NULL) {
738342c264fSdlg RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
739568ff528Shenning memset(p->pfik_packets, 0, sizeof(p->pfik_packets));
740568ff528Shenning memset(p->pfik_bytes, 0, sizeof(p->pfik_bytes));
7413209772dScheloha p->pfik_tzero = gettime();
742ec55ae92Smcbride }
743ec55ae92Smcbride return;
744ec55ae92Smcbride }
745ec55ae92Smcbride
746ec55ae92Smcbride strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
747342c264fSdlg p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
748ec359bd5Scedric if (p == NULL) {
749ec359bd5Scedric return;
750ec359bd5Scedric }
751372d2a18Smpf if (p->pfik_group != NULL) {
75247d085d4Shenning memcpy(&ifg_members, &p->pfik_group->ifg_members,
753372d2a18Smpf sizeof(ifg_members));
754372d2a18Smpf } else {
755372d2a18Smpf /* build a temporary list for p only */
756568ff528Shenning memset(&p_member, 0, sizeof(p_member));
757372d2a18Smpf p_member.ifgm_ifp = p->pfik_ifp;
758372d2a18Smpf TAILQ_INIT(&ifg_members);
759372d2a18Smpf TAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next);
760372d2a18Smpf }
761372d2a18Smpf if (pfs) {
762568ff528Shenning memset(pfs->pcounters, 0, sizeof(pfs->pcounters));
763568ff528Shenning memset(pfs->bcounters, 0, sizeof(pfs->bcounters));
764372d2a18Smpf }
765372d2a18Smpf TAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) {
7669c410680Smpf if (ifgm->ifgm_ifp == NULL)
7679c410680Smpf continue;
768372d2a18Smpf p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif;
769372d2a18Smpf
770372d2a18Smpf /* just clear statistics */
771372d2a18Smpf if (pfs == NULL) {
772568ff528Shenning memset(p->pfik_packets, 0, sizeof(p->pfik_packets));
773568ff528Shenning memset(p->pfik_bytes, 0, sizeof(p->pfik_bytes));
7743209772dScheloha p->pfik_tzero = gettime();
775372d2a18Smpf continue;
776372d2a18Smpf }
777ec359bd5Scedric for (i = 0; i < 2; i++)
778ec359bd5Scedric for (j = 0; j < 2; j++)
779ec359bd5Scedric for (k = 0; k < 2; k++) {
780372d2a18Smpf pfs->pcounters[i][j][k] +=
781ec359bd5Scedric p->pfik_packets[i][j][k];
782ec359bd5Scedric pfs->bcounters[i][j] +=
783ec359bd5Scedric p->pfik_bytes[i][j][k];
784ec359bd5Scedric }
785ec359bd5Scedric }
786ec359bd5Scedric }
787ec359bd5Scedric
788f3a753b5Smbuhl void
pfi_get_ifaces(const char * name,struct pfi_kif * buf,int * size)789c1f13696Shenning pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
790ec359bd5Scedric {
791408def72Skn struct pfi_kif *p;
792a7d48cecSmpi int n = 0;
793ec359bd5Scedric
794408def72Skn RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
795c1f13696Shenning if (pfi_skip_if(name, p))
796ec359bd5Scedric continue;
797edd74edcSsashan if (*size <= ++n)
798edd74edcSsashan break;
799ec359bd5Scedric if (!p->pfik_tzero)
8003209772dScheloha p->pfik_tzero = gettime();
801f3a753b5Smbuhl memcpy(buf++, p, sizeof(*buf));
802ec359bd5Scedric }
803ec359bd5Scedric *size = n;
804ec359bd5Scedric }
805ec359bd5Scedric
806ec359bd5Scedric int
pfi_skip_if(const char * filter,struct pfi_kif * p)807c1f13696Shenning pfi_skip_if(const char *filter, struct pfi_kif *p)
808ec359bd5Scedric {
80902794fccSsthen struct ifg_list *i;
810c888552eScedric int n;
811c888552eScedric
812128c3c8cSkn PF_ASSERT_LOCKED();
813128c3c8cSkn
814ec359bd5Scedric if (filter == NULL || !*filter)
815ec359bd5Scedric return (0);
816c888552eScedric if (!strcmp(p->pfik_name, filter))
817c888552eScedric return (0); /* exact match */
818c888552eScedric n = strlen(filter);
819c888552eScedric if (n < 1 || n >= IFNAMSIZ)
820c888552eScedric return (1); /* sanity check */
821c888552eScedric if (filter[n-1] >= '0' && filter[n-1] <= '9')
82202794fccSsthen return (1); /* group names may not end in a digit */
82302794fccSsthen if (p->pfik_ifp != NULL)
82402794fccSsthen TAILQ_FOREACH(i, &p->pfik_ifp->if_groups, ifgl_next)
82596909b11Shenning if (!strncmp(i->ifgl_group->ifg_group, filter, IFNAMSIZ))
82602794fccSsthen return (0); /* iface is in group "filter" */
82702794fccSsthen return (1);
828ec359bd5Scedric }
829ec359bd5Scedric
830c1f13696Shenning int
pfi_set_flags(const char * name,int flags)831c1f13696Shenning pfi_set_flags(const char *name, int flags)
832c1f13696Shenning {
833c1f13696Shenning struct pfi_kif *p;
834840840b0Ssashan size_t n;
835c1f13696Shenning
836128c3c8cSkn PF_ASSERT_LOCKED();
837128c3c8cSkn
838840840b0Ssashan if (name != NULL && name[0] != '\0') {
839840840b0Ssashan p = pfi_kif_find(name);
840840840b0Ssashan if (p == NULL) {
841840840b0Ssashan n = strlen(name);
842840840b0Ssashan if (n < 1 || n >= IFNAMSIZ)
843840840b0Ssashan return (EINVAL);
844840840b0Ssashan
845840840b0Ssashan if (!isalpha(name[0]))
846840840b0Ssashan return (EINVAL);
847840840b0Ssashan
848840840b0Ssashan p = pfi_kif_get(name, NULL);
849840840b0Ssashan if (p != NULL) {
850840840b0Ssashan p->pfik_flags_new = p->pfik_flags | flags;
851840840b0Ssashan /*
852840840b0Ssashan * We use pfik_flagrefs counter as an
853840840b0Ssashan * indication whether the kif has been created
854840840b0Ssashan * on behalf of 'pfi_set_flags()' or not.
855840840b0Ssashan */
856840840b0Ssashan KASSERT(p->pfik_flagrefs == 0);
857840840b0Ssashan if (ISSET(p->pfik_flags_new, PFI_IFLAG_SKIP))
858840840b0Ssashan pfi_kif_ref(p, PFI_KIF_REF_FLAG);
859840840b0Ssashan } else
860840840b0Ssashan panic("%s pfi_kif_get() returned NULL\n",
861840840b0Ssashan __func__);
862840840b0Ssashan } else
863840840b0Ssashan p->pfik_flags_new = p->pfik_flags | flags;
864840840b0Ssashan } else {
865840840b0Ssashan RB_FOREACH(p, pfi_ifhead, &pfi_ifs)
86626b46f76Smcbride p->pfik_flags_new = p->pfik_flags | flags;
867c1f13696Shenning }
868840840b0Ssashan
869c1f13696Shenning return (0);
870c1f13696Shenning }
871c1f13696Shenning
872c1f13696Shenning int
pfi_clear_flags(const char * name,int flags)873c1f13696Shenning pfi_clear_flags(const char *name, int flags)
874c1f13696Shenning {
875840840b0Ssashan struct pfi_kif *p, *w;
876c1f13696Shenning
877128c3c8cSkn PF_ASSERT_LOCKED();
878128c3c8cSkn
879840840b0Ssashan if (name != NULL && name[0] != '\0') {
880840840b0Ssashan p = pfi_kif_find(name);
881840840b0Ssashan if (p != NULL) {
88226b46f76Smcbride p->pfik_flags_new = p->pfik_flags & ~flags;
883840840b0Ssashan
884840840b0Ssashan KASSERT((p->pfik_flagrefs == 0) ||
885840840b0Ssashan (p->pfik_flagrefs == 1));
886840840b0Ssashan
887840840b0Ssashan if (!ISSET(p->pfik_flags_new, PFI_IFLAG_SKIP) &&
888840840b0Ssashan (p->pfik_flagrefs == 1))
889840840b0Ssashan pfi_kif_unref(p, PFI_KIF_REF_FLAG);
890840840b0Ssashan } else
891840840b0Ssashan return (ESRCH);
892840840b0Ssashan
893840840b0Ssashan } else
894840840b0Ssashan RB_FOREACH_SAFE(p, pfi_ifhead, &pfi_ifs, w) {
895840840b0Ssashan p->pfik_flags_new = p->pfik_flags & ~flags;
896840840b0Ssashan
897840840b0Ssashan KASSERT((p->pfik_flagrefs == 0) ||
898840840b0Ssashan (p->pfik_flagrefs == 1));
899840840b0Ssashan
900840840b0Ssashan if (!ISSET(p->pfik_flags_new, PFI_IFLAG_SKIP) &&
901840840b0Ssashan (p->pfik_flagrefs == 1))
902840840b0Ssashan pfi_kif_unref(p, PFI_KIF_REF_FLAG);
903c1f13696Shenning }
904840840b0Ssashan
905c1f13696Shenning return (0);
906c1f13696Shenning }
907c1f13696Shenning
90826b46f76Smcbride void
pfi_xcommit(void)90926b46f76Smcbride pfi_xcommit(void)
91026b46f76Smcbride {
911840840b0Ssashan struct pfi_kif *p, *gkif;
912840840b0Ssashan struct ifg_list *g;
913840840b0Ssashan struct ifnet *ifp;
914840840b0Ssashan size_t n;
91526b46f76Smcbride
916128c3c8cSkn PF_ASSERT_LOCKED();
917128c3c8cSkn
918840840b0Ssashan RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
91926b46f76Smcbride p->pfik_flags = p->pfik_flags_new;
920840840b0Ssashan n = strlen(p->pfik_name);
921840840b0Ssashan ifp = p->pfik_ifp;
922840840b0Ssashan /*
923840840b0Ssashan * if kif is backed by existing interface, then we must use
924840840b0Ssashan * skip flags found in groups. We use pfik_flags_new, otherwise
925840840b0Ssashan * we would need to do two RB_FOREACH() passes: the first to
926840840b0Ssashan * commit group changes the second to commit flag changes for
927840840b0Ssashan * interfaces.
928840840b0Ssashan */
929840840b0Ssashan if (ifp != NULL)
930840840b0Ssashan TAILQ_FOREACH(g, &ifp->if_groups, ifgl_next) {
931840840b0Ssashan gkif =
932840840b0Ssashan (struct pfi_kif *)g->ifgl_group->ifg_pf_kif;
933840840b0Ssashan KASSERT(gkif != NULL);
934840840b0Ssashan p->pfik_flags |= gkif->pfik_flags_new;
935840840b0Ssashan }
936840840b0Ssashan }
93726b46f76Smcbride }
93826b46f76Smcbride
939ec359bd5Scedric /* from pf_print_state.c */
940ec359bd5Scedric int
pfi_unmask(void * addr)941ec359bd5Scedric pfi_unmask(void *addr)
942ec359bd5Scedric {
943ec359bd5Scedric struct pf_addr *m = addr;
944ec359bd5Scedric int i = 31, j = 0, b = 0;
945ec359bd5Scedric u_int32_t tmp;
946ec359bd5Scedric
947ec359bd5Scedric while (j < 4 && m->addr32[j] == 0xffffffff) {
948ec359bd5Scedric b += 32;
949ec359bd5Scedric j++;
950ec359bd5Scedric }
951ec359bd5Scedric if (j < 4) {
952ec359bd5Scedric tmp = ntohl(m->addr32[j]);
953ec359bd5Scedric for (i = 31; tmp & (1 << i); --i)
954ec359bd5Scedric b++;
955ec359bd5Scedric }
956ec359bd5Scedric return (b);
957ec359bd5Scedric }
958ec359bd5Scedric
959