Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151294645
D41517.id126270.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
D41517.id126270.diff
View Options
Index: sys/net/pfvar.h
===================================================================
--- sys/net/pfvar.h
+++ sys/net/pfvar.h
@@ -1549,6 +1549,7 @@
char any[0];
} hdr;
+ int r_rt;
struct pf_krule *nat_rule; /* nat/rdr rule applied to packet */
struct pf_addr *src; /* src address */
struct pf_addr *dst; /* dst address */
@@ -2366,12 +2367,12 @@
const struct pf_addr *, const struct pf_addr *,
u_int16_t, u_int16_t, u_int32_t, u_int32_t,
u_int8_t, u_int16_t, u_int16_t, u_int8_t, bool,
- u_int16_t, u_int16_t, int);
+ u_int16_t, u_int16_t, int, struct pf_addr *);
void pf_send_tcp(const struct pf_krule *, sa_family_t,
- const struct pf_addr *, const struct pf_addr *,
- u_int16_t, u_int16_t, u_int32_t, u_int32_t,
- u_int8_t, u_int16_t, u_int16_t, u_int8_t, bool,
- u_int16_t, u_int16_t, int);
+ const struct pf_addr *, const struct pf_addr *,
+ u_int16_t, u_int16_t, u_int32_t, u_int32_t,
+ u_int8_t, u_int16_t, u_int16_t, u_int8_t, bool,
+ u_int16_t, u_int16_t, int, struct pf_addr *);
void pf_syncookies_init(void);
void pf_syncookies_cleanup(void);
Index: sys/netpfil/pf/pf.c
===================================================================
--- sys/netpfil/pf/pf.c
+++ sys/netpfil/pf/pf.c
@@ -274,9 +274,6 @@
static u_int32_t pf_tcp_iss(struct pf_pdesc *);
static int pf_dummynet(struct pf_pdesc *, struct pf_kstate *,
struct pf_krule *, struct mbuf **);
-static int pf_dummynet_route(struct pf_pdesc *,
- struct pf_kstate *, struct pf_krule *,
- struct ifnet *, struct sockaddr *, struct mbuf **);
static int pf_test_eth_rule(int, struct pfi_kkif *,
struct mbuf **);
static int pf_test_rule(struct pf_krule **, struct pf_kstate **,
@@ -330,19 +327,17 @@
static void pf_purge_unlinked_rules(void);
static int pf_mtag_uminit(void *, int, int);
static void pf_mtag_free(struct m_tag *);
-static void pf_packet_rework_nat(struct mbuf *, struct pf_pdesc *,
- int, struct pf_state_key *);
#ifdef INET
-static void pf_route(struct mbuf **, struct pf_krule *,
- struct ifnet *, struct pf_kstate *,
- struct pf_pdesc *, struct inpcb *);
+static int pf_route(struct mbuf **, struct mbuf **,
+ struct pf_krule *, struct pf_kstate *,
+ struct pf_pdesc *);
#endif /* INET */
#ifdef INET6
static void pf_change_a6(struct pf_addr *, u_int16_t *,
struct pf_addr *, u_int8_t);
-static void pf_route6(struct mbuf **, struct pf_krule *,
- struct ifnet *, struct pf_kstate *,
- struct pf_pdesc *, struct inpcb *);
+static int pf_route6(struct mbuf **, struct mbuf **,
+ struct pf_krule *, struct pf_kstate *,
+ struct pf_pdesc *);
#endif /* INET6 */
static __inline void pf_set_protostate(struct pf_kstate *, int, u_int8_t);
@@ -353,16 +348,6 @@
VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]);
-#define PACKET_UNDO_NAT(_m, _pd, _off, _s) \
- do { \
- struct pf_state_key *nk; \
- if ((pd->dir) == PF_OUT) \
- nk = (_s)->key[PF_SK_STACK]; \
- else \
- nk = (_s)->key[PF_SK_WIRE]; \
- pf_packet_rework_nat(_m, _pd, _off, nk); \
- } while (0)
-
#define PACKET_LOOPED(pd) ((pd)->pf_mtag && \
(pd)->pf_mtag->flags & PF_MTAG_FLAG_PACKET_LOOPED)
@@ -492,100 +477,6 @@
return (0);
}
-static void
-pf_packet_rework_nat(struct mbuf *m, struct pf_pdesc *pd, int off,
- struct pf_state_key *nk)
-{
-
- switch (pd->proto) {
- case IPPROTO_TCP: {
- struct tcphdr *th = &pd->hdr.tcp;
-
- if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af))
- pf_change_ap(m, pd->src, &th->th_sport, pd->ip_sum,
- &th->th_sum, &nk->addr[pd->sidx],
- nk->port[pd->sidx], 0, pd->af);
- if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af))
- pf_change_ap(m, pd->dst, &th->th_dport, pd->ip_sum,
- &th->th_sum, &nk->addr[pd->didx],
- nk->port[pd->didx], 0, pd->af);
- m_copyback(m, off, sizeof(*th), (caddr_t)th);
- break;
- }
- case IPPROTO_UDP: {
- struct udphdr *uh = &pd->hdr.udp;
-
- if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af))
- pf_change_ap(m, pd->src, &uh->uh_sport, pd->ip_sum,
- &uh->uh_sum, &nk->addr[pd->sidx],
- nk->port[pd->sidx], 1, pd->af);
- if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af))
- pf_change_ap(m, pd->dst, &uh->uh_dport, pd->ip_sum,
- &uh->uh_sum, &nk->addr[pd->didx],
- nk->port[pd->didx], 1, pd->af);
- m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
- break;
- }
- case IPPROTO_SCTP: {
- struct sctphdr *sh = &pd->hdr.sctp;
- uint16_t checksum = 0;
-
- if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af)) {
- pf_change_ap(m, pd->src, &sh->src_port, pd->ip_sum,
- &checksum, &nk->addr[pd->sidx],
- nk->port[pd->sidx], 1, pd->af);
- }
- if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af)) {
- pf_change_ap(m, pd->dst, &sh->dest_port, pd->ip_sum,
- &checksum, &nk->addr[pd->didx],
- nk->port[pd->didx], 1, pd->af);
- }
-
- break;
- }
- case IPPROTO_ICMP: {
- struct icmp *ih = &pd->hdr.icmp;
-
- if (nk->port[pd->sidx] != ih->icmp_id) {
- pd->hdr.icmp.icmp_cksum = pf_cksum_fixup(
- ih->icmp_cksum, ih->icmp_id,
- nk->port[pd->sidx], 0);
- ih->icmp_id = nk->port[pd->sidx];
- pd->sport = &ih->icmp_id;
-
- m_copyback(m, off, ICMP_MINLEN, (caddr_t)ih);
- }
- /* FALLTHROUGH */
- }
- default:
- if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af)) {
- switch (pd->af) {
- case AF_INET:
- pf_change_a(&pd->src->v4.s_addr,
- pd->ip_sum, nk->addr[pd->sidx].v4.s_addr,
- 0);
- break;
- case AF_INET6:
- PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
- break;
- }
- }
- if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af)) {
- switch (pd->af) {
- case AF_INET:
- pf_change_a(&pd->dst->v4.s_addr,
- pd->ip_sum, nk->addr[pd->didx].v4.s_addr,
- 0);
- break;
- case AF_INET6:
- PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
- break;
- }
- }
- break;
- }
-}
-
static __inline uint32_t
pf_hashkey(struct pf_state_key *sk)
{
@@ -1720,6 +1611,8 @@
pfse->pfse_m->m_pkthdr.csum_flags |=
CSUM_IP_VALID | CSUM_IP_CHECKED;
ip_input(pfse->pfse_m);
+ } else if (pfse->pfse_m->m_flags & M_IP_NEXTHOP) {
+ ip_forward(pfse->pfse_m, 1);
} else {
ip_output(pfse->pfse_m, NULL, NULL, 0, NULL,
NULL);
@@ -1736,6 +1629,8 @@
if (pf_isforlocal(pfse->pfse_m, AF_INET6)) {
pfse->pfse_m->m_flags |= M_SKIP_FIREWALL;
ip6_input(pfse->pfse_m);
+ } else if (pfse->pfse_m->m_flags & M_IP6_NEXTHOP) {
+ ip6_forward(pfse->pfse_m, 1);
} else {
ip6_output(pfse->pfse_m, NULL, NULL, 0, NULL,
NULL, NULL);
@@ -2078,7 +1973,8 @@
s->key[PF_SK_WIRE]->port[1],
s->key[PF_SK_WIRE]->port[0],
s->src.seqhi, s->src.seqlo + 1,
- TH_RST|TH_ACK, 0, 0, 0, true, s->tag, 0, s->act.rtableid);
+ TH_RST|TH_ACK, 0, 0, 0, true, s->tag, 0, s->act.rtableid,
+ NULL);
}
LIST_REMOVE(s, entry);
@@ -2828,15 +2724,20 @@
const struct pf_addr *saddr, const struct pf_addr *daddr,
u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
u_int8_t tcp_flags, u_int16_t win, u_int16_t mss, u_int8_t ttl,
- bool skip_firewall, u_int16_t mtag_tag, u_int16_t mtag_flags, int rtableid)
+ bool skip_firewall, u_int16_t mtag_tag, u_int16_t mtag_flags, int rtableid,
+ struct pf_addr *rt_addr)
{
struct mbuf *m;
+ struct m_tag *rt_mtag;
int len, tlen;
+ size_t rt_mtag_len;
#ifdef INET
struct ip *h = NULL;
+ struct sockaddr_in dst4;
#endif /* INET */
#ifdef INET6
struct ip6_hdr *h6 = NULL;
+ struct sockaddr_in6 dst6;
#endif /* INET6 */
struct tcphdr *th;
char *opt;
@@ -2884,6 +2785,58 @@
if (rtableid >= 0)
M_SETFIB(m, rtableid);
+ if (rt_addr != NULL) {
+
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ rt_mtag_len = sizeof(struct sockaddr_in);
+ bzero(&dst4, rt_mtag_len);
+ dst4.sin_family = AF_INET;
+ dst4.sin_len = rt_mtag_len;
+ dst4.sin_addr.s_addr = rt_addr->v4.s_addr;
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ rt_mtag_len = sizeof(struct sockaddr_in6);
+ bzero(&dst6, rt_mtag_len);
+ dst6.sin6_family = AF_INET6;
+ dst6.sin6_len = rt_mtag_len;
+ PF_ACPY((struct pf_addr *)&dst6.sin6_addr,
+ rt_addr, AF_INET6);
+ break;
+#endif /* INET6 */
+ default:
+ panic("%s: unsupported af %d", __func__, af);
+ }
+
+ rt_mtag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (rt_mtag == NULL) {
+ rt_mtag = m_tag_get(PACKET_TAG_IPFORWARD, rt_mtag_len,
+ M_NOWAIT);
+ if (rt_mtag == NULL) {
+ m_freem(m);
+ return (NULL);
+ }
+ m_tag_prepend(m, rt_mtag);
+ }
+ m->m_flags |= M_IP_NEXTHOP;
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ memcpy(rt_mtag+1, &dst4, rt_mtag_len);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ memcpy(rt_mtag+1, &dst6, rt_mtag_len);
+ break;
+#endif /* INET6 */
+ }
+
+ }
+
#ifdef ALTQ
if (r != NULL && r->qid) {
pf_mtag->qid = r->qid;
@@ -3094,18 +3047,20 @@
const struct pf_addr *saddr, const struct pf_addr *daddr,
u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
u_int8_t tcp_flags, u_int16_t win, u_int16_t mss, u_int8_t ttl,
- bool skip_firewall, u_int16_t mtag_tag, u_int16_t mtag_flags, int rtableid)
+ bool skip_firewall, u_int16_t mtag_tag, u_int16_t mtag_flags, int rtableid,
+ struct pf_addr *rt_addr)
{
struct pf_send_entry *pfse;
struct mbuf *m;
m = pf_build_tcp(r, af, saddr, daddr, sport, dport, seq, ack, tcp_flags,
- win, mss, ttl, skip_firewall, mtag_tag, mtag_flags, rtableid);
+ win, mss, ttl, skip_firewall, mtag_tag, mtag_flags, rtableid,
+ rt_addr);
if (m == NULL)
return;
/* Allocate outgoing queue entry, mbuf and mbuf tag. */
- pfse = malloc(sizeof(*pfse), M_PFTEMP, M_NOWAIT);
+ pfse = malloc(sizeof(*pfse), M_PFTEMP, M_NOWAIT | M_ZERO);
if (pfse == NULL) {
m_freem(m);
return;
@@ -3190,7 +3145,7 @@
pf_send_tcp(r, af, pd->dst,
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
- r->return_ttl, true, 0, 0, rtableid);
+ r->return_ttl, true, 0, 0, rtableid, NULL);
}
} else if (pd->proto == IPPROTO_SCTP &&
(r->rule_flag & PFRULE_RETURN)) {
@@ -4987,7 +4942,7 @@
pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport,
th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
TH_SYN|TH_ACK, 0, s->src.mss, 0, true, 0, 0,
- pd->act.rtableid);
+ pd->act.rtableid, NULL);
REASON_SET(&reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
@@ -5460,7 +5415,7 @@
th->th_sport, ntohl(th->th_ack), 0,
TH_RST, 0, 0,
(*state)->rule.ptr->return_ttl, true, 0, 0,
- (*state)->act.rtableid);
+ (*state)->act.rtableid, NULL);
src->seqlo = 0;
src->seqhi = 1;
src->max_win = 1;
@@ -5580,8 +5535,13 @@
static int
pf_synproxy(struct pf_pdesc *pd, struct pf_kstate **state, u_short *reason)
{
- struct pf_state_key *sk = (*state)->key[pd->didx];
- struct tcphdr *th = &pd->hdr.tcp;
+ struct pf_state_key *sk = (*state)->key[pd->didx];
+ struct tcphdr *th = &pd->hdr.tcp;
+ struct pf_addr *rt_addr = NULL;
+
+ if ((*state)->rt) {
+ rt_addr = &((*state)->rt_addr);
+ }
if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
if (pd->dir != (*state)->direction) {
@@ -5596,8 +5556,8 @@
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
pd->src, th->th_dport, th->th_sport,
(*state)->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, true, 0, 0,
- (*state)->act.rtableid);
+ TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, true, 0,
+ 0, (*state)->act.rtableid, NULL);
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if ((th->th_flags & (TH_ACK|TH_RST|TH_FIN)) != TH_ACK ||
@@ -5629,7 +5589,7 @@
sk->port[pd->sidx], sk->port[pd->didx],
(*state)->dst.seqhi, 0, TH_SYN, 0,
(*state)->src.mss, 0, false, (*state)->tag, 0,
- (*state)->act.rtableid);
+ (*state)->act.rtableid, rt_addr);
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
@@ -5642,15 +5602,15 @@
(*state)->dst.seqlo = ntohl(th->th_seq);
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
pd->src, th->th_dport, th->th_sport,
- ntohl(th->th_ack), ntohl(th->th_seq) + 1,
- TH_ACK, (*state)->src.max_win, 0, 0, false,
- (*state)->tag, 0, (*state)->act.rtableid);
+ ntohl(th->th_ack), ntohl(th->th_seq) + 1, TH_ACK,
+ (*state)->src.max_win, 0, 0, false, (*state)->tag,
+ 0, (*state)->act.rtableid, rt_addr);
pf_send_tcp((*state)->rule.ptr, pd->af,
&sk->addr[pd->sidx], &sk->addr[pd->didx],
sk->port[pd->sidx], sk->port[pd->didx],
(*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
TH_ACK, (*state)->dst.max_win, 0, 0, true, 0, 0,
- (*state)->act.rtableid);
+ (*state)->act.rtableid, NULL);
(*state)->src.seqdiff = (*state)->dst.seqhi -
(*state)->src.seqlo;
(*state)->dst.seqdiff = (*state)->src.seqhi -
@@ -6693,27 +6653,23 @@
}
#ifdef INET
-static void
-pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
- struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp)
+static int
+pf_route(struct mbuf **m, struct mbuf **mdup, struct pf_krule *r,
+ struct pf_kstate *s, struct pf_pdesc *pd)
{
- struct mbuf *m0, *m1, *md;
+ struct mbuf *m0;
+ struct m_tag *rt_mtag;
struct sockaddr_in dst;
struct ip *ip;
- struct ifnet *ifp = NULL;
struct pf_addr naddr;
struct pf_ksrc_node *sn = NULL;
- int error = 0;
- uint16_t ip_len, ip_off;
- int r_rt, r_dir;
+ int r_dir;
- KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
+ KASSERT(m && *m && r, ("%s: invalid parameters", __func__));
if (s) {
- r_rt = s->rt;
r_dir = s->direction;
} else {
- r_rt = r->rt;
r_dir = r->direction;
}
@@ -6726,45 +6682,23 @@
pd->pf_mtag->routed++ > 3) {
m0 = *m;
*m = NULL;
- goto bad_locked;
+ goto bad;
}
- if (r_rt == PF_DUPTO) {
- if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) {
- if (s == NULL) {
- ifp = r->rpool.cur->kif ?
- r->rpool.cur->kif->pfik_ifp : NULL;
- } else {
- ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
- /* If pfsync'd */
- if (ifp == NULL)
- ifp = r->rpool.cur->kif ?
- r->rpool.cur->kif->pfik_ifp : NULL;
- PF_STATE_UNLOCK(s);
- }
- if (ifp == oifp) {
- /* When the 2nd interface is not skipped */
- return;
- } else {
- m0 = *m;
- *m = NULL;
- goto bad;
- }
- } else {
- pd->pf_mtag->flags |= PF_MTAG_FLAG_DUPLICATED;
- if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) {
- if (s)
- PF_STATE_UNLOCK(s);
- return;
- }
+ if (pd->r_rt == PF_DUPTO) {
+ if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) {
+ return PF_PASS;
}
+ /*
+ * Original behaviour of pf was to emit the duplicated
+ * packet directly. We don't do it anymore in pf so
+ * set we set the M_SKIP_FIREWALL instead.
+ */
+ m0->m_flags |= M_SKIP_FIREWALL;
+ pd->pf_mtag->flags |= PF_MTAG_FLAG_DUPLICATED;
} else {
- if ((r_rt == PF_REPLYTO) == (r_dir == pd->dir)) {
- pf_dummynet(pd, s, r, m);
- if (s)
- PF_STATE_UNLOCK(s);
- return;
- }
+ if ((pd->r_rt == PF_REPLYTO) == (r_dir == pd->dir))
+ return PF_PASS;
m0 = *m;
}
@@ -6778,153 +6712,62 @@
bzero(&naddr, sizeof(naddr));
if (s == NULL) {
- if (TAILQ_EMPTY(&r->rpool.list)) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__));
- goto bad_locked;
- }
- pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
- &naddr, NULL, &sn);
- if (!PF_AZERO(&naddr, AF_INET))
- dst.sin_addr.s_addr = naddr.v4.s_addr;
- ifp = r->rpool.cur->kif ?
- r->rpool.cur->kif->pfik_ifp : NULL;
+ if (pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
+ &naddr, NULL, &sn) != 0)
+ goto bad;
+ dst.sin_addr.s_addr = naddr.v4.s_addr;
} else {
- if (!PF_AZERO(&s->rt_addr, AF_INET))
- dst.sin_addr.s_addr =
- s->rt_addr.v4.s_addr;
- ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
- PF_STATE_UNLOCK(s);
- }
- /* If pfsync'd */
- if (ifp == NULL)
- ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
- if (ifp == NULL)
- goto bad;
-
- if (pd->dir == PF_IN) {
- if (pf_test(PF_OUT, 0, ifp, &m0, inp, &pd->act) != PF_PASS)
- goto bad;
- else if (m0 == NULL)
- goto done;
- if (m0->m_len < sizeof(struct ip)) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: m0->m_len < sizeof(struct ip)\n", __func__));
- goto bad;
- }
- ip = mtod(m0, struct ip *);
- }
-
- if (ifp->if_flags & IFF_LOOPBACK)
- m0->m_flags |= M_SKIP_FIREWALL;
-
- ip_len = ntohs(ip->ip_len);
- ip_off = ntohs(ip->ip_off);
-
- /* Copied from FreeBSD 10.0-CURRENT ip_output. */
- m0->m_pkthdr.csum_flags |= CSUM_IP;
- if (m0->m_pkthdr.csum_flags & CSUM_DELAY_DATA & ~ifp->if_hwassist) {
- in_delayed_cksum(m0);
- m0->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- }
- if (m0->m_pkthdr.csum_flags & CSUM_SCTP & ~ifp->if_hwassist) {
- pf_sctp_checksum(m0, (uint32_t)(ip->ip_hl << 2));
- m0->m_pkthdr.csum_flags &= ~CSUM_SCTP;
+ dst.sin_addr.s_addr = s->rt_addr.v4.s_addr;
}
/*
- * If small enough for interface, or the interface will take
- * care of the fragmentation for us, we can just send directly.
+ * XXX Interface is ignored!
+ * That is sadly not yet reflected in structures, ioctls and userspace.
*/
- if (ip_len <= ifp->if_mtu ||
- (m0->m_pkthdr.csum_flags & ifp->if_hwassist & CSUM_TSO) != 0) {
- ip->ip_sum = 0;
- if (m0->m_pkthdr.csum_flags & CSUM_IP & ~ifp->if_hwassist) {
- ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
- m0->m_pkthdr.csum_flags &= ~CSUM_IP;
- }
- m_clrprotoflags(m0); /* Avoid confusing lower layers. */
- md = m0;
- error = pf_dummynet_route(pd, s, r, ifp, sintosa(&dst), &md);
- if (md != NULL)
- error = (*ifp->if_output)(ifp, md, sintosa(&dst), NULL);
- goto done;
- }
-
- /* 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)) {
- error = EMSGSIZE;
- KMOD_IPSTAT_INC(ips_cantfrag);
- if (r_rt != PF_DUPTO) {
- if (s && pd->nat_rule != NULL)
- PACKET_UNDO_NAT(m0, pd,
- (ip->ip_hl << 2) + (ip_off & IP_OFFMASK),
- s);
-
- icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
- ifp->if_mtu);
- goto done;
- } else
+ rt_mtag = m_tag_find(m0, PACKET_TAG_IPFORWARD, NULL);
+ if (rt_mtag == NULL) {
+ rt_mtag = m_tag_get(PACKET_TAG_IPFORWARD,
+ sizeof(struct sockaddr_in6), M_NOWAIT);
+ if (rt_mtag == NULL) {
goto bad;
+ }
+ m_tag_prepend(m0, rt_mtag);
+ }
+ m0->m_flags |= M_IP_NEXTHOP;
+ memcpy(rt_mtag+1, &dst, sizeof(struct sockaddr_in));
+
+ if (pd->r_rt == PF_DUPTO) {
+ *mdup = m0;
}
- error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist);
- if (error)
- goto bad;
+ return PF_PASS;
- for (; m0; m0 = m1) {
- m1 = m0->m_nextpkt;
- m0->m_nextpkt = NULL;
- if (error == 0) {
- m_clrprotoflags(m0);
- md = m0;
- error = pf_dummynet_route(pd, s, r, ifp,
- sintosa(&dst), &md);
- if (md != NULL)
- error = (*ifp->if_output)(ifp, md,
- sintosa(&dst), NULL);
- } else
- m_freem(m0);
- }
-
- if (error == 0)
- KMOD_IPSTAT_INC(ips_fragmented);
-
-done:
- if (r_rt != PF_DUPTO)
- *m = NULL;
- return;
-
-bad_locked:
- if (s)
- PF_STATE_UNLOCK(s);
bad:
m_freem(m0);
- goto done;
+ *m = NULL;
+ return PF_DROP;
}
#endif /* INET */
#ifdef INET6
-static void
-pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
- struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp)
+static int
+pf_route6(struct mbuf **m, struct mbuf **mdup, struct pf_krule *r,
+ struct pf_kstate *s, struct pf_pdesc *pd)
{
- struct mbuf *m0, *md;
+ struct mbuf *m0;
+ struct m_tag *rt_mtag;
struct sockaddr_in6 dst;
struct ip6_hdr *ip6;
- struct ifnet *ifp = NULL;
struct pf_addr naddr;
struct pf_ksrc_node *sn = NULL;
- int r_rt, r_dir;
+ int r_dir;
- KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
+ KASSERT(m && *m && r, ("%s: invalid parameters", __func__));
if (s) {
- r_rt = s->rt;
r_dir = s->direction;
} else {
- r_rt = r->rt;
r_dir = r->direction;
}
@@ -6937,45 +6780,23 @@
pd->pf_mtag->routed++ > 3) {
m0 = *m;
*m = NULL;
- goto bad_locked;
+ goto bad;
}
- if (r_rt == PF_DUPTO) {
- if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) {
- if (s == NULL) {
- ifp = r->rpool.cur->kif ?
- r->rpool.cur->kif->pfik_ifp : NULL;
- } else {
- ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
- /* If pfsync'd */
- if (ifp == NULL)
- ifp = r->rpool.cur->kif ?
- r->rpool.cur->kif->pfik_ifp : NULL;
- PF_STATE_UNLOCK(s);
- }
- if (ifp == oifp) {
- /* When the 2nd interface is not skipped */
- return;
- } else {
- m0 = *m;
- *m = NULL;
- goto bad;
- }
- } else {
- pd->pf_mtag->flags |= PF_MTAG_FLAG_DUPLICATED;
- if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) {
- if (s)
- PF_STATE_UNLOCK(s);
- return;
- }
+ if (pd->r_rt == PF_DUPTO) {
+ if (((m0 = m_dup(*m, M_NOWAIT)) == NULL)) {
+ return PF_PASS;
}
+ /*
+ * Original behaviour of pf was to emit the duplicated
+ * packet directly. We don't do it anymore in pf so
+ * set we set the M_SKIP_FIREWALL instead.
+ */
+ m0->m_flags |= M_SKIP_FIREWALL;
+ pd->pf_mtag->flags |= PF_MTAG_FLAG_DUPLICATED;
} else {
- if ((r_rt == PF_REPLYTO) == (r_dir == pd->dir)) {
- pf_dummynet(pd, s, r, m);
- if (s)
- PF_STATE_UNLOCK(s);
- return;
- }
+ if ((pd->r_rt == PF_REPLYTO) == (r_dir == pd->dir))
+ return PF_PASS;
m0 = *m;
}
@@ -6985,97 +6806,46 @@
dst.sin6_family = AF_INET6;
dst.sin6_len = sizeof(dst);
dst.sin6_addr = ip6->ip6_dst;
+ dst.sin6_scope_id = in6_get_unicast_scopeid(&ip6->ip6_dst, (*m)->m_pkthdr.rcvif);
bzero(&naddr, sizeof(naddr));
if (s == NULL) {
- if (TAILQ_EMPTY(&r->rpool.list)) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__));
- goto bad_locked;
- }
- pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
- &naddr, NULL, &sn);
- if (!PF_AZERO(&naddr, AF_INET6))
- PF_ACPY((struct pf_addr *)&dst.sin6_addr,
- &naddr, AF_INET6);
- ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
+ if (pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
+ &naddr, NULL, &sn) != 0)
+ goto bad;
+ PF_ACPY((struct pf_addr *)&dst.sin6_addr, &naddr, AF_INET6);
} else {
- if (!PF_AZERO(&s->rt_addr, AF_INET6))
- PF_ACPY((struct pf_addr *)&dst.sin6_addr,
- &s->rt_addr, AF_INET6);
- ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
- }
-
- if (s)
- PF_STATE_UNLOCK(s);
-
- /* If pfsync'd */
- if (ifp == NULL)
- ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
- if (ifp == NULL)
- goto bad;
-
- if (pd->dir == PF_IN) {
- if (pf_test6(PF_OUT, 0, ifp, &m0, inp, &pd->act) != PF_PASS)
- goto bad;
- else if (m0 == NULL)
- goto done;
- if (m0->m_len < sizeof(struct ip6_hdr)) {
- DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: m0->m_len < sizeof(struct ip6_hdr)\n",
- __func__));
- goto bad;
- }
- ip6 = mtod(m0, struct ip6_hdr *);
- }
-
- if (ifp->if_flags & IFF_LOOPBACK)
- m0->m_flags |= M_SKIP_FIREWALL;
-
- if (m0->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6 &
- ~ifp->if_hwassist) {
- uint32_t plen = m0->m_pkthdr.len - sizeof(*ip6);
- in6_delayed_cksum(m0, plen, sizeof(struct ip6_hdr));
- m0->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
+ PF_ACPY((struct pf_addr *)&dst.sin6_addr, &s->rt_addr, AF_INET6);
}
/*
- * If the packet is too large for the outgoing interface,
- * send back an icmp6 error.
+ * XXX Interface is ignored!
+ * That is sadly not yet reflected in structures, ioctls and userspace.
*/
- if (IN6_IS_SCOPE_EMBED(&dst.sin6_addr))
- dst.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
- if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
- md = m0;
- pf_dummynet_route(pd, s, r, ifp, sintosa(&dst), &md);
- if (md != NULL)
- nd6_output_ifp(ifp, ifp, md, &dst, NULL);
- }
- else {
- in6_ifstat_inc(ifp, ifs6_in_toobig);
- if (r_rt != PF_DUPTO) {
- if (s && pd->nat_rule != NULL)
- PACKET_UNDO_NAT(m0, pd,
- ((caddr_t)ip6 - m0->m_data) +
- sizeof(struct ip6_hdr), s);
- icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
- } else
+ rt_mtag = m_tag_find(m0, PACKET_TAG_IPFORWARD, NULL);
+ if (rt_mtag == NULL) {
+ rt_mtag = m_tag_get(PACKET_TAG_IPFORWARD,
+ sizeof(struct sockaddr_in), M_NOWAIT);
+ if (rt_mtag == NULL) {
goto bad;
+ }
+ m_tag_prepend(m0, rt_mtag);
+ }
+ m0->m_flags |= M_IP6_NEXTHOP;
+ memcpy(rt_mtag+1, &dst, sizeof(struct sockaddr_in6));
+
+ if (pd->r_rt == PF_DUPTO) {
+ *mdup = m0;
}
-done:
- if (r_rt != PF_DUPTO)
- *m = NULL;
- return;
+ return PF_PASS;
-bad_locked:
- if (s)
- PF_STATE_UNLOCK(s);
bad:
m_freem(m0);
- goto done;
+ *m = NULL;
+ return PF_DROP;
}
#endif /* INET6 */
@@ -7308,14 +7078,6 @@
static int
pf_dummynet(struct pf_pdesc *pd, struct pf_kstate *s,
struct pf_krule *r, struct mbuf **m0)
-{
- return (pf_dummynet_route(pd, s, r, NULL, NULL, m0));
-}
-
-static int
-pf_dummynet_route(struct pf_pdesc *pd, struct pf_kstate *s,
- struct pf_krule *r, struct ifnet *ifp, struct sockaddr *sa,
- struct mbuf **m0)
{
NET_EPOCH_ASSERT();
@@ -7334,27 +7096,10 @@
return (ENOMEM);
}
- if (ifp != NULL) {
- pd->pf_mtag->flags |= PF_MTAG_FLAG_ROUTE_TO;
-
- pd->pf_mtag->if_index = ifp->if_index;
- 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(pd, r, s, &dnflow)) {
pd->pf_mtag->flags |= PF_MTAG_FLAG_DUMMYNET;
ip_dn_io_ptr(m0, &dnflow);
if (*m0 != NULL) {
- pd->pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO;
pd->pf_mtag->flags &= ~PF_MTAG_FLAG_DUMMYNET;
}
}
@@ -7370,7 +7115,7 @@
{
struct pfi_kkif *kif;
u_short action, reason = 0;
- struct mbuf *m = *m0;
+ struct mbuf *m = *m0, *mdup = NULL;
struct ip *h = NULL;
struct m_tag *ipfwtag;
struct pf_krule *a = NULL, *r = &V_pf_default_rule, *tr, *nr;
@@ -7379,7 +7124,6 @@
struct pf_pdesc pd;
int off, dirndx, use_2nd_queue = 0;
uint16_t tag;
- uint8_t rt;
PF_RULES_RLOCK_TRACKER;
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
@@ -7413,23 +7157,6 @@
memcpy(&pd.act, default_actions, sizeof(pd.act));
pd.pf_mtag = pf_find_mtag(m);
- if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) {
- pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO;
-
- ifp = ifnet_byindexgen(pd.pf_mtag->if_index,
- pd.pf_mtag->if_idxgen);
- if (ifp == NULL || ifp->if_flags & IFF_DYING) {
- PF_RULES_RUNLOCK();
- m_freem(*m0);
- *m0 = NULL;
- return (PF_PASS);
- }
- PF_RULES_RUNLOCK();
- (ifp->if_output)(ifp, m, sintosa(&pd.pf_mtag->dst), NULL);
- *m0 = NULL;
- return (PF_PASS);
- }
-
if (pd.pf_mtag && pd.pf_mtag->dnpipe) {
pd.act.dnpipe = pd.pf_mtag->dnpipe;
pd.act.flags = pd.pf_mtag->dnflags;
@@ -7689,10 +7416,10 @@
if (s) {
memcpy(&pd.act, &s->act, sizeof(struct pf_rule_actions));
tag = s->tag;
- rt = s->rt;
+ pd.r_rt = s->rt;
} else {
tag = r->tag;
- rt = r->rt;
+ pd.r_rt = r->rt;
}
if (tag > 0 && pf_tag_packet(m, &pd, tag)) {
@@ -7890,14 +7617,14 @@
*m0 = NULL;
break;
default:
- /* pf_route() returns unlocked. */
- if (rt) {
- pf_route(m0, r, kif->pfik_ifp, s, &pd, inp);
- return (action);
+ if (pd.r_rt) {
+ action = pf_route(m0, &mdup, r, s, &pd);
}
- if (pf_dummynet(&pd, s, r, m0) != 0) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
+ if (*m0 != NULL) {
+ if (pf_dummynet(&pd, s, r, m0) != 0) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ }
}
break;
}
@@ -7907,6 +7634,10 @@
if (s)
PF_STATE_UNLOCK(s);
+ if (mdup != NULL) {
+ ip_output(mdup, NULL, NULL, 0, NULL, NULL);
+ }
+
return (action);
}
#endif /* INET */
@@ -7918,7 +7649,7 @@
{
struct pfi_kkif *kif;
u_short action, reason = 0;
- struct mbuf *m = *m0, *n = NULL;
+ struct mbuf *m = *m0, *n = NULL, *mdup = NULL;
struct m_tag *mtag;
struct ip6_hdr *h = NULL;
struct pf_krule *a = NULL, *r = &V_pf_default_rule, *tr, *nr;
@@ -7927,7 +7658,6 @@
struct pf_pdesc pd;
int off, terminal = 0, dirndx, rh_cnt = 0, use_2nd_queue = 0;
uint16_t tag;
- uint8_t rt;
PF_RULES_RLOCK_TRACKER;
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
@@ -7960,24 +7690,6 @@
memcpy(&pd.act, default_actions, sizeof(pd.act));
pd.pf_mtag = pf_find_mtag(m);
- if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) {
- pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO;
-
- ifp = ifnet_byindexgen(pd.pf_mtag->if_index,
- pd.pf_mtag->if_idxgen);
- if (ifp == NULL || ifp->if_flags & IFF_DYING) {
- PF_RULES_RUNLOCK();
- m_freem(*m0);
- *m0 = NULL;
- return (PF_PASS);
- }
- PF_RULES_RUNLOCK();
- 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) {
pd.act.dnpipe = pd.pf_mtag->dnpipe;
pd.act.flags = pd.pf_mtag->dnflags;
@@ -8157,7 +7869,6 @@
s->src.seqhi = ntohl(pd.hdr.tcp.th_ack) - 1;
s->src.seqlo = ntohl(pd.hdr.tcp.th_seq) - 1;
pf_set_protostate(s, PF_PEER_SRC, PF_TCPS_PROXY_DST);
-
action = pf_synproxy(&pd, &s, &reason);
break;
} else {
@@ -8286,10 +7997,10 @@
if (s) {
memcpy(&pd.act, &s->act, sizeof(struct pf_rule_actions));
tag = s->tag;
- rt = s->rt;
+ pd.r_rt = s->rt;
} else {
tag = r->tag;
- rt = r->rt;
+ pd.r_rt = r->rt;
}
if (tag > 0 && pf_tag_packet(m, &pd, tag)) {
@@ -8435,14 +8146,14 @@
*m0 = NULL;
break;
default:
- /* pf_route6() returns unlocked. */
- if (rt) {
- pf_route6(m0, r, kif->pfik_ifp, s, &pd, inp);
- return (action);
+ if (pd.r_rt) {
+ action = pf_route6(m0, &mdup, r, s, &pd);
}
- if (pf_dummynet(&pd, s, r, m0) != 0) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
+ if (*m0 != NULL) {
+ if (pf_dummynet(&pd, s, r, m0) != 0) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ }
}
break;
}
@@ -8450,6 +8161,10 @@
if (s)
PF_STATE_UNLOCK(s);
+ if (mdup != NULL) {
+ ip6_output(mdup, NULL, NULL, 0, NULL, NULL, NULL);
+ }
+
/* If reassembled packet passed, create new fragments. */
if (action == PF_PASS && *m0 && dir == PF_OUT &&
(mtag = m_tag_find(m, PACKET_TAG_PF_REASSEMBLED, NULL)) != NULL)
Index: sys/netpfil/pf/pf_mtag.h
===================================================================
--- sys/netpfil/pf/pf_mtag.h
+++ sys/netpfil/pf/pf_mtag.h
@@ -36,7 +36,7 @@
#ifdef _KERNEL
/* pf_mtag -> flags */
-#define PF_MTAG_FLAG_ROUTE_TO 0x01
+/* 0x01 unused */
#define PF_MTAG_FLAG_DUMMYNET 0x02
#define PF_MTAG_FLAG_TRANSLATE_LOCALHOST 0x04
#define PF_MTAG_FLAG_PACKET_LOOPED 0x08
Index: sys/netpfil/pf/pf_syncookies.c
===================================================================
--- sys/netpfil/pf/pf_syncookies.c
+++ sys/netpfil/pf/pf_syncookies.c
@@ -300,7 +300,7 @@
iss = pf_syncookie_generate(m, off, pd, mss);
pf_send_tcp(NULL, pd->af, pd->dst, pd->src, *pd->dport, *pd->sport,
iss, ntohl(pd->hdr.tcp.th_seq) + 1, TH_SYN|TH_ACK, 0, mss,
- 0, true, 0, 0, pd->act.rtableid);
+ 0, true, 0, 0, pd->act.rtableid, NULL);
counter_u64_add(V_pf_status.lcounters[KLCNT_SYNCOOKIES_SENT], 1);
/* XXX Maybe only in adaptive mode? */
atomic_add_64(&V_pf_status.syncookies_inflight[V_pf_syncookie_status.oddeven],
@@ -519,5 +519,5 @@
return (pf_build_tcp(NULL, pd->af, pd->src, pd->dst, *pd->sport,
*pd->dport, seq, 0, TH_SYN, wscale, mss, ttl, false, 0,
- PF_MTAG_FLAG_SYNCOOKIE_RECREATED, pd->act.rtableid));
+ PF_MTAG_FLAG_SYNCOOKIE_RECREATED, pd->act.rtableid, NULL));
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 8, 9:39 AM (9 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31092125
Default Alt Text
D41517.id126270.diff (31 KB)
Attached To
Mode
D41517: Draft: pf: Switch pf_route() to PACKET_TAG_IPFORWARD tag
Attached
Detach File
Event Timeline
Log In to Comment