Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf.c
Show First 20 Lines • Show All 275 Lines • ▼ Show 20 Lines | |||||
static void pf_detach_state(struct pf_kstate *); | static void pf_detach_state(struct pf_kstate *); | ||||
static int pf_state_key_attach(struct pf_state_key *, | 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 *, | |||||
struct pf_krule *, 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 5,950 Lines • ▼ Show 20 Lines | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef INET | #ifdef INET | ||||
static void | static void | ||||
pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, | pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, | ||||
struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) | struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) | ||||
{ | { | ||||
struct mbuf *m0, *m1; | struct mbuf *m0, *m1, *md; | ||||
struct sockaddr_in dst; | struct sockaddr_in dst; | ||||
struct ip *ip; | struct ip *ip; | ||||
struct ifnet *ifp = NULL; | struct ifnet *ifp = NULL; | ||||
struct pf_addr naddr; | struct pf_addr naddr; | ||||
struct pf_ksrc_node *sn = NULL; | struct pf_ksrc_node *sn = NULL; | ||||
int error = 0; | int error = 0; | ||||
uint16_t ip_len, ip_off; | uint16_t ip_len, ip_off; | ||||
Show All 31 Lines | if ((pd->pf_mtag->flags & PF_DUPLICATED)) { | ||||
if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) { | if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) { | ||||
if (s) | if (s) | ||||
PF_STATE_UNLOCK(s); | PF_STATE_UNLOCK(s); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
if ((r->rt == PF_REPLYTO) == (r->direction == dir)) { | if ((r->rt == PF_REPLYTO) == (r->direction == dir)) { | ||||
pf_dummynet(pd, dir, s, r, m); | |||||
if (s) | if (s) | ||||
PF_STATE_UNLOCK(s); | PF_STATE_UNLOCK(s); | ||||
return; | return; | ||||
} | } | ||||
m0 = *m; | m0 = *m; | ||||
} | } | ||||
ip = mtod(m0, struct ip *); | ip = mtod(m0, struct ip *); | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | #endif | ||||
if (ip_len <= ifp->if_mtu || | if (ip_len <= ifp->if_mtu || | ||||
(m0->m_pkthdr.csum_flags & ifp->if_hwassist & CSUM_TSO) != 0) { | (m0->m_pkthdr.csum_flags & ifp->if_hwassist & CSUM_TSO) != 0) { | ||||
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. */ | ||||
error = (*ifp->if_output)(ifp, m0, sintosa(&dst), NULL); | |||||
md = m0; | |||||
error = pf_dummynet(pd, dir, s, r, &md); | |||||
if (md != 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; | ||||
KMOD_IPSTAT_INC(ips_cantfrag); | KMOD_IPSTAT_INC(ips_cantfrag); | ||||
if (r->rt != PF_DUPTO) { | if (r->rt != PF_DUPTO) { | ||||
Show All 13 Lines | #endif | ||||
if (error) | 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); | ||||
error = (*ifp->if_output)(ifp, m0, sintosa(&dst), NULL); | md = m0; | ||||
error = pf_dummynet(pd, dir, s, r, &md); | |||||
if (md != NULL) | |||||
error = (*ifp->if_output)(ifp, md, | |||||
sintosa(&dst), NULL); | |||||
} else | } else | ||||
m_freem(m0); | m_freem(m0); | ||||
} | } | ||||
if (error == 0) | if (error == 0) | ||||
KMOD_IPSTAT_INC(ips_fragmented); | KMOD_IPSTAT_INC(ips_fragmented); | ||||
done: | done: | ||||
Show All 10 Lines | |||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static void | static void | ||||
pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, | pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp, | ||||
struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) | struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) | ||||
{ | { | ||||
struct mbuf *m0; | struct mbuf *m0, *md; | ||||
struct sockaddr_in6 dst; | struct sockaddr_in6 dst; | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct ifnet *ifp = NULL; | struct ifnet *ifp = NULL; | ||||
struct pf_addr naddr; | struct pf_addr naddr; | ||||
struct pf_ksrc_node *sn = NULL; | struct pf_ksrc_node *sn = NULL; | ||||
KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__)); | KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__)); | ||||
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction", | KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction", | ||||
Show All 29 Lines | if ((pd->pf_mtag->flags & PF_DUPLICATED)) { | ||||
if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) { | if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) { | ||||
if (s) | if (s) | ||||
PF_STATE_UNLOCK(s); | PF_STATE_UNLOCK(s); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
if ((r->rt == PF_REPLYTO) == (r->direction == dir)) { | if ((r->rt == PF_REPLYTO) == (r->direction == dir)) { | ||||
pf_dummynet(pd, dir, s, r, m); | |||||
if (s) | if (s) | ||||
PF_STATE_UNLOCK(s); | PF_STATE_UNLOCK(s); | ||||
return; | return; | ||||
} | } | ||||
m0 = *m; | m0 = *m; | ||||
} | } | ||||
ip6 = mtod(m0, struct ip6_hdr *); | ip6 = mtod(m0, struct ip6_hdr *); | ||||
▲ Show 20 Lines • Show All 55 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) { | ||||
nd6_output_ifp(ifp, ifp, m0, &dst, NULL); | md = m0; | ||||
pf_dummynet(pd, dir, s, r, &md); | |||||
if (md != 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, | ||||
((caddr_t)ip6 - m0->m_data) + | ((caddr_t)ip6 - m0->m_data) + | ||||
sizeof(struct ip6_hdr), s, dir); | sizeof(struct ip6_hdr), s, dir); | ||||
▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | pf_test_eth(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, | ||||
if (m->m_flags & M_SKIP_FIREWALL) | if (m->m_flags & M_SKIP_FIREWALL) | ||||
return (PF_PASS); | return (PF_PASS); | ||||
/* Stateless! */ | /* Stateless! */ | ||||
return (pf_test_eth_rule(dir, kif, m0)); | return (pf_test_eth_rule(dir, kif, m0)); | ||||
} | } | ||||
static int | |||||
pf_dummynet(struct pf_pdesc *pd, int dir, struct pf_kstate *s, | |||||
struct pf_krule *r, struct mbuf **m0) | |||||
{ | |||||
if (s && (s->dnpipe || s->dnrpipe)) { | |||||
pd->act.dnpipe = s->dnpipe; | |||||
pd->act.dnrpipe = s->dnrpipe; | |||||
pd->act.flags = s->state_flags; | |||||
} else if (r->dnpipe || r->dnrpipe) { | |||||
pd->act.dnpipe = r->dnpipe; | |||||
pd->act.dnrpipe = r->dnrpipe; | |||||
pd->act.flags = r->free_flags; | |||||
} | |||||
if (pd->act.dnpipe || pd->act.dnrpipe) { | |||||
struct ip_fw_args dnflow; | |||||
if (ip_dn_io_ptr == NULL) { | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
return (ENOMEM); | |||||
} | |||||
if (pd->pf_mtag == NULL && | |||||
((pd->pf_mtag = pf_get_mtag(*m0)) == NULL)) { | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
return (ENOMEM); | |||||
} | |||||
if (pf_pdesc_to_dnflow(dir, pd, r, s, &dnflow)) { | |||||
pd->pf_mtag->flags |= PF_TAG_DUMMYNET; | |||||
ip_dn_io_ptr(m0, &dnflow); | |||||
if (*m0 != NULL) | |||||
pd->pf_mtag->flags &= ~PF_TAG_DUMMYNET; | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
#ifdef INET | #ifdef INET | ||||
int | int | ||||
pf_test(int dir, int pflags, 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_kkif *kif; | struct pfi_kkif *kif; | ||||
u_short action, reason = 0, log = 0; | u_short action, reason = 0, log = 0; | ||||
struct mbuf *m = *m0; | struct mbuf *m = *m0; | ||||
struct ip *h = NULL; | struct ip *h = NULL; | ||||
▲ Show 20 Lines • Show All 443 Lines • ▼ Show 20 Lines | case PF_DROP: | ||||
*m0 = NULL; | *m0 = NULL; | ||||
break; | break; | ||||
default: | default: | ||||
/* pf_route() returns unlocked. */ | /* pf_route() returns unlocked. */ | ||||
if (r->rt) { | if (r->rt) { | ||||
pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp); | pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp); | ||||
return (action); | return (action); | ||||
} | } | ||||
/* Dummynet processing. */ | if (pf_dummynet(&pd, dir, s, r, m0) != 0) { | ||||
if (s && (s->dnpipe || s->dnrpipe)) { | |||||
pd.act.dnpipe = s->dnpipe; | |||||
pd.act.dnrpipe = s->dnrpipe; | |||||
pd.act.flags = s->state_flags; | |||||
} else if (r->dnpipe || r->dnrpipe) { | |||||
pd.act.dnpipe = r->dnpipe; | |||||
pd.act.dnrpipe = r->dnrpipe; | |||||
pd.act.flags = r->free_flags; | |||||
} | |||||
if (pd.act.dnpipe || pd.act.dnrpipe) { | |||||
struct ip_fw_args dnflow; | |||||
if (ip_dn_io_ptr == NULL) { | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
break; | |||||
} | } | ||||
if (pd.pf_mtag == NULL && | |||||
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
action = PF_DROP; | |||||
REASON_SET(&reason, PFRES_MEMORY); | |||||
break; | break; | ||||
} | } | ||||
if (pf_pdesc_to_dnflow(dir, &pd, r, s, &dnflow)) { | |||||
pd.pf_mtag->flags |= PF_TAG_DUMMYNET; | |||||
ip_dn_io_ptr(m0, &dnflow); | |||||
if (*m0 != NULL) | |||||
pd.pf_mtag->flags &= ~PF_TAG_DUMMYNET; | |||||
} | |||||
} | |||||
break; | |||||
} | |||||
SDT_PROBE4(pf, ip, test, done, action, reason, r, s); | SDT_PROBE4(pf, ip, test, done, action, reason, r, s); | ||||
if (s) | if (s) | ||||
PF_STATE_UNLOCK(s); | PF_STATE_UNLOCK(s); | ||||
return (action); | return (action); | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
▲ Show 20 Lines • Show All 402 Lines • ▼ Show 20 Lines | case PF_DROP: | ||||
*m0 = NULL; | *m0 = NULL; | ||||
break; | break; | ||||
default: | default: | ||||
/* pf_route6() returns unlocked. */ | /* pf_route6() returns unlocked. */ | ||||
if (r->rt) { | if (r->rt) { | ||||
pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp); | pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp); | ||||
return (action); | return (action); | ||||
} | } | ||||
/* Dummynet processing. */ | if (pf_dummynet(&pd, dir, s, r, m0) != 0) { | ||||
if (s && (s->dnpipe || s->dnrpipe)) { | |||||
pd.act.dnpipe = s->dnpipe; | |||||
pd.act.dnrpipe = s->dnrpipe; | |||||
pd.act.flags = s->state_flags; | |||||
} else { | |||||
pd.act.dnpipe = r->dnpipe; | |||||
pd.act.dnrpipe = r->dnrpipe; | |||||
pd.act.flags = r->free_flags; | |||||
} | |||||
if (pd.act.dnpipe || pd.act.dnrpipe) { | |||||
struct ip_fw_args dnflow; | |||||
if (ip_dn_io_ptr == NULL) { | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
action = PF_DROP; | action = PF_DROP; | ||||
REASON_SET(&reason, PFRES_MEMORY); | REASON_SET(&reason, PFRES_MEMORY); | ||||
break; | |||||
} | |||||
if (pd.pf_mtag == NULL && | |||||
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { | |||||
m_freem(*m0); | |||||
*m0 = NULL; | |||||
action = PF_DROP; | |||||
REASON_SET(&reason, PFRES_MEMORY); | |||||
break; | |||||
} | |||||
if (pf_pdesc_to_dnflow(dir, &pd, r, s, &dnflow)) { | |||||
pd.pf_mtag->flags |= PF_TAG_DUMMYNET; | |||||
ip_dn_io_ptr(m0, &dnflow); | |||||
if (*m0 != NULL) | |||||
pd.pf_mtag->flags &= ~PF_TAG_DUMMYNET; | |||||
} | |||||
} | } | ||||
break; | break; | ||||
} | } | ||||
if (s) | if (s) | ||||
PF_STATE_UNLOCK(s); | PF_STATE_UNLOCK(s); | ||||
/* If reassembled packet passed, create new fragments. */ | /* If reassembled packet passed, create new fragments. */ | ||||
Show All 9 Lines |