Page MenuHomeFreeBSD

D41517.id126270.diff
No OneTemporary

D41517.id126270.diff

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

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)

Event Timeline