Changeset View
Standalone View
sys/netpfil/pf/pf.c
| Show First 20 Lines • Show All 188 Lines • ▼ Show 20 Lines | |||||
| MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules", | MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules", | ||||
| MTX_DEF); | MTX_DEF); | ||||
| static VNET_DEFINE(uma_zone_t, pf_sources_z); | static VNET_DEFINE(uma_zone_t, pf_sources_z); | ||||
| #define V_pf_sources_z VNET(pf_sources_z) | #define V_pf_sources_z VNET(pf_sources_z) | ||||
| uma_zone_t pf_mtag_z; | uma_zone_t pf_mtag_z; | ||||
| VNET_DEFINE(uma_zone_t, pf_state_z); | VNET_DEFINE(uma_zone_t, pf_state_z); | ||||
| VNET_DEFINE(uma_zone_t, pf_state_key_z); | VNET_DEFINE(uma_zone_t, pf_state_key_z); | ||||
| VNET_DEFINE(uma_zone_t, pf_udp_mapping_z); | |||||
| VNET_DEFINE(uint64_t, pf_stateid[MAXCPU]); | VNET_DEFINE(uint64_t, pf_stateid[MAXCPU]); | ||||
| #define PFID_CPUBITS 8 | #define PFID_CPUBITS 8 | ||||
| #define PFID_CPUSHIFT (sizeof(uint64_t) * NBBY - PFID_CPUBITS) | #define PFID_CPUSHIFT (sizeof(uint64_t) * NBBY - PFID_CPUBITS) | ||||
| #define PFID_CPUMASK ((uint64_t)((1 << PFID_CPUBITS) - 1) << PFID_CPUSHIFT) | #define PFID_CPUMASK ((uint64_t)((1 << PFID_CPUBITS) - 1) << PFID_CPUSHIFT) | ||||
| #define PFID_MAXID (~PFID_CPUMASK) | #define PFID_MAXID (~PFID_CPUMASK) | ||||
| CTASSERT((1 << PFID_CPUBITS) >= MAXCPU); | CTASSERT((1 << PFID_CPUBITS) >= MAXCPU); | ||||
| Show All 31 Lines | static int pf_test_rule(struct pf_rule **, struct pf_state **, | ||||
| struct pf_pdesc *, struct pf_rule **, | struct pf_pdesc *, struct pf_rule **, | ||||
| struct pf_ruleset **, struct inpcb *); | struct pf_ruleset **, struct inpcb *); | ||||
| static int pf_create_state(struct pf_rule *, struct pf_rule *, | static int pf_create_state(struct pf_rule *, struct pf_rule *, | ||||
| struct pf_rule *, struct pf_pdesc *, | struct pf_rule *, struct pf_pdesc *, | ||||
| struct pf_src_node *, struct pf_state_key *, | struct pf_src_node *, struct pf_state_key *, | ||||
| struct pf_state_key *, struct mbuf *, int, | struct pf_state_key *, struct mbuf *, int, | ||||
| u_int16_t, u_int16_t, int *, struct pfi_kif *, | u_int16_t, u_int16_t, int *, struct pfi_kif *, | ||||
| struct pf_state **, int, u_int16_t, u_int16_t, | struct pf_state **, int, u_int16_t, u_int16_t, | ||||
| int); | int, struct pf_udp_mapping *); | ||||
| static int pf_test_fragment(struct pf_rule **, int, | static int pf_test_fragment(struct pf_rule **, int, | ||||
| struct pfi_kif *, struct mbuf *, void *, | struct pfi_kif *, struct mbuf *, void *, | ||||
| struct pf_pdesc *, struct pf_rule **, | struct pf_pdesc *, struct pf_rule **, | ||||
| struct pf_ruleset **); | struct pf_ruleset **); | ||||
| static int pf_tcp_track_full(struct pf_state_peer *, | static int pf_tcp_track_full(struct pf_state_peer *, | ||||
| struct pf_state_peer *, struct pf_state **, | struct pf_state_peer *, struct pf_state **, | ||||
| struct pfi_kif *, struct mbuf *, int, | struct pfi_kif *, struct mbuf *, int, | ||||
| struct pf_pdesc *, u_short *, int *); | struct pf_pdesc *, u_short *, int *); | ||||
| ▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | do { \ | ||||
| if (s->nat_rule.ptr != NULL) \ | if (s->nat_rule.ptr != NULL) \ | ||||
| counter_u64_add(s->nat_rule.ptr->states_cur, -1);\ | counter_u64_add(s->nat_rule.ptr->states_cur, -1);\ | ||||
| if (s->anchor.ptr != NULL) \ | if (s->anchor.ptr != NULL) \ | ||||
| counter_u64_add(s->anchor.ptr->states_cur, -1); \ | counter_u64_add(s->anchor.ptr->states_cur, -1); \ | ||||
| counter_u64_add(s->rule.ptr->states_cur, -1); \ | counter_u64_add(s->rule.ptr->states_cur, -1); \ | ||||
| } while (0) | } while (0) | ||||
| static MALLOC_DEFINE(M_PFHASH, "pf_hash", "pf(4) hash header structures"); | static MALLOC_DEFINE(M_PFHASH, "pf_hash", "pf(4) hash header structures"); | ||||
| VNET_DEFINE(struct pf_keyhash *, pf_keyhash); | VNET_DEFINE(struct pf_keyhash *, pf_keyhash); | ||||
kp: I seem to be missing the allocation (and freeing) of this. Am I looking in the wrong place or… | |||||
| VNET_DEFINE(struct pf_idhash *, pf_idhash); | VNET_DEFINE(struct pf_idhash *, pf_idhash); | ||||
| VNET_DEFINE(struct pf_srchash *, pf_srchash); | VNET_DEFINE(struct pf_srchash *, pf_srchash); | ||||
| VNET_DEFINE(struct pf_udpendpointhash *, pf_udpendpointhash); | |||||
| SYSCTL_NODE(_net, OID_AUTO, pf, CTLFLAG_RW, 0, "pf(4)"); | SYSCTL_NODE(_net, OID_AUTO, pf, CTLFLAG_RW, 0, "pf(4)"); | ||||
| u_long pf_hashmask; | u_long pf_hashmask; | ||||
| u_long pf_srchashmask; | u_long pf_srchashmask; | ||||
| static u_long pf_hashsize; | static u_long pf_hashsize; | ||||
| static u_long pf_srchashsize; | static u_long pf_srchashsize; | ||||
| SYSCTL_ULONG(_net_pf, OID_AUTO, states_hashsize, CTLFLAG_RDTUN, | SYSCTL_ULONG(_net_pf, OID_AUTO, states_hashsize, CTLFLAG_RDTUN, | ||||
| &pf_hashsize, 0, "Size of pf(4) states hashtable"); | &pf_hashsize, 0, "Size of pf(4) states hashtable"); | ||||
Done Inline ActionsThat'll want an entry in the pf(4) man page. kp: That'll want an entry in the pf(4) man page. | |||||
| SYSCTL_ULONG(_net_pf, OID_AUTO, source_nodes_hashsize, CTLFLAG_RDTUN, | SYSCTL_ULONG(_net_pf, OID_AUTO, source_nodes_hashsize, CTLFLAG_RDTUN, | ||||
| &pf_srchashsize, 0, "Size of pf(4) source nodes hashtable"); | &pf_srchashsize, 0, "Size of pf(4) source nodes hashtable"); | ||||
| VNET_DEFINE(void *, pf_swi_cookie); | VNET_DEFINE(void *, pf_swi_cookie); | ||||
| VNET_DEFINE(uint32_t, pf_hashseed); | VNET_DEFINE(uint32_t, pf_hashseed); | ||||
| #define V_pf_hashseed VNET(pf_hashseed) | #define V_pf_hashseed VNET(pf_hashseed) | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | pf_hashkey(struct pf_state_key *sk) | ||||
| h = murmur3_32_hash32((uint32_t *)sk, | h = murmur3_32_hash32((uint32_t *)sk, | ||||
| sizeof(struct pf_state_key_cmp)/sizeof(uint32_t), | sizeof(struct pf_state_key_cmp)/sizeof(uint32_t), | ||||
| V_pf_hashseed); | V_pf_hashseed); | ||||
| return (h & pf_hashmask); | return (h & pf_hashmask); | ||||
| } | } | ||||
| static inline uint32_t | |||||
| pf_hashudpendpoint(struct pf_udp_endpoint *endpoint) | |||||
| { | |||||
| uint32_t h; | |||||
| h = murmur3_32_hash32((uint32_t *)endpoint, | |||||
| sizeof(struct pf_udp_endpoint_cmp)/sizeof(uint32_t), | |||||
| V_pf_hashseed); | |||||
| return (h & pf_hashmask); | |||||
| } | |||||
| static __inline uint32_t | static __inline uint32_t | ||||
| pf_hashsrc(struct pf_addr *addr, sa_family_t af) | pf_hashsrc(struct pf_addr *addr, sa_family_t af) | ||||
| { | { | ||||
| uint32_t h; | uint32_t h; | ||||
| switch (af) { | switch (af) { | ||||
| case AF_INET: | case AF_INET: | ||||
| h = murmur3_32_hash32((uint32_t *)&addr->v4, | h = murmur3_32_hash32((uint32_t *)&addr->v4, | ||||
| sizeof(addr->v4)/sizeof(uint32_t), V_pf_hashseed); | sizeof(addr->v4)/sizeof(uint32_t), V_pf_hashseed); | ||||
| break; | break; | ||||
| case AF_INET6: | case AF_INET6: | ||||
| h = murmur3_32_hash32((uint32_t *)&addr->v6, | h = murmur3_32_hash32((uint32_t *)&addr->v6, | ||||
| sizeof(addr->v6)/sizeof(uint32_t), V_pf_hashseed); | sizeof(addr->v6)/sizeof(uint32_t), V_pf_hashseed); | ||||
Not Done Inline ActionsPlease use standard C keyword "inline" instead of "__inline" gcc-ism. glebius: Please use standard C keyword "inline" instead of "__inline" gcc-ism. | |||||
| break; | break; | ||||
| default: | default: | ||||
| panic("%s: unknown address family %u", __func__, af); | panic("%s: unknown address family %u", __func__, af); | ||||
| } | } | ||||
| return (h & pf_srchashmask); | return (h & pf_srchashmask); | ||||
| } | } | ||||
| #ifdef ALTQ | #ifdef ALTQ | ||||
| static int | static int | ||||
| pf_state_hash(struct pf_state *s) | pf_state_hash(struct pf_state *s) | ||||
| { | { | ||||
| u_int32_t hv = (intptr_t)s / sizeof(*s); | u_int32_t hv = (intptr_t)s / sizeof(*s); | ||||
| hv ^= crc32(&s->src, sizeof(s->src)); | hv ^= crc32(&s->src, sizeof(s->src)); | ||||
| hv ^= crc32(&s->dst, sizeof(s->dst)); | hv ^= crc32(&s->dst, sizeof(s->dst)); | ||||
| if (hv == 0) | if (hv == 0) | ||||
Done Inline ActionsShouldn't that be V_pf_udpendpointhashmask ? kp: Shouldn't that be V_pf_udpendpointhashmask ? | |||||
| hv = 1; | hv = 1; | ||||
| return (hv); | return (hv); | ||||
| } | } | ||||
| #endif | #endif | ||||
| #ifdef INET6 | #ifdef INET6 | ||||
| void | void | ||||
| pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) | pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) | ||||
| ▲ Show 20 Lines • Show All 308 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* Per-vnet data storage structures initialization. */ | /* Per-vnet data storage structures initialization. */ | ||||
| void | void | ||||
| pf_initialize() | pf_initialize() | ||||
| { | { | ||||
| struct pf_keyhash *kh; | struct pf_keyhash *kh; | ||||
| struct pf_idhash *ih; | struct pf_idhash *ih; | ||||
| struct pf_udpendpointhash *uh; | |||||
| struct pf_srchash *sh; | struct pf_srchash *sh; | ||||
| u_int i; | u_int i; | ||||
| if (pf_hashsize == 0 || !powerof2(pf_hashsize)) | if (pf_hashsize == 0 || !powerof2(pf_hashsize)) | ||||
| pf_hashsize = PF_HASHSIZ; | pf_hashsize = PF_HASHSIZ; | ||||
| if (pf_srchashsize == 0 || !powerof2(pf_srchashsize)) | if (pf_srchashsize == 0 || !powerof2(pf_srchashsize)) | ||||
Done Inline ActionsDo we want to default to the same size as the state table, or maybe something smaller? It's hardly scientific, but my local gateway has about twice as much TCP as UDP, and on my server box it's more like 4 to 1, so I'd go with half or even a quarter of PF_HASHSIZ as a default. kp: Do we want to default to the same size as the state table, or maybe something smaller?
It's… | |||||
| pf_srchashsize = PF_HASHSIZ / 4; | pf_srchashsize = PF_HASHSIZ / 4; | ||||
| V_pf_hashseed = arc4random(); | V_pf_hashseed = arc4random(); | ||||
| /* States and state keys storage. */ | /* States and state keys storage. */ | ||||
| V_pf_state_z = uma_zcreate("pf states", sizeof(struct pf_state), | V_pf_state_z = uma_zcreate("pf states", sizeof(struct pf_state), | ||||
| NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); | NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); | ||||
| V_pf_limits[PF_LIMIT_STATES].zone = V_pf_state_z; | V_pf_limits[PF_LIMIT_STATES].zone = V_pf_state_z; | ||||
| uma_zone_set_max(V_pf_state_z, PFSTATE_HIWAT); | uma_zone_set_max(V_pf_state_z, PFSTATE_HIWAT); | ||||
| uma_zone_set_warning(V_pf_state_z, "PF states limit reached"); | uma_zone_set_warning(V_pf_state_z, "PF states limit reached"); | ||||
| V_pf_state_key_z = uma_zcreate("pf state keys", | V_pf_state_key_z = uma_zcreate("pf state keys", | ||||
| sizeof(struct pf_state_key), pf_state_key_ctor, NULL, NULL, NULL, | sizeof(struct pf_state_key), pf_state_key_ctor, NULL, NULL, NULL, | ||||
| UMA_ALIGN_PTR, 0); | UMA_ALIGN_PTR, 0); | ||||
| V_pf_udp_mapping_z = uma_zcreate("pf UDP mappings", | |||||
| sizeof(struct pf_udp_mapping), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); | |||||
| V_pf_keyhash = malloc(pf_hashsize * sizeof(struct pf_keyhash), | V_pf_keyhash = malloc(pf_hashsize * sizeof(struct pf_keyhash), | ||||
| M_PFHASH, M_WAITOK | M_ZERO); | M_PFHASH, M_WAITOK | M_ZERO); | ||||
Done Inline ActionsI'd leave this out. kp: I'd leave this out. | |||||
| V_pf_idhash = malloc(pf_hashsize * sizeof(struct pf_idhash), | V_pf_idhash = malloc(pf_hashsize * sizeof(struct pf_idhash), | ||||
| M_PFHASH, M_WAITOK | M_ZERO); | M_PFHASH, M_WAITOK | M_ZERO); | ||||
| V_pf_udpendpointhash = malloc(pf_hashsize * sizeof(struct pf_udpendpointhash), | |||||
| M_PFHASH, M_WAITOK | M_ZERO); | |||||
| pf_hashmask = pf_hashsize - 1; | pf_hashmask = pf_hashsize - 1; | ||||
| for (i = 0, kh = V_pf_keyhash, ih = V_pf_idhash; i <= pf_hashmask; | for (i = 0, kh = V_pf_keyhash, ih = V_pf_idhash, uh=V_pf_udpendpointhash; i <= pf_hashmask; | ||||
| i++, kh++, ih++) { | i++, kh++, ih++, uh++) { | ||||
| mtx_init(&kh->lock, "pf_keyhash", NULL, MTX_DEF | MTX_DUPOK); | mtx_init(&kh->lock, "pf_keyhash", NULL, MTX_DEF | MTX_DUPOK); | ||||
| mtx_init(&ih->lock, "pf_idhash", NULL, MTX_DEF); | mtx_init(&ih->lock, "pf_idhash", NULL, MTX_DEF); | ||||
| mtx_init(&uh->lock, "pf_udpendpointhash", NULL, MTX_DEF | MTX_DUPOK); | |||||
Not Done Inline ActionsOh dear god. Another lock for the data path? At the very least it needs thorough documentation w.r.t what it locks and what the lock order expectations are. kp: Oh dear god. Another lock for the data path?
This is worrying.
At the very least it needs… | |||||
| } | } | ||||
Not Done Inline Actions
Ick. Probably required for the same reason we need it for pf_keyhash, but ick nonetheless. kp: > MTX_DUPOK
Ick. Probably required for the same reason we need it for pf_keyhash, but ick… | |||||
| /* Source nodes. */ | /* Source nodes. */ | ||||
| V_pf_sources_z = uma_zcreate("pf source nodes", | V_pf_sources_z = uma_zcreate("pf source nodes", | ||||
| sizeof(struct pf_src_node), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, | sizeof(struct pf_src_node), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, | ||||
| 0); | 0); | ||||
| V_pf_limits[PF_LIMIT_SRC_NODES].zone = V_pf_sources_z; | 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_max(V_pf_sources_z, PFSNODE_HIWAT); | ||||
| uma_zone_set_warning(V_pf_sources_z, "PF source nodes limit reached"); | uma_zone_set_warning(V_pf_sources_z, "PF source nodes limit reached"); | ||||
| Show All 9 Lines | pf_initialize() | ||||
| TAILQ_INIT(&V_pf_pabuf); | TAILQ_INIT(&V_pf_pabuf); | ||||
| V_pf_altqs_active = &V_pf_altqs[0]; | V_pf_altqs_active = &V_pf_altqs[0]; | ||||
| V_pf_altqs_inactive = &V_pf_altqs[1]; | V_pf_altqs_inactive = &V_pf_altqs[1]; | ||||
| /* Send & overload+flush queues. */ | /* Send & overload+flush queues. */ | ||||
| STAILQ_INIT(&V_pf_sendqueue); | STAILQ_INIT(&V_pf_sendqueue); | ||||
| SLIST_INIT(&V_pf_overloadqueue); | SLIST_INIT(&V_pf_overloadqueue); | ||||
| TASK_INIT(&V_pf_overloadtask, 0, pf_overload_task, curvnet); | TASK_INIT(&V_pf_overloadtask, 0, pf_overload_task, curvnet); | ||||
Done Inline ActionsAnd given that we have a hardcoded default for the udp hash size we probably want a define (at least, if we end up choosing a different default for it than PF_HASHSIZ). kp: And given that we have a hardcoded default for the udp hash size we probably want a define (at… | |||||
| /* Unlinked, but may be referenced rules. */ | /* Unlinked, but may be referenced rules. */ | ||||
| TAILQ_INIT(&V_pf_unlinked_rules); | TAILQ_INIT(&V_pf_unlinked_rules); | ||||
| } | } | ||||
| void | void | ||||
| pf_mtag_cleanup() | pf_mtag_cleanup() | ||||
Done Inline Actions<= V_pf_udpendpointhashmask ? Arguably another reason for having a different default size for the udp hash table is that we'd encounter issues like this in default configurations. Now we're only going to see this when a user twiddles the setting. kp: <= V_pf_udpendpointhashmask ?
Arguably another reason for having a different default size for… | |||||
| { | { | ||||
| uma_zdestroy(pf_mtag_z); | uma_zdestroy(pf_mtag_z); | ||||
| } | } | ||||
| void | void | ||||
| pf_cleanup() | pf_cleanup() | ||||
| { | { | ||||
| struct pf_keyhash *kh; | struct pf_keyhash *kh; | ||||
| struct pf_idhash *ih; | struct pf_idhash *ih; | ||||
| struct pf_udpendpointhash *uh; | |||||
| struct pf_srchash *sh; | struct pf_srchash *sh; | ||||
| struct pf_send_entry *pfse, *next; | struct pf_send_entry *pfse, *next; | ||||
| u_int i; | u_int i; | ||||
| for (i = 0, kh = V_pf_keyhash, ih = V_pf_idhash; i <= pf_hashmask; | for (i = 0, kh = V_pf_keyhash, ih = V_pf_idhash, uh=V_pf_udpendpointhash; i <= pf_hashmask; | ||||
| i++, kh++, ih++) { | i++, kh++, ih++, uh++) { | ||||
Done Inline ActionsIs that right? What happens if V_pf_hashmask != V_pf_udpendpointhashmask? kp: Is that right? What happens if V_pf_hashmask != V_pf_udpendpointhashmask? | |||||
| KASSERT(LIST_EMPTY(&kh->keys), ("%s: key hash not empty", | KASSERT(LIST_EMPTY(&kh->keys), ("%s: key hash not empty", | ||||
| __func__)); | __func__)); | ||||
| KASSERT(LIST_EMPTY(&ih->states), ("%s: id hash not empty", | KASSERT(LIST_EMPTY(&ih->states), ("%s: id hash not empty", | ||||
| __func__)); | __func__)); | ||||
| KASSERT(LIST_EMPTY(&uh->endpoints), ("%s: udpendpoint hash not empty", | |||||
| __func__)); | |||||
| mtx_destroy(&kh->lock); | mtx_destroy(&kh->lock); | ||||
| mtx_destroy(&ih->lock); | mtx_destroy(&ih->lock); | ||||
| mtx_destroy(&uh->lock); | |||||
| } | } | ||||
| free(V_pf_keyhash, M_PFHASH); | free(V_pf_keyhash, M_PFHASH); | ||||
| free(V_pf_idhash, M_PFHASH); | free(V_pf_idhash, M_PFHASH); | ||||
| free(V_pf_udpendpointhash, M_PFHASH); | |||||
| for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask; i++, sh++) { | for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask; i++, sh++) { | ||||
| KASSERT(LIST_EMPTY(&sh->nodes), | KASSERT(LIST_EMPTY(&sh->nodes), | ||||
| ("%s: source node hash not empty", __func__)); | ("%s: source node hash not empty", __func__)); | ||||
| mtx_destroy(&sh->lock); | mtx_destroy(&sh->lock); | ||||
| } | } | ||||
| free(V_pf_srchash, M_PFHASH); | free(V_pf_srchash, M_PFHASH); | ||||
| STAILQ_FOREACH_SAFE(pfse, &V_pf_sendqueue, pfse_next, next) { | STAILQ_FOREACH_SAFE(pfse, &V_pf_sendqueue, pfse_next, next) { | ||||
| m_freem(pfse->pfse_m); | m_freem(pfse->pfse_m); | ||||
| free(pfse, M_PFTEMP); | free(pfse, M_PFTEMP); | ||||
| } | } | ||||
| uma_zdestroy(V_pf_sources_z); | uma_zdestroy(V_pf_sources_z); | ||||
| uma_zdestroy(V_pf_state_z); | uma_zdestroy(V_pf_state_z); | ||||
| uma_zdestroy(V_pf_state_key_z); | uma_zdestroy(V_pf_state_key_z); | ||||
| uma_zdestroy(V_pf_udp_mapping_z); | |||||
| } | } | ||||
| static int | static int | ||||
| pf_mtag_uminit(void *mem, int size, int how) | pf_mtag_uminit(void *mem, int size, int how) | ||||
| { | { | ||||
| struct m_tag *t; | struct m_tag *t; | ||||
| t = (struct m_tag *)mem; | t = (struct m_tag *)mem; | ||||
| ▲ Show 20 Lines • Show All 471 Lines • ▼ Show 20 Lines | if (inout == 1) { | ||||
| idx = PF_SK_STACK; | idx = PF_SK_STACK; | ||||
| goto second_run; | goto second_run; | ||||
| } | } | ||||
| PF_HASHROW_UNLOCK(kh); | PF_HASHROW_UNLOCK(kh); | ||||
| return (ret); | return (ret); | ||||
| } | } | ||||
| struct pf_udp_mapping* | |||||
| pf_udp_mapping_create(sa_family_t af, struct pf_addr *src_addr, uint16_t src_port, | |||||
| struct pf_addr *nat_addr, uint16_t nat_port) | |||||
| { | |||||
| struct pf_udp_mapping *mapping; | |||||
Not Done Inline ActionsPlease follow style(9), do not initialize variables in declaration. They rule may be violated sometimes, but calling function in initializer is too much! glebius: Please follow style(9), do not initialize variables in declaration. They rule may be violated… | |||||
| mapping = uma_zalloc(V_pf_udp_mapping_z, M_NOWAIT | M_ZERO); | |||||
| if (mapping == NULL) | |||||
| return NULL; | |||||
Not Done Inline Actionsstyle(9) kp: style(9) | |||||
Not Done Inline Actionsreturn (NULL); please. kp: return (NULL); please. | |||||
| PF_ACPY(&mapping->endpoints[0].addr, src_addr, af); | |||||
| mapping->endpoints[0].port = src_port; | |||||
| mapping->endpoints[0].af = af; | |||||
| mapping->endpoints[0].mapping = mapping; | |||||
| PF_ACPY(&mapping->endpoints[1].addr, nat_addr, af); | |||||
| mapping->endpoints[1].port = nat_port; | |||||
| mapping->endpoints[1].af = af; | |||||
| mapping->endpoints[1].mapping = mapping; | |||||
Not Done Inline ActionsPlease put return values into braces, to follow style(9). This refers to all new returns in this patch. glebius: Please put return values into braces, to follow style(9). This refers to all new returns in… | |||||
| refcount_init(&mapping->refs, 1); | |||||
| return (mapping); | |||||
| } | |||||
| int | |||||
| pf_udp_mapping_insert(struct pf_udp_mapping *mapping) | |||||
| { | |||||
| struct pf_udpendpointhash *h0, *h1; | |||||
| struct pf_udp_endpoint *endpoint; | |||||
| int ret = 1; | |||||
Done Inline ActionsI'd default to EEXIST, or maybe just switch to a bool return value. kp: I'd default to EEXIST, or maybe just switch to a bool return value. | |||||
| h0 = &V_pf_udpendpointhash[pf_hashudpendpoint(&mapping->endpoints[0])]; | |||||
| h1 = &V_pf_udpendpointhash[pf_hashudpendpoint(&mapping->endpoints[1])]; | |||||
| if (h0 == h1) { | |||||
| PF_HASHROW_LOCK(h0); | |||||
| } else if (h0 < h1) { | |||||
| PF_HASHROW_LOCK(h0); | |||||
| PF_HASHROW_LOCK(h1); | |||||
| } else { | |||||
| PF_HASHROW_LOCK(h1); | |||||
| PF_HASHROW_LOCK(h0); | |||||
| } | |||||
| LIST_FOREACH(endpoint, &h0->endpoints, entry) | |||||
| if (bcmp(endpoint, &mapping->endpoints[0], sizeof(struct pf_udp_endpoint_cmp)) == 0) | |||||
| break; | |||||
| if (endpoint != NULL) | |||||
| goto cleanup; | |||||
| LIST_FOREACH(endpoint, &h1->endpoints, entry) | |||||
| if (bcmp(endpoint, &mapping->endpoints[1], sizeof(struct pf_udp_endpoint_cmp)) == 0) | |||||
| break; | |||||
| if (endpoint != NULL) | |||||
| goto cleanup; | |||||
| LIST_INSERT_HEAD(&h0->endpoints, &mapping->endpoints[0], entry); | |||||
| LIST_INSERT_HEAD(&h1->endpoints, &mapping->endpoints[1], entry); | |||||
| ret = 0; | |||||
| cleanup: | |||||
| if (h0 != h1) { | |||||
| PF_HASHROW_UNLOCK(h0); | |||||
| PF_HASHROW_UNLOCK(h1); | |||||
| } else { | |||||
| PF_HASHROW_UNLOCK(h0); | |||||
Done Inline ActionsSeems to have wound up with spaces to rather than tabs here. kp: Seems to have wound up with spaces to rather than tabs here. | |||||
| } | |||||
| return (ret); | |||||
| } | |||||
| void | |||||
| pf_udp_mapping_release(struct pf_udp_mapping *mapping) | |||||
| { | |||||
| /* refcount is synchronized on the source endpoint's row lock */ | |||||
Not Done Inline ActionsPlease put empty line after declarations. glebius: Please put empty line after declarations. | |||||
| struct pf_udpendpointhash *h0, *h1; | |||||
| h0 = &V_pf_udpendpointhash[pf_hashudpendpoint(&mapping->endpoints[0])]; | |||||
| PF_HASHROW_LOCK(h0); | |||||
Done Inline ActionsI like that that's documented, but wonder if it wouldn't be more useful to put that in the struct definition instead. Or possibly both here and there. kp: I like that that's documented, but wonder if it wouldn't be more useful to put that in the… | |||||
| if (refcount_release(&mapping->refs)) { | |||||
| LIST_REMOVE(&mapping->endpoints[0], entry); | |||||
| PF_HASHROW_UNLOCK(h0); | |||||
| h1 = &V_pf_udpendpointhash[pf_hashudpendpoint(&mapping->endpoints[1])]; | |||||
| PF_HASHROW_LOCK(h1); | |||||
| LIST_REMOVE(&mapping->endpoints[1], entry); | |||||
| PF_HASHROW_UNLOCK(h1); | |||||
| uma_zfree(V_pf_udp_mapping_z, mapping); | |||||
Not Done Inline ActionsIs there a risk of races because we remove separate entries (why are there two?) non-atomically? kp: Is there a risk of races because we remove separate entries (why are there two?) non-atomically? | |||||
| } else { | |||||
| PF_HASHROW_UNLOCK(h0); | |||||
| } | |||||
| } | |||||
| struct pf_udp_mapping * | |||||
| pf_udp_mapping_find(struct pf_udp_endpoint_cmp *key) | |||||
| { | |||||
| struct pf_udpendpointhash *uh; | |||||
| struct pf_udp_endpoint *endpoint; | |||||
| uh = &V_pf_udpendpointhash[pf_hashudpendpoint((struct pf_udp_endpoint*)key)]; | |||||
| PF_HASHROW_LOCK(uh); | |||||
| LIST_FOREACH(endpoint, &uh->endpoints, entry) | |||||
| if (bcmp(endpoint, key, sizeof(struct pf_udp_endpoint_cmp)) == 0 && | |||||
| bcmp(endpoint, &endpoint->mapping->endpoints[0], sizeof(struct pf_udp_endpoint_cmp)) == 0) | |||||
| break; | |||||
| if (endpoint == NULL) { | |||||
| PF_HASHROW_UNLOCK(uh); | |||||
| return NULL; | |||||
| } | |||||
| refcount_acquire(&endpoint->mapping->refs); | |||||
| PF_HASHROW_UNLOCK(uh); | |||||
| return (endpoint->mapping); | |||||
| } | |||||
| /* END state table stuff */ | /* END state table stuff */ | ||||
Done Inline Actionsstyle(9). kp: style(9). | |||||
| static void | static void | ||||
| pf_send(struct pf_send_entry *pfse) | pf_send(struct pf_send_entry *pfse) | ||||
| { | { | ||||
| PF_SENDQ_LOCK(); | PF_SENDQ_LOCK(); | ||||
| STAILQ_INSERT_TAIL(&V_pf_sendqueue, pfse, pfse_next); | STAILQ_INSERT_TAIL(&V_pf_sendqueue, pfse, pfse_next); | ||||
| PF_SENDQ_UNLOCK(); | PF_SENDQ_UNLOCK(); | ||||
| ▲ Show 20 Lines • Show All 264 Lines • ▼ Show 20 Lines | pf_unlink_state(struct pf_state *s, u_int flags) | ||||
| s->timeout = PFTM_UNLINKED; | s->timeout = PFTM_UNLINKED; | ||||
| PF_HASHROW_UNLOCK(ih); | PF_HASHROW_UNLOCK(ih); | ||||
| pf_detach_state(s); | pf_detach_state(s); | ||||
| refcount_release(&s->refs); | refcount_release(&s->refs); | ||||
| if (s->udp_mapping) | |||||
| pf_udp_mapping_release(s->udp_mapping); | |||||
| return (pf_release_state(s)); | return (pf_release_state(s)); | ||||
| } | } | ||||
| void | void | ||||
| pf_free_state(struct pf_state *cur) | pf_free_state(struct pf_state *cur) | ||||
| { | { | ||||
| KASSERT(cur->refs == 0, ("%s: %p has refs", __func__, cur)); | KASSERT(cur->refs == 0, ("%s: %p has refs", __func__, cur)); | ||||
| ▲ Show 20 Lines • Show All 1,470 Lines • ▼ Show 20 Lines | pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, | ||||
| int tag = -1, rtableid = -1; | int tag = -1, rtableid = -1; | ||||
| int asd = 0; | int asd = 0; | ||||
| int match = 0; | int match = 0; | ||||
| int state_icmp = 0; | int state_icmp = 0; | ||||
| u_int16_t sport = 0, dport = 0; | u_int16_t sport = 0, dport = 0; | ||||
| u_int16_t bproto_sum = 0, bip_sum = 0; | u_int16_t bproto_sum = 0, bip_sum = 0; | ||||
| u_int8_t icmptype = 0, icmpcode = 0; | u_int8_t icmptype = 0, icmpcode = 0; | ||||
| struct pf_anchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | struct pf_anchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE]; | ||||
| struct pf_udp_mapping *udp_mapping = NULL; | |||||
Done Inline ActionsAlign *udp_mapping with the other variables with a tab. kp: Align *udp_mapping with the other variables with a tab. | |||||
| PF_RULES_RASSERT(); | PF_RULES_RASSERT(); | ||||
| if (inp != NULL) { | if (inp != NULL) { | ||||
| INP_LOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
| pd->lookup.uid = inp->inp_cred->cr_uid; | pd->lookup.uid = inp->inp_cred->cr_uid; | ||||
| pd->lookup.gid = inp->inp_cred->cr_groups[0]; | pd->lookup.gid = inp->inp_cred->cr_groups[0]; | ||||
| pd->lookup.done = 1; | pd->lookup.done = 1; | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | default: | ||||
| sport = dport = hdrlen = 0; | sport = dport = hdrlen = 0; | ||||
| break; | break; | ||||
| } | } | ||||
| r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); | r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); | ||||
| /* check packet for BINAT/NAT/RDR */ | /* check packet for BINAT/NAT/RDR */ | ||||
| if ((nr = pf_get_translation(pd, m, off, direction, kif, &nsn, &sk, | if ((nr = pf_get_translation(pd, m, off, direction, kif, &nsn, &sk, | ||||
| &nk, saddr, daddr, sport, dport, anchor_stack)) != NULL) { | &nk, saddr, daddr, sport, dport, anchor_stack, &udp_mapping)) != NULL) { | ||||
| KASSERT(sk != NULL, ("%s: null sk", __func__)); | KASSERT(sk != NULL, ("%s: null sk", __func__)); | ||||
| KASSERT(nk != NULL, ("%s: null nk", __func__)); | KASSERT(nk != NULL, ("%s: null nk", __func__)); | ||||
| if (pd->ip_sum) | if (pd->ip_sum) | ||||
| bip_sum = *pd->ip_sum; | bip_sum = *pd->ip_sum; | ||||
| switch (pd->proto) { | switch (pd->proto) { | ||||
| case IPPROTO_TCP: | case IPPROTO_TCP: | ||||
| ▲ Show 20 Lines • Show All 290 Lines • ▼ Show 20 Lines | #endif | ||||
| if (rtableid >= 0) | if (rtableid >= 0) | ||||
| M_SETFIB(m, rtableid); | M_SETFIB(m, rtableid); | ||||
| if (!state_icmp && (r->keep_state || nr != NULL || | if (!state_icmp && (r->keep_state || nr != NULL || | ||||
| (pd->flags & PFDESC_TCP_NORM))) { | (pd->flags & PFDESC_TCP_NORM))) { | ||||
| int action; | int action; | ||||
| action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off, | action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off, | ||||
| sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, | sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, | ||||
| hdrlen); | hdrlen, udp_mapping); | ||||
Done Inline ActionsI wonder if we shouldn't put the NULL check in pf_udp_mapping_release() instead. It looks like there are at least three callers, so that'd save a couple of lines of code too. kp: I wonder if we shouldn't put the NULL check in pf_udp_mapping_release() instead.
Similar to… | |||||
| if (action != PF_PASS) | if (action != PF_PASS) { | ||||
| if (udp_mapping != NULL) | |||||
| pf_udp_mapping_release(udp_mapping); | |||||
| return (action); | return (action); | ||||
| } | |||||
| } else { | } else { | ||||
| if (sk != NULL) | if (sk != NULL) | ||||
| uma_zfree(V_pf_state_key_z, sk); | uma_zfree(V_pf_state_key_z, sk); | ||||
| if (nk != NULL) | if (nk != NULL) | ||||
| uma_zfree(V_pf_state_key_z, nk); | uma_zfree(V_pf_state_key_z, nk); | ||||
| if (udp_mapping != NULL) | |||||
| pf_udp_mapping_release(udp_mapping); | |||||
| } | } | ||||
| /* copy back packet headers if we performed NAT operations */ | /* copy back packet headers if we performed NAT operations */ | ||||
| if (rewrite) | if (rewrite) | ||||
| m_copyback(m, off, hdrlen, pd->hdr.any); | m_copyback(m, off, hdrlen, pd->hdr.any); | ||||
| if (*sm != NULL && !((*sm)->state_flags & PFSTATE_NOSYNC) && | if (*sm != NULL && !((*sm)->state_flags & PFSTATE_NOSYNC) && | ||||
| direction == PF_OUT && | direction == PF_OUT && | ||||
| pfsync_defer_ptr != NULL && pfsync_defer_ptr(*sm, m)) | pfsync_defer_ptr != NULL && pfsync_defer_ptr(*sm, m)) | ||||
| /* | /* | ||||
| * We want the state created, but we dont | * We want the state created, but we dont | ||||
| * want to send this in case a partner | * want to send this in case a partner | ||||
| * firewall has to know about it to allow | * firewall has to know about it to allow | ||||
| * replies through it. | * replies through it. | ||||
| */ | */ | ||||
| return (PF_DEFER); | return (PF_DEFER); | ||||
| return (PF_PASS); | return (PF_PASS); | ||||
| cleanup: | cleanup: | ||||
| if (sk != NULL) | if (sk != NULL) | ||||
| uma_zfree(V_pf_state_key_z, sk); | uma_zfree(V_pf_state_key_z, sk); | ||||
| if (nk != NULL) | if (nk != NULL) | ||||
Done Inline ActionsDoesn't need the NULL check any more. kp: Doesn't need the NULL check any more. | |||||
| uma_zfree(V_pf_state_key_z, nk); | uma_zfree(V_pf_state_key_z, nk); | ||||
| if (udp_mapping != NULL) | |||||
| pf_udp_mapping_release(udp_mapping); | |||||
| return (PF_DROP); | return (PF_DROP); | ||||
| } | } | ||||
| static int | static int | ||||
| pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, | pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, | ||||
| struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *nk, | struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *nk, | ||||
| struct pf_state_key *sk, struct mbuf *m, int off, u_int16_t sport, | struct pf_state_key *sk, struct mbuf *m, int off, u_int16_t sport, | ||||
| u_int16_t dport, int *rewrite, struct pfi_kif *kif, struct pf_state **sm, | u_int16_t dport, int *rewrite, struct pfi_kif *kif, struct pf_state **sm, | ||||
| int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen) | int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, | ||||
| struct pf_udp_mapping *udp_mapping) | |||||
| { | { | ||||
| struct pf_state *s = NULL; | struct pf_state *s = NULL; | ||||
| struct pf_src_node *sn = NULL; | struct pf_src_node *sn = NULL; | ||||
| struct tcphdr *th = pd->hdr.tcp; | struct tcphdr *th = pd->hdr.tcp; | ||||
| u_int16_t mss = V_tcp_mssdflt; | u_int16_t mss = V_tcp_mssdflt; | ||||
| u_short reason; | u_short reason; | ||||
| /* check maximums */ | /* check maximums */ | ||||
| ▲ Show 20 Lines • Show All 189 Lines • ▼ Show 20 Lines | if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) == | ||||
| mss = pf_calc_mss(pd->dst, pd->af, rtid, mss); | mss = pf_calc_mss(pd->dst, pd->af, rtid, mss); | ||||
| s->src.mss = mss; | s->src.mss = mss; | ||||
| pf_send_tcp(NULL, r, pd->af, pd->dst, pd->src, th->th_dport, | pf_send_tcp(NULL, r, pd->af, pd->dst, pd->src, th->th_dport, | ||||
| th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, | th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, | ||||
| TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL); | TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL); | ||||
| REASON_SET(&reason, PFRES_SYNPROXY); | REASON_SET(&reason, PFRES_SYNPROXY); | ||||
| return (PF_SYNPROXY_DROP); | return (PF_SYNPROXY_DROP); | ||||
| } | } | ||||
| s->udp_mapping = udp_mapping; | |||||
| return (PF_PASS); | return (PF_PASS); | ||||
| csfailed: | csfailed: | ||||
| if (sk != NULL) | if (sk != NULL) | ||||
| uma_zfree(V_pf_state_key_z, sk); | uma_zfree(V_pf_state_key_z, sk); | ||||
| if (nk != NULL) | if (nk != NULL) | ||||
| uma_zfree(V_pf_state_key_z, nk); | uma_zfree(V_pf_state_key_z, nk); | ||||
| ▲ Show 20 Lines • Show All 2,871 Lines • Show Last 20 Lines | |||||
I seem to be missing the allocation (and freeing) of this. Am I looking in the wrong place or is it just not part of the patch?