Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf.c
Show First 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | static int pf_state_key_attach(struct pf_state_key *, | ||||
struct pf_state_key *, struct pf_kstate *); | struct pf_state_key *, struct pf_kstate *); | ||||
static void pf_state_key_detach(struct pf_kstate *, int); | static void pf_state_key_detach(struct pf_kstate *, int); | ||||
static int pf_state_key_ctor(void *, int, void *, int); | static int pf_state_key_ctor(void *, int, void *, int); | ||||
static u_int32_t pf_tcp_iss(struct pf_pdesc *); | static u_int32_t pf_tcp_iss(struct pf_pdesc *); | ||||
void pf_rule_to_actions(struct pf_krule *, | void pf_rule_to_actions(struct pf_krule *, | ||||
struct pf_rule_actions *); | struct pf_rule_actions *); | ||||
static int pf_dummynet(struct pf_pdesc *, int, struct pf_kstate *, | static int pf_dummynet(struct pf_pdesc *, int, struct pf_kstate *, | ||||
struct pf_krule *, struct mbuf **); | struct pf_krule *, struct mbuf **); | ||||
static int pf_dummynet_route(struct pf_pdesc *, int, | |||||
struct pf_kstate *, struct pf_krule *, | |||||
struct ifnet *, struct sockaddr *, struct mbuf **); | |||||
static int pf_test_eth_rule(int, struct pfi_kkif *, | static int pf_test_eth_rule(int, struct pfi_kkif *, | ||||
struct mbuf **); | struct mbuf **); | ||||
static int pf_test_rule(struct pf_krule **, struct pf_kstate **, | static int pf_test_rule(struct pf_krule **, struct pf_kstate **, | ||||
int, struct pfi_kkif *, struct mbuf *, int, | int, struct pfi_kkif *, struct mbuf *, int, | ||||
struct pf_pdesc *, struct pf_krule **, | struct pf_pdesc *, struct pf_krule **, | ||||
struct pf_kruleset **, struct inpcb *); | struct pf_kruleset **, struct inpcb *); | ||||
static int pf_create_state(struct pf_krule *, struct pf_krule *, | static int pf_create_state(struct pf_krule *, struct pf_krule *, | ||||
struct pf_krule *, struct pf_pdesc *, | struct pf_krule *, struct pf_pdesc *, | ||||
▲ Show 20 Lines • Show All 6,083 Lines • ▼ Show 20 Lines | if (ip_len <= ifp->if_mtu || | ||||
ip->ip_sum = 0; | ip->ip_sum = 0; | ||||
if (m0->m_pkthdr.csum_flags & CSUM_IP & ~ifp->if_hwassist) { | if (m0->m_pkthdr.csum_flags & CSUM_IP & ~ifp->if_hwassist) { | ||||
ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); | ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); | ||||
m0->m_pkthdr.csum_flags &= ~CSUM_IP; | m0->m_pkthdr.csum_flags &= ~CSUM_IP; | ||||
} | } | ||||
m_clrprotoflags(m0); /* Avoid confusing lower layers. */ | m_clrprotoflags(m0); /* Avoid confusing lower layers. */ | ||||
md = m0; | md = m0; | ||||
error = pf_dummynet(pd, dir, s, r, &md); | error = pf_dummynet_route(pd, dir, s, r, ifp, sintosa(&dst), &md); | ||||
if (md != NULL) | if (md != NULL) | ||||
error = (*ifp->if_output)(ifp, md, sintosa(&dst), NULL); | error = (*ifp->if_output)(ifp, md, sintosa(&dst), NULL); | ||||
goto done; | goto done; | ||||
} | } | ||||
/* Balk when DF bit is set or the interface didn't support TSO. */ | /* Balk when DF bit is set or the interface didn't support TSO. */ | ||||
if ((ip_off & IP_DF) || (m0->m_pkthdr.csum_flags & CSUM_TSO)) { | if ((ip_off & IP_DF) || (m0->m_pkthdr.csum_flags & CSUM_TSO)) { | ||||
error = EMSGSIZE; | error = EMSGSIZE; | ||||
Show All 16 Lines | if (error) | ||||
goto bad; | goto bad; | ||||
for (; m0; m0 = m1) { | for (; m0; m0 = m1) { | ||||
m1 = m0->m_nextpkt; | m1 = m0->m_nextpkt; | ||||
m0->m_nextpkt = NULL; | m0->m_nextpkt = NULL; | ||||
if (error == 0) { | if (error == 0) { | ||||
m_clrprotoflags(m0); | m_clrprotoflags(m0); | ||||
md = m0; | md = m0; | ||||
error = pf_dummynet(pd, dir, s, r, &md); | error = pf_dummynet_route(pd, dir, s, r, ifp, | ||||
sintosa(&dst), &md); | |||||
if (md != NULL) | if (md != NULL) | ||||
error = (*ifp->if_output)(ifp, md, | error = (*ifp->if_output)(ifp, md, | ||||
sintosa(&dst), NULL); | sintosa(&dst), NULL); | ||||
} else | } else | ||||
m_freem(m0); | m_freem(m0); | ||||
} | } | ||||
if (error == 0) | if (error == 0) | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, | ||||
/* | /* | ||||
* If the packet is too large for the outgoing interface, | * If the packet is too large for the outgoing interface, | ||||
* send back an icmp6 error. | * send back an icmp6 error. | ||||
*/ | */ | ||||
if (IN6_IS_SCOPE_EMBED(&dst.sin6_addr)) | if (IN6_IS_SCOPE_EMBED(&dst.sin6_addr)) | ||||
dst.sin6_addr.s6_addr16[1] = htons(ifp->if_index); | dst.sin6_addr.s6_addr16[1] = htons(ifp->if_index); | ||||
if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { | if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) { | ||||
md = m0; | md = m0; | ||||
pf_dummynet(pd, dir, s, r, &md); | pf_dummynet_route(pd, dir, s, r, ifp, sintosa(&dst), &md); | ||||
if (md != NULL) | if (md != NULL) | ||||
nd6_output_ifp(ifp, ifp, md, &dst, NULL); | nd6_output_ifp(ifp, ifp, md, &dst, NULL); | ||||
} | } | ||||
else { | else { | ||||
in6_ifstat_inc(ifp, ifs6_in_toobig); | in6_ifstat_inc(ifp, ifs6_in_toobig); | ||||
if (r->rt != PF_DUPTO) { | if (r->rt != PF_DUPTO) { | ||||
if (s && pd->nat_rule != NULL) | if (s && pd->nat_rule != NULL) | ||||
PACKET_UNDO_NAT(m0, pd, | PACKET_UNDO_NAT(m0, pd, | ||||
▲ Show 20 Lines • Show All 245 Lines • ▼ Show 20 Lines | pf_test_eth(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, | ||||
/* Stateless! */ | /* Stateless! */ | ||||
return (pf_test_eth_rule(dir, kif, m0)); | return (pf_test_eth_rule(dir, kif, m0)); | ||||
} | } | ||||
static int | static int | ||||
pf_dummynet(struct pf_pdesc *pd, int dir, struct pf_kstate *s, | pf_dummynet(struct pf_pdesc *pd, int dir, struct pf_kstate *s, | ||||
struct pf_krule *r, struct mbuf **m0) | struct pf_krule *r, struct mbuf **m0) | ||||
{ | { | ||||
return (pf_dummynet_route(pd, dir, s, r, NULL, NULL, m0)); | |||||
} | |||||
static int | |||||
pf_dummynet_route(struct pf_pdesc *pd, int dir, struct pf_kstate *s, | |||||
struct pf_krule *r, struct ifnet *ifp, struct sockaddr *sa, | |||||
struct mbuf **m0) | |||||
{ | |||||
NET_EPOCH_ASSERT(); | |||||
if (s && (s->dnpipe || s->dnrpipe)) { | if (s && (s->dnpipe || s->dnrpipe)) { | ||||
pd->act.dnpipe = s->dnpipe; | pd->act.dnpipe = s->dnpipe; | ||||
pd->act.dnrpipe = s->dnrpipe; | pd->act.dnrpipe = s->dnrpipe; | ||||
pd->act.flags = s->state_flags; | pd->act.flags = s->state_flags; | ||||
} else if (r->dnpipe || r->dnrpipe) { | } else if (r->dnpipe || r->dnrpipe) { | ||||
pd->act.dnpipe = r->dnpipe; | pd->act.dnpipe = r->dnpipe; | ||||
pd->act.dnrpipe = r->dnrpipe; | pd->act.dnrpipe = r->dnrpipe; | ||||
pd->act.flags = r->free_flags; | pd->act.flags = r->free_flags; | ||||
} | } | ||||
if (pd->act.dnpipe || pd->act.dnrpipe) { | if (pd->act.dnpipe || pd->act.dnrpipe) { | ||||
struct ip_fw_args dnflow; | struct ip_fw_args dnflow; | ||||
if (ip_dn_io_ptr == NULL) { | if (ip_dn_io_ptr == NULL) { | ||||
m_freem(*m0); | m_freem(*m0); | ||||
*m0 = NULL; | *m0 = NULL; | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
if (pd->pf_mtag == NULL && | if (pd->pf_mtag == NULL && | ||||
((pd->pf_mtag = pf_get_mtag(*m0)) == NULL)) { | ((pd->pf_mtag = pf_get_mtag(*m0)) == NULL)) { | ||||
m_freem(*m0); | m_freem(*m0); | ||||
*m0 = NULL; | *m0 = NULL; | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
if (ifp != NULL) { | |||||
pd->pf_mtag->flags |= PF_TAG_ROUTE_TO; | |||||
pd->pf_mtag->if_index = ifp->if_index; | |||||
glebius: Can we assert network epoch here? | |||||
Done Inline ActionsYeah, that makes sense. Pretty much all of pf runs under net_epoch, but an assert will make it more obvious that it's safe to access these fields here. kp: Yeah, that makes sense.
Pretty much all of pf runs under net_epoch, but an assert will make it… | |||||
pd->pf_mtag->if_idxgen = ifp->if_idxgen; | |||||
MPASS(sa != NULL); | |||||
if (pd->af == AF_INET) | |||||
memcpy(&pd->pf_mtag->dst, sa, | |||||
sizeof(struct sockaddr_in)); | |||||
else | |||||
memcpy(&pd->pf_mtag->dst, sa, | |||||
sizeof(struct sockaddr_in6)); | |||||
} | |||||
if (pf_pdesc_to_dnflow(dir, pd, r, s, &dnflow)) { | if (pf_pdesc_to_dnflow(dir, pd, r, s, &dnflow)) { | ||||
pd->pf_mtag->flags |= PF_TAG_DUMMYNET; | pd->pf_mtag->flags |= PF_TAG_DUMMYNET; | ||||
ip_dn_io_ptr(m0, &dnflow); | ip_dn_io_ptr(m0, &dnflow); | ||||
if (*m0 != NULL) | if (*m0 != NULL) | ||||
pd->pf_mtag->flags &= ~PF_TAG_DUMMYNET; | pd->pf_mtag->flags &= ~PF_TAG_DUMMYNET; | ||||
} | } | ||||
} | } | ||||
Show All 33 Lines | if (kif->pfik_flags & PFI_IFLAG_SKIP) | ||||
return (PF_PASS); | return (PF_PASS); | ||||
if (m->m_flags & M_SKIP_FIREWALL) | if (m->m_flags & M_SKIP_FIREWALL) | ||||
return (PF_PASS); | return (PF_PASS); | ||||
memset(&pd, 0, sizeof(pd)); | memset(&pd, 0, sizeof(pd)); | ||||
pd.pf_mtag = pf_find_mtag(m); | pd.pf_mtag = pf_find_mtag(m); | ||||
if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_TAG_ROUTE_TO)) { | |||||
pd.pf_mtag->flags &= ~PF_TAG_ROUTE_TO; | |||||
ifp = ifnet_byindexgen(pd.pf_mtag->if_index, | |||||
pd.pf_mtag->if_idxgen); | |||||
if (ifp == NULL || ifp->if_flags & IFF_DYING) { | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
return (PF_PASS); | |||||
} | |||||
(ifp->if_output)(ifp, m, sintosa(&pd.pf_mtag->dst), NULL); | |||||
*m0 = NULL; | |||||
return (PF_PASS); | |||||
} | |||||
if (pd.pf_mtag && pd.pf_mtag->dnpipe) { | if (pd.pf_mtag && pd.pf_mtag->dnpipe) { | ||||
pd.act.dnpipe = pd.pf_mtag->dnpipe; | pd.act.dnpipe = pd.pf_mtag->dnpipe; | ||||
pd.act.flags = pd.pf_mtag->dnflags; | pd.act.flags = pd.pf_mtag->dnflags; | ||||
} | } | ||||
if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && | if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && | ||||
pd.pf_mtag->flags & PF_TAG_DUMMYNET) { | pd.pf_mtag->flags & PF_TAG_DUMMYNET) { | ||||
/* Dummynet re-injects packets after they've | /* Dummynet re-injects packets after they've | ||||
▲ Show 20 Lines • Show All 457 Lines • ▼ Show 20 Lines | pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) | ||||
if (kif->pfik_flags & PFI_IFLAG_SKIP) | if (kif->pfik_flags & PFI_IFLAG_SKIP) | ||||
return (PF_PASS); | return (PF_PASS); | ||||
if (m->m_flags & M_SKIP_FIREWALL) | if (m->m_flags & M_SKIP_FIREWALL) | ||||
return (PF_PASS); | return (PF_PASS); | ||||
memset(&pd, 0, sizeof(pd)); | memset(&pd, 0, sizeof(pd)); | ||||
pd.pf_mtag = pf_find_mtag(m); | pd.pf_mtag = pf_find_mtag(m); | ||||
if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_TAG_ROUTE_TO)) { | |||||
pd.pf_mtag->flags &= ~PF_TAG_ROUTE_TO; | |||||
ifp = ifnet_byindexgen(pd.pf_mtag->if_index, | |||||
pd.pf_mtag->if_idxgen); | |||||
if (ifp == NULL || ifp->if_flags & IFF_DYING) { | |||||
Not Done Inline ActionsWhat do you think about changing ifnet_byindexgen() to never return IFF_DYING interfaces? P.S. I desire the need for this flag to be eliminated. glebius: What do you think about changing ifnet_byindexgen() to never return IFF_DYING interfaces?
P.S. | |||||
Done Inline ActionsThat would make sense to me, yes. kp: That would make sense to me, yes. | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
return (PF_PASS); | |||||
} | |||||
nd6_output_ifp(ifp, ifp, m, | |||||
(struct sockaddr_in6 *)&pd.pf_mtag->dst, NULL); | |||||
*m0 = NULL; | |||||
return (PF_PASS); | |||||
} | |||||
if (pd.pf_mtag && pd.pf_mtag->dnpipe) { | if (pd.pf_mtag && pd.pf_mtag->dnpipe) { | ||||
pd.act.dnpipe = pd.pf_mtag->dnpipe; | pd.act.dnpipe = pd.pf_mtag->dnpipe; | ||||
pd.act.flags = pd.pf_mtag->dnflags; | pd.act.flags = pd.pf_mtag->dnflags; | ||||
} | } | ||||
if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && | if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && | ||||
pd.pf_mtag->flags & PF_TAG_DUMMYNET) { | pd.pf_mtag->flags & PF_TAG_DUMMYNET) { | ||||
▲ Show 20 Lines • Show All 385 Lines • Show Last 20 Lines |
Can we assert network epoch here?