summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netpfil
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-08-21 09:39:55 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-21 10:29:40 +0200
commit2df56dbd60bb5d925d2ce0ddbdefdbe6107ea783 (patch)
treebd7bad558534db4a1f400bc38a2c9aa7ea4f411e /freebsd/sys/netpfil
parentUpdate to FreeBSD head 2018-02-01 (diff)
downloadrtems-libbsd-2df56dbd60bb5d925d2ce0ddbdefdbe6107ea783.tar.bz2
Update to FreeBSD head 2018-04-01
Git mirror commit 8dfb1ccc26d1cea7e2529303003ff61f9f1784c4. Update #3472.
Diffstat (limited to 'freebsd/sys/netpfil')
-rw-r--r--freebsd/sys/netpfil/ipfw/ip_fw_private.h44
-rw-r--r--freebsd/sys/netpfil/pf/if_pfsync.c6
-rw-r--r--freebsd/sys/netpfil/pf/pf.c75
-rw-r--r--freebsd/sys/netpfil/pf/pf.h2
-rw-r--r--freebsd/sys/netpfil/pf/pf_ioctl.c44
-rw-r--r--freebsd/sys/netpfil/pf/pf_table.c4
6 files changed, 107 insertions, 68 deletions
diff --git a/freebsd/sys/netpfil/ipfw/ip_fw_private.h b/freebsd/sys/netpfil/ipfw/ip_fw_private.h
index b6471a02..c389e01a 100644
--- a/freebsd/sys/netpfil/ipfw/ip_fw_private.h
+++ b/freebsd/sys/netpfil/ipfw/ip_fw_private.h
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
* Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
*
* Redistribution and use in source and binary forms, with or without
@@ -182,24 +184,48 @@ enum { /* result for matching dynamic rules */
struct ip_fw_chain;
struct sockopt_data;
int ipfw_is_dyn_rule(struct ip_fw *rule);
-void ipfw_expire_dyn_rules(struct ip_fw_chain *, ipfw_range_tlv *);
-void ipfw_dyn_unlock(ipfw_dyn_rule *q);
+void ipfw_expire_dyn_states(struct ip_fw_chain *, ipfw_range_tlv *);
struct tcphdr;
struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,
u_int32_t, u_int32_t, int);
-int ipfw_install_state(struct ip_fw_chain *chain, struct ip_fw *rule,
- ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg);
-ipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt,
- int *match_direction, struct tcphdr *tcp, uint16_t kidx);
-void ipfw_remove_dyn_children(struct ip_fw *rule);
+/*
+ * Macro to determine that we need to do or redo dynamic state lookup.
+ * direction == MATCH_UNKNOWN means that this is first lookup, then we need
+ * to do lookup.
+ * Otherwise check the state name, if previous lookup was for "any" name,
+ * this means there is no state with specific name. Thus no need to do
+ * lookup. If previous name was not "any", redo lookup for specific name.
+ */
+#define DYN_LOOKUP_NEEDED(p, cmd) \
+ ((p)->direction == MATCH_UNKNOWN || \
+ ((p)->kidx != 0 && (p)->kidx != (cmd)->arg1))
+#define DYN_INFO_INIT(p) do { \
+ (p)->direction = MATCH_UNKNOWN; \
+ (p)->kidx = 0; \
+} while (0)
+struct ipfw_dyn_info {
+ uint16_t direction; /* match direction */
+ uint16_t kidx; /* state name kidx */
+ uint32_t hashval; /* hash value */
+ uint32_t version; /* bucket version */
+ uint32_t f_pos;
+};
+int ipfw_dyn_install_state(struct ip_fw_chain *chain, struct ip_fw *rule,
+ const ipfw_insn_limit *cmd, const struct ip_fw_args *args,
+ const void *ulp, int pktlen, struct ipfw_dyn_info *info,
+ uint32_t tablearg);
+struct ip_fw *ipfw_dyn_lookup_state(const struct ip_fw_args *args,
+ const void *ulp, int pktlen, const ipfw_insn *cmd,
+ struct ipfw_dyn_info *info);
+
void ipfw_get_dynamic(struct ip_fw_chain *chain, char **bp, const char *ep);
int ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd);
void ipfw_dyn_init(struct ip_fw_chain *); /* per-vnet initialization */
void ipfw_dyn_uninit(int); /* per-vnet deinitialization */
int ipfw_dyn_len(void);
-int ipfw_dyn_get_count(void);
+uint32_t ipfw_dyn_get_count(void);
/* common variables */
VNET_DECLARE(int, fw_one_pass);
@@ -625,6 +651,8 @@ void ipfw_destroy_skipto_cache(struct ip_fw_chain *chain);
int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id);
int ipfw_ctl3(struct sockopt *sopt);
int ipfw_chk(struct ip_fw_args *args);
+int ipfw_add_protected_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
+ int locked);
void ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head,
struct ip_fw *rule);
void ipfw_reap_rules(struct ip_fw *head);
diff --git a/freebsd/sys/netpfil/pf/if_pfsync.c b/freebsd/sys/netpfil/pf/if_pfsync.c
index 2343adc2..3ed1b3bb 100644
--- a/freebsd/sys/netpfil/pf/if_pfsync.c
+++ b/freebsd/sys/netpfil/pf/if_pfsync.c
@@ -1321,7 +1321,8 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
pfsyncr.pfsyncr_defer = (PFSYNCF_DEFER ==
(sc->sc_flags & PFSYNCF_DEFER));
PFSYNC_UNLOCK(sc);
- return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)));
+ return (copyout(&pfsyncr, ifr_data_get_ptr(ifr),
+ sizeof(pfsyncr)));
case SIOCSETPFSYNC:
{
@@ -1332,7 +1333,8 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
return (error);
- if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
+ if ((error = copyin(ifr_data_get_ptr(ifr), &pfsyncr,
+ sizeof(pfsyncr))))
return (error);
if (pfsyncr.pfsyncr_maxupdates > 255)
diff --git a/freebsd/sys/netpfil/pf/pf.c b/freebsd/sys/netpfil/pf/pf.c
index a904a0db..1aab6f49 100644
--- a/freebsd/sys/netpfil/pf/pf.c
+++ b/freebsd/sys/netpfil/pf/pf.c
@@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$");
#include <net/radix_mpath.h>
#include <net/vnet.h>
+#include <net/pfil.h>
#include <net/pfvar.h>
#include <net/if_pflog.h>
#include <net/if_pfsync.h>
@@ -792,7 +793,7 @@ pf_initialize()
if (pf_hashsize == 0 || !powerof2(pf_hashsize))
pf_hashsize = PF_HASHSIZ;
if (pf_srchashsize == 0 || !powerof2(pf_srchashsize))
- pf_srchashsize = PF_HASHSIZ / 4;
+ pf_srchashsize = PF_SRCHASHSIZ;
V_pf_hashseed = arc4random();
@@ -806,10 +807,25 @@ pf_initialize()
V_pf_state_key_z = uma_zcreate("pf state keys",
sizeof(struct pf_state_key), pf_state_key_ctor, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
- V_pf_keyhash = malloc(pf_hashsize * sizeof(struct pf_keyhash),
- M_PFHASH, M_WAITOK | M_ZERO);
- V_pf_idhash = malloc(pf_hashsize * sizeof(struct pf_idhash),
- M_PFHASH, M_WAITOK | M_ZERO);
+
+ V_pf_keyhash = mallocarray(pf_hashsize, sizeof(struct pf_keyhash),
+ M_PFHASH, M_NOWAIT | M_ZERO);
+ V_pf_idhash = mallocarray(pf_hashsize, sizeof(struct pf_idhash),
+ M_PFHASH, M_NOWAIT | M_ZERO);
+ if (V_pf_keyhash == NULL || V_pf_idhash == NULL) {
+ printf("pf: Unable to allocate memory for "
+ "state_hashsize %lu.\n", pf_hashsize);
+
+ free(V_pf_keyhash, M_PFHASH);
+ free(V_pf_idhash, M_PFHASH);
+
+ pf_hashsize = PF_HASHSIZ;
+ V_pf_keyhash = mallocarray(pf_hashsize,
+ sizeof(struct pf_keyhash), M_PFHASH, M_WAITOK | M_ZERO);
+ V_pf_idhash = mallocarray(pf_hashsize,
+ sizeof(struct pf_idhash), M_PFHASH, M_WAITOK | M_ZERO);
+ }
+
pf_hashmask = pf_hashsize - 1;
for (i = 0, kh = V_pf_keyhash, ih = V_pf_idhash; i <= pf_hashmask;
i++, kh++, ih++) {
@@ -824,8 +840,18 @@ pf_initialize()
V_pf_limits[PF_LIMIT_SRC_NODES].zone = V_pf_sources_z;
uma_zone_set_max(V_pf_sources_z, PFSNODE_HIWAT);
uma_zone_set_warning(V_pf_sources_z, "PF source nodes limit reached");
- V_pf_srchash = malloc(pf_srchashsize * sizeof(struct pf_srchash),
- M_PFHASH, M_WAITOK|M_ZERO);
+
+ V_pf_srchash = mallocarray(pf_srchashsize,
+ sizeof(struct pf_srchash), M_PFHASH, M_NOWAIT | M_ZERO);
+ if (V_pf_srchash == NULL) {
+ printf("pf: Unable to allocate memory for "
+ "source_hashsize %lu.\n", pf_srchashsize);
+
+ pf_srchashsize = PF_SRCHASHSIZ;
+ V_pf_srchash = mallocarray(pf_srchashsize,
+ sizeof(struct pf_srchash), M_PFHASH, M_WAITOK | M_ZERO);
+ }
+
pf_srchashmask = pf_srchashsize - 1;
for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask; i++, sh++)
mtx_init(&sh->lock, "pf_srchash", NULL, MTX_DEF);
@@ -1615,7 +1641,6 @@ int
pf_unlink_state(struct pf_state *s, u_int flags)
{
struct pf_idhash *ih = &V_pf_idhash[PF_IDHASH(s)];
- int last;
if ((flags & PF_ENTER_LOCKED) == 0)
PF_HASHROW_LOCK(ih);
@@ -1656,8 +1681,9 @@ pf_unlink_state(struct pf_state *s, u_int flags)
PF_HASHROW_UNLOCK(ih);
pf_detach_state(s);
- last = refcount_release(&s->refs);
- KASSERT(last == 0, ("Incorrect state reference count"));
+ /* pf_state_insert() initialises refs to 2, so we can never release the
+ * last reference here, only in pf_release_state(). */
+ (void)refcount_release(&s->refs);
return (pf_release_state(s));
}
@@ -5493,7 +5519,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
+ if (pf_test(PF_OUT, 0, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
@@ -5655,7 +5681,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test6(PF_FWD, ifp, &m0, NULL) != PF_PASS)
+ if (pf_test6(PF_OUT, PFIL_FWD, ifp, &m0, NULL) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
@@ -5845,7 +5871,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t a
#ifdef INET
int
-pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
+pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
@@ -6232,7 +6258,7 @@ done:
#ifdef INET6
int
-pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
+pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
{
struct pfi_kif *kif;
u_short action, reason = 0, log = 0;
@@ -6244,28 +6270,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
int off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0;
- int fwdir = dir;
M_ASSERTPKTHDR(m);
- /* Detect packet forwarding.
- * If the input interface is different from the output interface we're
- * forwarding.
- * We do need to be careful about bridges. If the
- * net.link.bridge.pfil_bridge sysctl is set we can be filtering on a
- * bridge, so if the input interface is a bridge member and the output
- * interface is its bridge or a member of the same bridge we're not
- * actually forwarding but bridging.
- */
- if (dir == PF_OUT && m->m_pkthdr.rcvif && ifp != m->m_pkthdr.rcvif &&
- (m->m_pkthdr.rcvif->if_bridge == NULL ||
- (m->m_pkthdr.rcvif->if_bridge != ifp->if_softc &&
- m->m_pkthdr.rcvif->if_bridge != ifp->if_bridge)))
- fwdir = PF_FWD;
-
- if (dir == PF_FWD)
- dir = PF_OUT;
-
if (!V_pf_status.running)
return (PF_PASS);
@@ -6643,7 +6650,7 @@ done:
PF_STATE_UNLOCK(s);
/* If reassembled packet passed, create new fragments. */
- if (action == PF_PASS && *m0 && fwdir == PF_FWD &&
+ if (action == PF_PASS && *m0 && (pflags & PFIL_FWD) &&
(mtag = m_tag_find(m, PF_REASSEMBLED, NULL)) != NULL)
action = pf_refragment6(ifp, m0, mtag);
diff --git a/freebsd/sys/netpfil/pf/pf.h b/freebsd/sys/netpfil/pf/pf.h
index 69472782..253e8804 100644
--- a/freebsd/sys/netpfil/pf/pf.h
+++ b/freebsd/sys/netpfil/pf/pf.h
@@ -45,7 +45,7 @@
#endif
#endif
-enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD };
+enum { PF_INOUT, PF_IN, PF_OUT };
enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER };
enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT,
diff --git a/freebsd/sys/netpfil/pf/pf_ioctl.c b/freebsd/sys/netpfil/pf/pf_ioctl.c
index a1b0b5e5..9be57273 100644
--- a/freebsd/sys/netpfil/pf/pf_ioctl.c
+++ b/freebsd/sys/netpfil/pf/pf_ioctl.c
@@ -167,15 +167,15 @@ static void pf_tbladdr_copyout(struct pf_addr_wrap *);
*/
#ifdef INET
static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
- int dir, struct inpcb *inp);
+ int dir, int flags, struct inpcb *inp);
static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
- int dir, struct inpcb *inp);
+ int dir, int flags, struct inpcb *inp);
#endif
#ifdef INET6
static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
- int dir, struct inpcb *inp);
+ int dir, int flags, struct inpcb *inp);
static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
- int dir, struct inpcb *inp);
+ int dir, int flags, struct inpcb *inp);
#endif
static int hook_pf(void);
@@ -3661,12 +3661,12 @@ shutdown_pf(void)
#ifdef INET
static int
-pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
struct inpcb *inp)
{
int chk;
- chk = pf_test(PF_IN, ifp, m, inp);
+ chk = pf_test(PF_IN, flags, ifp, m, inp);
if (chk && *m) {
m_freem(*m);
*m = NULL;
@@ -3678,12 +3678,12 @@ pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
}
static int
-pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
struct inpcb *inp)
{
int chk;
- chk = pf_test(PF_OUT, ifp, m, inp);
+ chk = pf_test(PF_OUT, flags, ifp, m, inp);
if (chk && *m) {
m_freem(*m);
*m = NULL;
@@ -3697,7 +3697,7 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
#ifdef INET6
static int
-pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
struct inpcb *inp)
{
int chk;
@@ -3708,7 +3708,7 @@ pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
* filtering we have change this to lo0 as it is the case in IPv4.
*/
CURVNET_SET(ifp->if_vnet);
- chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, inp);
+ chk = pf_test6(PF_IN, flags, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, inp);
CURVNET_RESTORE();
if (chk && *m) {
m_freem(*m);
@@ -3720,13 +3720,13 @@ pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
}
static int
-pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
+pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, int flags,
struct inpcb *inp)
{
int chk;
CURVNET_SET(ifp->if_vnet);
- chk = pf_test6(PF_OUT, ifp, m, inp);
+ chk = pf_test6(PF_OUT, flags, ifp, m, inp);
CURVNET_RESTORE();
if (chk && *m) {
m_freem(*m);
@@ -3755,22 +3755,22 @@ hook_pf(void)
pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
if (pfh_inet == NULL)
return (ESRCH); /* XXX */
- pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
- pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
+ pfil_add_hook_flags(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
+ pfil_add_hook_flags(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
#endif
#ifdef INET6
pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
if (pfh_inet6 == NULL) {
#ifdef INET
- pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfil_remove_hook_flags(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
pfh_inet);
- pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfil_remove_hook_flags(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
pfh_inet);
#endif
return (ESRCH); /* XXX */
}
- pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
- pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
+ pfil_add_hook_flags(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
+ pfil_add_hook_flags(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
#endif
V_pf_pfil_hooked = 1;
@@ -3794,18 +3794,18 @@ dehook_pf(void)
pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
if (pfh_inet == NULL)
return (ESRCH); /* XXX */
- pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfil_remove_hook_flags(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
pfh_inet);
- pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfil_remove_hook_flags(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
pfh_inet);
#endif
#ifdef INET6
pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
if (pfh_inet6 == NULL)
return (ESRCH); /* XXX */
- pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfil_remove_hook_flags(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
pfh_inet6);
- pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfil_remove_hook_flags(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
pfh_inet6);
#endif
diff --git a/freebsd/sys/netpfil/pf/pf_table.c b/freebsd/sys/netpfil/pf/pf_table.c
index 68e24d22..06916204 100644
--- a/freebsd/sys/netpfil/pf/pf_table.c
+++ b/freebsd/sys/netpfil/pf/pf_table.c
@@ -1133,8 +1133,10 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
if (p == NULL)
senderr(ENOMEM);
SLIST_FOREACH(q, &addq, pfrkt_workq) {
- if (!pfr_ktable_compare(p, q))
+ if (!pfr_ktable_compare(p, q)) {
+ pfr_destroy_ktable(p, 0);
goto _skip;
+ }
}
SLIST_INSERT_HEAD(&addq, p, pfrkt_workq);
xadd++;