diff --git a/contrib/tcpdump/print-pfsync.c b/contrib/tcpdump/print-pfsync.c index eb9aed8..1bad01c 100644 --- a/contrib/tcpdump/print-pfsync.c +++ b/contrib/tcpdump/print-pfsync.c @@ -396,22 +396,22 @@ print_state(netdissect_options *ndo, struct pfsync_state *s) ND_PRINT((ndo, "\t%s ", s->ifname)); ND_PRINT((ndo, "proto %u ", s->proto)); - print_host(ndo, &nk->addr[1], nk->port[1], s->af, NULL); - if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) || + print_host(ndo, &nk->addr[1], nk->port[1], nk->af, NULL); + if (PF_ANEQ(&nk->addr[1], &sk->addr[1], nk->af) || nk->port[1] != sk->port[1]) { ND_PRINT((ndo, " (")); - print_host(ndo, &sk->addr[1], sk->port[1], s->af, NULL); + print_host(ndo, &sk->addr[1], sk->port[1], nk->af, NULL); ND_PRINT((ndo, ")")); } if (s->direction == PF_OUT) ND_PRINT((ndo, " -> ")); else ND_PRINT((ndo, " <- ")); - print_host(ndo, &nk->addr[0], nk->port[0], s->af, NULL); - if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) || + print_host(ndo, &nk->addr[0], nk->port[0], nk->af, NULL); + if (PF_ANEQ(&nk->addr[0], &sk->addr[0], nk->af) || nk->port[0] != sk->port[0]) { ND_PRINT((ndo, " (")); - print_host(ndo, &sk->addr[0], sk->port[0], s->af, NULL); + print_host(ndo, &sk->addr[0], sk->port[0], nk->af, NULL); ND_PRINT((ndo, ")")); } diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 934037c..956f652 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -28,7 +28,7 @@ */ %{ #include -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: stable/11/sbin/pfctl/parse.y 303864 2016-08-09 03:39:21Z loos $"); #include #include @@ -447,7 +447,7 @@ int parseport(char *, struct range *r, int); %token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE -%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF +%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT NAT64 BINAT ARROW NODF %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR @@ -3593,8 +3593,8 @@ tos : STRING { else if ($1[0] == '0' && $1[1] == 'x') $$ = strtoul($1, NULL, 16); else - $$ = 256; /* flag bad argument */ - if ($$ < 0 || $$ > 255) { + $$ = 0; /* flag bad argument */ + if (!$$ || $$ > 255) { yyerror("illegal tos value %s", $1); free($1); YYERROR; @@ -3603,7 +3603,7 @@ tos : STRING { } | NUMBER { $$ = $1; - if ($$ < 0 || $$ > 255) { + if (!$$ || $$ > 255) { yyerror("illegal tos value %s", $1); YYERROR; } @@ -4017,6 +4017,19 @@ nataction : no NAT natpasslog { $$.w = $3.b2; $$.w2 = $3.w2; } + | no NAT64 natpasslog { + if ($1 && $3.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } + if ($1) + $$.b1 = PF_NONAT64; + else + $$.b1 = PF_NAT64; + $$.b2 = $3.b1; + $$.w = $3.b2; + $$.w2 = $3.w2; + } | no RDR natpasslog { if ($1 && $3.b1) { yyerror("\"pass\" not valid with \"no\""); @@ -4048,6 +4061,12 @@ natrule : nataction interface af proto fromto tag tagged rtable r.logif = $1.w2; r.af = $3; + if ((r.action == PF_NAT64 || r.action == PF_NONAT64) + && r.af && r.af != AF_INET6) { + yyerror("nat64 can only match on inet6"); + YYERROR; + } + if (!r.af) { if ($5.src.host && $5.src.host->af && !$5.src.host->ifindex) @@ -4075,7 +4094,8 @@ natrule : nataction interface af proto fromto tag tagged rtable r.match_tag_not = $7.neg; r.rtableid = $8; - if (r.action == PF_NONAT || r.action == PF_NORDR) { + if (r.action == PF_NONAT || r.action == PF_NORDR + || r.action == PF_NONAT64) { if ($9 != NULL) { yyerror("translation rule with 'no' " "does not need '->'"); @@ -4090,10 +4110,13 @@ natrule : nataction interface af proto fromto tag tagged rtable if (!r.af && ! $9->host->ifindex) r.af = $9->host->af; - remove_invalid_hosts(&$9->host, &r.af); - if (invalid_redirect($9->host, r.af)) + r.rpool.af = r.action == PF_NAT64 ? AF_INET : + r.af; + + remove_invalid_hosts(&$9->host, &r.rpool.af); + if (invalid_redirect($9->host, r.rpool.af)) YYERROR; - if (check_netmask($9->host, r.af)) + if (check_netmask($9->host, r.rpool.af)) YYERROR; r.rpool.proxy_port[0] = ntohs($9->rport.a); @@ -4113,6 +4136,7 @@ natrule : nataction interface af proto fromto tag tagged rtable ntohs($9->rport.b); break; case PF_NAT: + case PF_NAT64: r.rpool.proxy_port[1] = ntohs($9->rport.b); if (!r.rpool.proxy_port[0] && @@ -4157,6 +4181,18 @@ natrule : nataction interface af proto fromto tag tagged rtable } } } + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_BITMASK && r.action == PF_NAT64) { + yyerror("nat64 doesn't support bitmask " + "pool type"); + YYERROR; + } + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_SRCHASH && r.action == PF_NAT64) { + yyerror("nat64 doesn't support " + "source-hash pool type"); + YYERROR; + } if ($10.key != NULL) memcpy(&r.rpool.key, $10.key, @@ -4229,6 +4265,7 @@ binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag "undefined"); YYERROR; } + binat.rpool.af = binat.af; if ($4 != NULL) { memcpy(binat.ifname, $4->ifname, @@ -5501,6 +5538,7 @@ lookup(char *s) { "modulate", MODULATE}, { "nat", NAT}, { "nat-anchor", NATANCHOR}, + { "nat64", NAT64}, { "no", NO}, { "no-df", NODF}, { "no-route", NOROUTE}, diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c index 346e623..8ad4774 100644 --- a/sbin/pfctl/pf_print_state.c +++ b/sbin/pfctl/pf_print_state.c @@ -31,7 +31,7 @@ */ #include -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: stable/11/sbin/pfctl/pf_print_state.c 295086 2016-01-30 22:03:14Z ian $"); #include #include @@ -241,22 +241,22 @@ print_state(struct pfsync_state *s, int opts) else printf("%u ", s->proto); - print_host(&nk->addr[1], nk->port[1], s->af, opts); - if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) || + print_host(&nk->addr[1], nk->port[1], nk->af, opts); + if (nk->af != sk->af || PF_ANEQ(&nk->addr[1], &sk->addr[1], nk->af) || nk->port[1] != sk->port[1]) { printf(" ("); - print_host(&sk->addr[1], sk->port[1], s->af, opts); + print_host(&sk->addr[1], sk->port[1], sk->af, opts); printf(")"); } if (s->direction == PF_OUT) printf(" -> "); else printf(" <- "); - print_host(&nk->addr[0], nk->port[0], s->af, opts); - if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) || + print_host(&nk->addr[0], nk->port[0], nk->af, opts); + if (nk->af != sk->af || PF_ANEQ(&nk->addr[0], &sk->addr[0], nk->af) || nk->port[0] != sk->port[0]) { printf(" ("); - print_host(&sk->addr[0], sk->port[0], s->af, opts); + print_host(&sk->addr[0], sk->port[0], sk->af, opts); printf(")"); } diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 43d9dc5..2fb61a6 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -32,7 +32,7 @@ */ #include -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: stable/11/sbin/pfctl/pfctl.c 290236 2015-11-01 17:20:17Z kp $"); #include #include @@ -1346,7 +1346,8 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth) name = ""; if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (pfctl_add_pool(pf, &r->rpool, r->af)) + if (pfctl_add_pool(pf, &r->rpool, + r->action == PF_NAT64 ? AF_INET : r->af)) return (1); pr.pool_ticket = pf->paddr.ticket; memcpy(&pr.rule, r, sizeof(pr.rule)); diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 4bb1477..755964f 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -32,7 +32,7 @@ */ #include -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: stable/11/sbin/pfctl/pfctl_parser.c 301998 2016-06-17 18:21:55Z kp $"); #include #include @@ -408,6 +408,7 @@ print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, TAILQ_FOREACH(pooladdr, &pool->list, entries){ switch (id) { case PF_NAT: + case PF_NAT64: case PF_RDR: case PF_BINAT: print_addr(&pooladdr->addr, af, 0); @@ -431,6 +432,7 @@ print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, } switch (id) { case PF_NAT: + case PF_NAT64: if ((p1 != PF_NAT_PROXY_PORT_LOW || p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) { if (p1 == p2) @@ -655,6 +657,7 @@ print_src_node(struct pf_src_node *sn, int opts) sn->bytes[0] + sn->bytes[1]); #endif switch (sn->ruletype) { + case PF_NAT64: case PF_NAT: if (sn->rule.nr != -1) printf(", nat rule %u", sn->rule.nr); @@ -676,15 +679,16 @@ void print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) { static const char *actiontypes[] = { "pass", "block", "scrub", - "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" }; + "no scrub", "nat", "no nat", "binat", "no binat", + "rdr", "no rdr" , "nat64", "no nat64"}; static const char *anchortypes[] = { "anchor", "anchor", "anchor", "anchor", "nat-anchor", "nat-anchor", "binat-anchor", - "binat-anchor", "rdr-anchor", "rdr-anchor" }; + "binat-anchor", "rdr-anchor", "rdr-anchor", "nat64-anchor", "nat64-anchor" }; int i, opts; if (verbose) printf("@%d ", r->nr); - if (r->action > PF_NORDR) + if (r->action > PF_NONAT64) printf("action(%d)", r->action); else if (anchor_call[0]) { if (anchor_call[0] == '_') { @@ -1035,10 +1039,12 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) #endif } if (!anchor_call[0] && (r->action == PF_NAT || - r->action == PF_BINAT || r->action == PF_RDR)) { + r->action == PF_BINAT || r->action == PF_RDR || + r->action == PF_NAT64)) { printf(" -> "); print_pool(&r->rpool, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], r->af, r->action); + r->rpool.proxy_port[1], + r->action == PF_NAT64 ? AF_INET : r->af, r->action); } } diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 2b5ca39..1d0081d 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -364,6 +364,7 @@ struct pf_pool { int tblidx; u_int16_t proxy_port[2]; u_int8_t opts; + sa_family_t af; }; @@ -780,6 +781,7 @@ struct pfsync_state_peer { struct pfsync_state_key { struct pf_addr addr[2]; u_int16_t port[2]; + sa_family_t af; }; struct pfsync_state { @@ -797,7 +799,7 @@ struct pfsync_state { u_int32_t packets[2][2]; u_int32_t bytes[2][2]; u_int32_t creatorid; - sa_family_t af; + //sa_family_t af; u_int8_t proto; u_int8_t direction; u_int8_t __spare[2]; @@ -1119,6 +1121,7 @@ struct pf_pdesc { sa_family_t af; u_int8_t proto; u_int8_t tos; + u_int8_t ttl; u_int8_t dir; /* direction */ u_int8_t sidx; /* key index for source */ u_int8_t didx; /* key index for destination */ @@ -1561,6 +1564,10 @@ extern void pf_print_state(struct pf_state *); extern void pf_print_flags(u_int8_t); extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t, u_int8_t); +extern u_int16_t pf_cksum_remove(uint16_t, uint16_t *, + uint16_t *, int); +extern u_int16_t pf_cksum_add(uint16_t, uint16_t *, uint16_t *, + int); extern u_int16_t pf_proto_cksum_fixup(struct mbuf *, u_int16_t, u_int16_t, u_int16_t, u_int8_t); @@ -1750,7 +1757,7 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, uint16_t, uint16_t, struct pf_anchor_stackframe *); struct pf_state_key *pf_state_key_setup(struct pf_pdesc *, struct pf_addr *, - struct pf_addr *, u_int16_t, u_int16_t); + struct pf_addr *, u_int16_t, u_int16_t, struct pf_rule *); struct pf_state_key *pf_state_key_clone(struct pf_state_key *); #endif /* _KERNEL */ diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index de6494e..9b0661c 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -465,8 +465,8 @@ pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) ks = &sp->key[PF_SK_STACK]; #endif - if (PF_ANEQ(&kw->addr[0], &ks->addr[0], sp->af) || - PF_ANEQ(&kw->addr[1], &ks->addr[1], sp->af) || + if (PF_ANEQ(&kw->addr[0], &ks->addr[0], ks->af) || + PF_ANEQ(&kw->addr[1], &ks->addr[1], ks->af) || kw->port[0] != ks->port[0] || kw->port[1] != ks->port[1]) { sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT); @@ -486,14 +486,14 @@ pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) skw->port[0] = kw->port[0]; skw->port[1] = kw->port[1]; skw->proto = sp->proto; - skw->af = sp->af; + skw->af = kw->af; if (sks != skw) { sks->addr[0] = ks->addr[0]; sks->addr[1] = ks->addr[1]; sks->port[0] = ks->port[0]; sks->port[1] = ks->port[1]; sks->proto = sp->proto; - sks->af = sp->af; + sks->af = ks->af; } /* copy to state */ @@ -735,8 +735,9 @@ pfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) for (i = 0; i < count; i++) { sp = &sa[i]; + /* BABAK - disabled this to figure out what is the right thing to do */ /* Check for invalid values. */ - if (sp->timeout >= PFTM_MAX || +/* if (sp->timeout >= PFTM_MAX || sp->src.state > PF_TCPS_PROXY_DST || sp->dst.state > PF_TCPS_PROXY_DST || sp->direction > PF_OUT || @@ -746,7 +747,7 @@ pfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) V_pfsyncstats.pfsyncs_badval++; continue; } - +*/ if (pfsync_state_import(sp, pkt->flags) == ENOMEM) /* Drop out, but process the rest of the actions. */ break; diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 2d32b7a..16725af 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -36,7 +36,7 @@ */ #include -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: stable/11/sys/netpfil/pf/pf.c 302156 2016-06-23 21:34:38Z bz $"); #include "opt_inet.h" #include "opt_inet6.h" @@ -208,7 +208,7 @@ static int pf_check_threshold(struct pf_threshold *); static void pf_change_ap(struct mbuf *, struct pf_addr *, u_int16_t *, u_int16_t *, u_int16_t *, struct pf_addr *, - u_int16_t, u_int8_t, sa_family_t); + u_int16_t, u_int8_t, sa_family_t, sa_family_t); static int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *, struct tcphdr *, struct pf_state_peer *); static void pf_change_icmp(struct pf_addr *, u_int16_t *, @@ -295,6 +295,10 @@ static void pf_change_a6(struct pf_addr *, u_int16_t *, static void pf_route6(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *, struct pf_pdesc *); +void pf_change_addr(struct pf_addr *a, u_int16_t *c, + struct pf_addr *an, u_int8_t u, + sa_family_t af, sa_family_t afn); + #endif /* INET6 */ int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); @@ -985,7 +989,8 @@ keyattach: PF_HASHROW_LOCK(ih); if (si->kif == s->kif && - si->direction == s->direction) { + ((si->key[0]->af == sk->af && si->direction == s->direction) + || (si->key[0]->af != si->key[1]->af && sk->af == si->key[1]->af && si->direction != s->direction))) { if (sk->proto == IPPROTO_TCP && si->src.state >= TCPS_FIN_WAIT_2 && si->dst.state >= TCPS_FIN_WAIT_2) { @@ -1148,7 +1153,7 @@ pf_state_key_ctor(void *mem, int size, void *arg, int flags) struct pf_state_key * pf_state_key_setup(struct pf_pdesc *pd, struct pf_addr *saddr, - struct pf_addr *daddr, u_int16_t sport, u_int16_t dport) + struct pf_addr *daddr, u_int16_t sport, u_int16_t dport, struct pf_rule *nr) { struct pf_state_key *sk; @@ -1161,7 +1166,7 @@ pf_state_key_setup(struct pf_pdesc *pd, struct pf_addr *saddr, sk->port[pd->sidx] = sport; sk->port[pd->didx] = dport; sk->proto = pd->proto; - sk->af = pd->af; + sk->af = nr->action == PF_NAT64 ? AF_INET : pd->af; return (sk); } @@ -1292,6 +1297,7 @@ pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir) /* List is sorted, if-bound states before floating ones. */ TAILQ_FOREACH(s, &sk->states[idx], key_list[idx]) if (s->kif == V_pfi_all || s->kif == kif) { + /* BABAK patch:392 */ PF_STATE_LOCK(s); PF_HASHROW_UNLOCK(kh); if (s->timeout >= PFTM_MAX) { @@ -2044,13 +2050,14 @@ pf_proto_cksum_fixup(struct mbuf *m, u_int16_t cksum, u_int16_t old, static void pf_change_ap(struct mbuf *m, struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc, struct pf_addr *an, u_int16_t pn, u_int8_t u, - sa_family_t af) + sa_family_t af, sa_family_t afn) { struct pf_addr ao; u_int16_t po = *p; PF_ACPY(&ao, a, af); PF_ACPY(a, an, af); + PF_ACPY(a, an, afn); if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6)) *pc = ~*pc; @@ -2060,33 +2067,71 @@ pf_change_ap(struct mbuf *m, struct pf_addr *a, u_int16_t *p, u_int16_t *ic, switch (af) { #ifdef INET case AF_INET: - *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, - ao.addr16[0], an->addr16[0], 0), - ao.addr16[1], an->addr16[1], 0); - *p = pn; - - *pc = pf_cksum_fixup(pf_cksum_fixup(*pc, - ao.addr16[0], an->addr16[0], u), - ao.addr16[1], an->addr16[1], u); - - *pc = pf_proto_cksum_fixup(m, *pc, po, pn, u); + switch (afn) { + case AF_INET: + *ic = pf_cksum_fixup(pf_cksum_fixup(*ic, + ao.addr16[0], an->addr16[0], 0), + ao.addr16[1], an->addr16[1], 0); + *p = pn; + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + po, pn, u); + break; +#ifdef INET6 + case AF_INET6: + *p = pn; + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + 0, an->addr16[2], u), + 0, an->addr16[3], u), + 0, an->addr16[4], u), + 0, an->addr16[5], u), + 0, an->addr16[6], u), + 0, an->addr16[7], u), + po, pn, u); + break; +#endif /* INET6 */ + } break; #endif /* INET */ #ifdef INET6 case AF_INET6: - *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(*pc, - ao.addr16[0], an->addr16[0], u), - ao.addr16[1], an->addr16[1], u), - ao.addr16[2], an->addr16[2], u), - ao.addr16[3], an->addr16[3], u), - ao.addr16[4], an->addr16[4], u), - ao.addr16[5], an->addr16[5], u), - ao.addr16[6], an->addr16[6], u), - ao.addr16[7], an->addr16[7], u); - - *pc = pf_proto_cksum_fixup(m, *pc, po, pn, u); + switch (afn) { +#ifdef INET + case AF_INET: + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], 0, u), + ao.addr16[3], 0, u), + ao.addr16[4], 0, u), + ao.addr16[5], 0, u), + ao.addr16[6], 0, u), + ao.addr16[7], 0, u), + po, pn, u); + break; +#endif /* INET */ + case AF_INET6: + *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], an->addr16[2], u), + ao.addr16[3], an->addr16[3], u), + ao.addr16[4], an->addr16[4], u), + ao.addr16[5], an->addr16[5], u), + ao.addr16[6], an->addr16[6], u), + ao.addr16[7], an->addr16[7], u), + po, pn, u); + break; + } break; #endif /* INET6 */ } @@ -2145,6 +2190,59 @@ pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u) ao.addr16[6], an->addr16[6], u), ao.addr16[7], an->addr16[7], u); } + +void +pf_change_addr(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u, + sa_family_t af, sa_family_t afn) +{ + struct pf_addr ao; + + PF_ACPY(&ao, a, af); + PF_ACPY(a, an, afn); + + switch (af) { + case AF_INET: + switch (afn) { + case AF_INET: + pf_change_a(a, c, an->v4.s_addr, u); + break; + case AF_INET6: + *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*c, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + 0, an->addr16[2], u), + 0, an->addr16[3], u), + 0, an->addr16[4], u), + 0, an->addr16[5], u), + 0, an->addr16[6], u), + 0, an->addr16[7], u); + break; + } + break; + case AF_INET6: + switch (afn) { + case AF_INET: + *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*c, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], 0, u), + ao.addr16[3], 0, u), + ao.addr16[4], 0, u), + ao.addr16[5], 0, u), + ao.addr16[6], 0, u), + ao.addr16[7], 0, u); + break; + case AF_INET6: + pf_change_a6(a, c, an, u); + break; + } + break; + } +} #endif /* INET6 */ static void @@ -2600,8 +2698,8 @@ pf_match_addr_range(struct pf_addr *b, struct pf_addr *e, switch (af) { #ifdef INET case AF_INET: - if ((ntohl(a->addr32[0]) < ntohl(b->addr32[0])) || - (ntohl(a->addr32[0]) > ntohl(e->addr32[0]))) + if ((a->addr32[0] < b->addr32[0]) || + (a->addr32[0] > e->addr32[0])) return (0); break; #endif /* INET */ @@ -2611,15 +2709,15 @@ pf_match_addr_range(struct pf_addr *b, struct pf_addr *e, /* check a >= b */ for (i = 0; i < 4; ++i) - if (ntohl(a->addr32[i]) > ntohl(b->addr32[i])) + if (a->addr32[i] > b->addr32[i]) break; - else if (ntohl(a->addr32[i]) < ntohl(b->addr32[i])) + else if (a->addr32[i] < b->addr32[i]) return (0); /* check a <= e */ for (i = 0; i < 4; ++i) - if (ntohl(a->addr32[i]) < ntohl(e->addr32[i])) + if (a->addr32[i] < e->addr32[i]) break; - else if (ntohl(a->addr32[i]) > ntohl(e->addr32[i])) + else if (a->addr32[i] > e->addr32[i]) return (0); break; } @@ -3101,6 +3199,137 @@ pf_tcp_iss(struct pf_pdesc *pd) } static int +pf_nat64_icmp6(struct icmp6_hdr *icmp6) +{ + u_int16_t type; + u_int16_t code; + u_int16_t mtu; + + type = icmp6->icmp6_type; + code = icmp6->icmp6_code; + mtu = icmp6->icmp6_mtu; + + if (type & ICMP6_INFOMSG_MASK) { + switch (type) { + case ICMP6_ECHO_REQUEST: + type = ICMP_ECHO; + break; + case ICMP6_ECHO_REPLY: + type = ICMP_ECHOREPLY; + break; + default: + return PF_DROP; + } + } else { + switch (type) { + case ICMP6_DST_UNREACH: + type = ICMP_UNREACH; + switch (code) { + case ICMP6_DST_UNREACH_NOROUTE: + case ICMP6_DST_UNREACH_BEYONDSCOPE: + case ICMP6_DST_UNREACH_ADDR: + code = ICMP_UNREACH_HOST; + break; + case ICMP6_DST_UNREACH_ADMIN: + code = ICMP_UNREACH_HOST_PROHIB; + break; + case ICMP6_DST_UNREACH_NOPORT: + code = ICMP_UNREACH_PORT; + break; + default: + return PF_DROP; + } + break; + case ICMP6_PACKET_TOO_BIG: + type = ICMP_UNREACH; + code = ICMP_UNREACH_NEEDFRAG; + mtu -= 20; + break; + case ICMP6_TIME_EXCEEDED: + type = ICMP_TIMXCEED; + break; + case ICMP6_PARAM_PROB: + if (code == ICMP6_PARAMPROB_NEXTHEADER) + { + type = ICMP_UNREACH; + code = ICMP_UNREACH_PROTOCOL; + } else { + type = ICMP_PARAMPROB; + code = 0; + } + /* TODO update pointer */ + break; + default: + return PF_DROP; + } + } + + if (icmp6->icmp6_type != type) { + icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum, + icmp6->icmp6_type, type, 0); + icmp6->icmp6_type = type; + } + if (icmp6->icmp6_code != code) { + icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum, + icmp6->icmp6_code, code, 0); + icmp6->icmp6_code = code; + } + if (icmp6->icmp6_mtu != mtu) { + icmp6->icmp6_cksum = pf_cksum_fixup(icmp6->icmp6_cksum, + icmp6->icmp6_mtu, mtu, 0); + icmp6->icmp6_mtu = mtu; + } + + return PF_PASS; +} + +static int +pf_nat64_ipv6(struct mbuf *m, int off, struct pf_pdesc *pd, + struct pf_state_key *nk) +{ + struct ip *ip4; + + m_adj(m, off); + if (!(m = m_prepend(m, sizeof(*ip4), M_NOWAIT))) + return PF_DROP; + ip4 = mtod(m, struct ip *); + ip4->ip_v = 4; + ip4->ip_hl = 5; + ip4->ip_tos = pd->tos & htonl(0x0ff00000); + ip4->ip_len = htons(sizeof(*ip4) + (pd->tot_len - off)); + ip4->ip_id = 0; + ip4->ip_off = htons(IP_DF); + ip4->ip_ttl = pd->ttl; + ip4->ip_p = pd->proto; + ip4->ip_sum = 0; + ip4->ip_src = nk->addr[pd->didx].v4; + ip4->ip_dst = nk->addr[pd->sidx].v4; + ip4->ip_sum = in_cksum(m, ip4->ip_hl << 2); + ip_input(m); + return PF_DEFER; +} + +static int +pf_nat64_ipv4(struct mbuf *m, int off, struct pf_pdesc *pd, + struct pf_state_key *nk) +{ + struct ip6_hdr *ip6; + + m_adj(m, off); + if (!(m = m_prepend(m, sizeof(*ip6), M_NOWAIT))) + return PF_DROP; + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_vfc = htonl((6 << 28) | (pd->tos << 20)); + ip6->ip6_plen = htons(pd->tot_len - off); + ip6->ip6_nxt = pd->proto; + ip6->ip6_hlim = pd->ttl; + ip6->ip6_src = nk->addr[pd->didx].v6; + ip6->ip6_dst = nk->addr[pd->sidx].v6; + ip6_input(m); + return PF_DEFER; +} + +static int pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, struct pfi_kif *kif, struct mbuf *m, int off, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct inpcb *inp) @@ -3108,7 +3337,6 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, struct pf_rule *nr = NULL; struct pf_addr * const saddr = pd->src; struct pf_addr * const daddr = pd->dst; - sa_family_t af = pd->af; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; @@ -3164,7 +3392,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, #endif /* INET */ #ifdef INET6 case IPPROTO_ICMPV6: - if (af != AF_INET6) + if (pd->af != AF_INET6) break; sport = dport = pd->hdr.icmp6->icmp6_id; hdrlen = sizeof(*pd->hdr.icmp6); @@ -3199,20 +3427,22 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, bproto_sum = th->th_sum; pd->proto_sum = &th->th_sum; - if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || + if (pd->af != nk->af || + PF_ANEQ(saddr, &nk->addr[pd->sidx], pd->af) || nk->port[pd->sidx] != sport) { pf_change_ap(m, saddr, &th->th_sport, pd->ip_sum, &th->th_sum, &nk->addr[pd->sidx], - nk->port[pd->sidx], 0, af); + nk->port[pd->sidx], 0, pd->af, nk->af); pd->sport = &th->th_sport; sport = th->th_sport; } - if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || + if (pd->af != nk->af || + PF_ANEQ(daddr, &nk->addr[pd->didx], pd->af) || nk->port[pd->didx] != dport) { pf_change_ap(m, daddr, &th->th_dport, pd->ip_sum, &th->th_sum, &nk->addr[pd->didx], - nk->port[pd->didx], 0, af); + nk->port[pd->didx], 0, pd->af, nk->af); dport = th->th_dport; pd->dport = &th->th_dport; } @@ -3222,22 +3452,24 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, bproto_sum = pd->hdr.udp->uh_sum; pd->proto_sum = &pd->hdr.udp->uh_sum; - if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || + if (pd->af != nk->af || + PF_ANEQ(saddr, &nk->addr[pd->sidx], pd->af) || nk->port[pd->sidx] != sport) { pf_change_ap(m, saddr, &pd->hdr.udp->uh_sport, pd->ip_sum, &pd->hdr.udp->uh_sum, &nk->addr[pd->sidx], - nk->port[pd->sidx], 1, af); + nk->port[pd->sidx], 1, pd->af, nk->af); sport = pd->hdr.udp->uh_sport; pd->sport = &pd->hdr.udp->uh_sport; } - if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || + if (pd->af != nk->af || + PF_ANEQ(daddr, &nk->addr[pd->didx], pd->af) || nk->port[pd->didx] != dport) { pf_change_ap(m, daddr, &pd->hdr.udp->uh_dport, pd->ip_sum, &pd->hdr.udp->uh_sum, &nk->addr[pd->didx], - nk->port[pd->didx], 1, af); + nk->port[pd->didx], 1, pd->af, nk->af); dport = pd->hdr.udp->uh_dport; pd->dport = &pd->hdr.udp->uh_dport; } @@ -3245,6 +3477,9 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, break; #ifdef INET case IPPROTO_ICMP: + if (pd->af != AF_INET) + break; + nk->port[0] = nk->port[1]; if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET)) pf_change_a(&saddr->v4.s_addr, pd->ip_sum, @@ -3266,51 +3501,75 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, #endif /* INET */ #ifdef INET6 case IPPROTO_ICMPV6: - nk->port[0] = nk->port[1]; - if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6)) - pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, - &nk->addr[pd->sidx], 0); + if (pd->af != AF_INET6) + break; - if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6)) - pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, - &nk->addr[pd->didx], 0); + nk->port[0] = nk->port[1]; /* BABAK - should be removed? patch:799 */ + + if (nk->af != AF_INET6 || + PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6)) + pf_change_addr(saddr, + &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[pd->sidx], 0, AF_INET6, nk->af); + + if (nk->af != AF_INET6 || + PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6)) + pf_change_addr(daddr, + &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[pd->didx], 0, AF_INET6, nk->af); + + if (nk->af != AF_INET6) { + int action; + if ((action = pf_nat64_icmp6(pd->hdr.icmp6)) != + PF_PASS) + return action; + pd->hdr.icmp->icmp_cksum = + pf_cksum_fixup(pd->hdr.icmp->icmp_cksum, + pd->proto, IPPROTO_ICMP, 0); + pd->proto = IPPROTO_ICMP; + } rewrite++; break; #endif /* INET */ default: - switch (af) { + switch (pd->af) { #ifdef INET case AF_INET: - if (PF_ANEQ(saddr, + if (nk->af != AF_INET || PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET)) - pf_change_a(&saddr->v4.s_addr, - pd->ip_sum, - nk->addr[pd->sidx].v4.s_addr, 0); - - if (PF_ANEQ(daddr, - &nk->addr[pd->didx], AF_INET)) - pf_change_a(&daddr->v4.s_addr, - pd->ip_sum, - nk->addr[pd->didx].v4.s_addr, 0); + pf_change_addr(saddr, pd->ip_sum, + &nk->addr[pd->sidx], 0, + AF_INET, nk->af); + + if (nk->af != AF_INET || PF_ANEQ(daddr, + &nk->addr[pd->didx], AF_INET)) + pf_change_addr(daddr, pd->ip_sum, + &nk->addr[pd->didx], 0, + AF_INET, nk->af); break; #endif /* INET */ #ifdef INET6 case AF_INET6: if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6)) - PF_ACPY(saddr, &nk->addr[pd->sidx], af); + PF_ACPY(saddr, &nk->addr[pd->sidx], + pd->af); if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6)) - PF_ACPY(saddr, &nk->addr[pd->didx], af); + PF_ACPY(saddr, &nk->addr[pd->didx], + pd->af); break; #endif /* INET */ } break; } + if (nr->natpass) r = NULL; pd->nat_rule = nr; + + pd->af = nk->af; } while (r != NULL) { @@ -3319,18 +3578,18 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, r = r->skip[PF_SKIP_IFP].ptr; else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR].ptr; - else if (r->af && r->af != af) + else if (r->af && r->af != pd->af) r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, saddr, af, + else if (PF_MISMATCHAW(&r->src.addr, saddr, pd->af, r->src.neg, kif, M_GETFIB(m))) r = r->skip[PF_SKIP_SRC_ADDR].ptr; /* tcp/udp only. port_op always 0 in other cases */ else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], sport)) r = r->skip[PF_SKIP_SRC_PORT].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, + else if (PF_MISMATCHAW(&r->dst.addr, daddr, pd->af, r->dst.neg, NULL, M_GETFIB(m))) r = r->skip[PF_SKIP_DST_ADDR].ptr; /* tcp/udp only. port_op always 0 in other cases */ @@ -3407,7 +3666,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->log || (nr != NULL && nr->log)) { if (rewrite) m_copyback(m, off, hdrlen, pd->hdr.any); - PFLOG_PACKET(kif, m, af, direction, reason, r->log ? r : nr, a, + PFLOG_PACKET(kif, m, pd->af, direction, reason, r->log ? r : nr, a, ruleset, pd, 1); } @@ -3416,9 +3675,11 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, (r->rule_flag & PFRULE_RETURNICMP) || (r->rule_flag & PFRULE_RETURN))) { /* undo NAT changes, if they have taken place */ - if (nr != NULL) { - PF_ACPY(saddr, &sk->addr[pd->sidx], af); - PF_ACPY(daddr, &sk->addr[pd->didx], af); + if (nr != NULL && + (nr->action != PF_NAT64 && nr->action != PF_NONAT64)) { + pd->af = sk->af; + PF_ACPY(saddr, &sk->addr[pd->sidx], pd->af); + PF_ACPY(daddr, &sk->addr[pd->didx], pd->af); if (pd->sport) *pd->sport = sk->port[pd->sidx]; if (pd->dport) @@ -3442,7 +3703,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, struct ip6_hdr *h6; #endif - switch (af) { + switch (pd->af) { #ifdef INET case AF_INET: h4 = mtod(m, struct ip *); @@ -3457,26 +3718,26 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, #endif } - if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) + if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, pd->af)) REASON_SET(&reason, PFRES_PROTCKSUM); else { if (th->th_flags & TH_SYN) ack++; if (th->th_flags & TH_FIN) ack++; - pf_send_tcp(m, r, af, pd->dst, + pf_send_tcp(m, r, pd->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, 1, 0, kif->pfik_ifp); } - } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && + } else if (pd->proto != IPPROTO_ICMP && pd->af == AF_INET && r->return_icmp) pf_send_icmp(m, r->return_icmp >> 8, - r->return_icmp & 255, af, r); - else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && + r->return_icmp & 255, pd->af, r); + else if (pd->proto != IPPROTO_ICMPV6 && pd->af == AF_INET6 && r->return_icmp6) pf_send_icmp(m, r->return_icmp6 >> 8, - r->return_icmp6 & 255, af, r); + r->return_icmp6 & 255, pd->af, r); } if (r->action == PF_DROP) @@ -3505,8 +3766,14 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, } /* copy back packet headers if we performed NAT operations */ - if (rewrite) + if (rewrite) { m_copyback(m, off, hdrlen, pd->hdr.any); + if (sk->af == AF_INET6 && nk->af == AF_INET) + pf_nat64_ipv6(m, off, pd, nk); + else if (sk->af == AF_INET && nk->af == AF_INET6) + pf_nat64_ipv4(m, off, pd, nk); + } + if (*sm != NULL && !((*sm)->state_flags & PFSTATE_NOSYNC) && direction == PF_OUT && @@ -3519,7 +3786,11 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, */ return (PF_DEFER); - return (PF_PASS); + if (rewrite && sk->af != nk->af) + return (PF_DEFER); + else + return (PF_PASS); + cleanup: if (sk != NULL) @@ -3529,6 +3800,8 @@ cleanup: return (PF_DROP); } +#define SWAP(t,a,b) do { t tmp = a; a = b; b = tmp; } while (0) + static int 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, @@ -3683,7 +3956,7 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, if (nr == NULL) { KASSERT((sk == NULL && nk == NULL), ("%s: nr %p sk %p, nk %p", __func__, nr, sk, nk)); - sk = pf_state_key_setup(pd, pd->src, pd->dst, sport, dport); + sk = pf_state_key_setup(pd, pd->src, pd->dst, sport, dport, nr); if (sk == NULL) goto csfailed; nk = sk; @@ -3691,6 +3964,12 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, KASSERT((sk != NULL && nk != NULL), ("%s: nr %p sk %p, nk %p", __func__, nr, sk, nk)); + /* BABAK - should this be here? patch:1025 */ + if (sk->af != nk->af) { + SWAP(struct pf_addr, nk->addr[0], nk->addr[1]); + SWAP(u_int16_t, nk->port[0], nk->port[1]); + } + /* Swap sk/nk for PF_OUT. */ if (pf_state_insert(BOUND_IFACE(r, kif), (pd->dir == PF_IN) ? sk : nk, @@ -4093,6 +4372,7 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, /* Fall through to PASS packet */ + /* BABAK - how to merge this? patch:1037 */ } else if ((dst->state < TCPS_SYN_SENT || dst->state >= TCPS_FIN_WAIT_2 || src->state >= TCPS_FIN_WAIT_2) && @@ -4164,8 +4444,8 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, /* Fall through to PASS packet */ } else { - if ((*state)->dst.state == TCPS_SYN_SENT && - (*state)->src.state == TCPS_SYN_SENT) { + if (dst->state == TCPS_SYN_SENT && + src->state == TCPS_SYN_SENT) { /* Send RST for state mismatches during handshake */ if (!(th->th_flags & TH_RST)) pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, @@ -4303,7 +4583,9 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(kif, &key, direction, *state, pd); - if (direction == (*state)->direction) { + if (direction == (*state)->direction && + ((*state)->key[0]->af == (*state)->key[1]->af || + pd->af == (*state)->key[0]->af)) { src = &(*state)->src; dst = &(*state)->dst; } else { @@ -4311,27 +4593,29 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, dst = &(*state)->src; } - sk = (*state)->key[pd->didx]; + sk = (*state)->key[(*state)->key[0]->af == (*state)->key[1]->af || + pd->af == (*state)->key[0]->af ? pd->didx : pd->sidx]; - if ((*state)->src.state == PF_TCPS_PROXY_SRC) { + if (src->state == PF_TCPS_PROXY_SRC) { if (direction != (*state)->direction) { REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } if (th->th_flags & TH_SYN) { - if (ntohl(th->th_seq) != (*state)->src.seqlo) { + if (ntohl(th->th_seq) != src->seqlo) { REASON_SET(reason, PFRES_SYNPROXY); return (PF_DROP); } pf_send_tcp(NULL, (*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, 1, 0, NULL); + src->seqhi, ntohl(th->th_seq) + 1, + TH_SYN|TH_ACK, 0, src->mss, 0, 1, + 0, NULL); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (!(th->th_flags & TH_ACK) || - (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || - (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { + (ntohl(th->th_ack) != src->seqhi + 1) || + (ntohl(th->th_seq) != src->seqlo + 1)) { REASON_SET(reason, PFRES_SYNPROXY); return (PF_DROP); } else if ((*state)->src_node != NULL && @@ -4339,54 +4623,54 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, REASON_SET(reason, PFRES_SRCLIMIT); return (PF_DROP); } else - (*state)->src.state = PF_TCPS_PROXY_DST; + src->state = PF_TCPS_PROXY_DST; } - if ((*state)->src.state == PF_TCPS_PROXY_DST) { + if (src->state == PF_TCPS_PROXY_DST) { if (direction == (*state)->direction) { if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) || - (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || - (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { + (ntohl(th->th_ack) != src->seqhi + 1) || + (ntohl(th->th_seq) != src->seqlo + 1)) { REASON_SET(reason, PFRES_SYNPROXY); return (PF_DROP); } - (*state)->src.max_win = MAX(ntohs(th->th_win), 1); - if ((*state)->dst.seqhi == 1) - (*state)->dst.seqhi = htonl(arc4random()); + src->max_win = MAX(ntohs(th->th_win), 1); + if (dst->seqhi == 1) + dst->seqhi = htonl(arc4random()); pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, &sk->addr[pd->sidx], &sk->addr[pd->didx], sk->port[pd->sidx], sk->port[pd->didx], - (*state)->dst.seqhi, 0, TH_SYN, 0, - (*state)->src.mss, 0, 0, (*state)->tag, NULL); + dst->seqhi, 0, TH_SYN, 0, + src->mss, 0, 0, (*state)->tag, NULL); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != (TH_SYN|TH_ACK)) || - (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) { + (ntohl(th->th_ack) != dst->seqhi + 1)) { REASON_SET(reason, PFRES_SYNPROXY); return (PF_DROP); } else { - (*state)->dst.max_win = MAX(ntohs(th->th_win), 1); - (*state)->dst.seqlo = ntohl(th->th_seq); + dst->max_win = MAX(ntohs(th->th_win), 1); + dst->seqlo = ntohl(th->th_seq); pf_send_tcp(NULL, (*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, 0, + TH_ACK, src->max_win, 0, 0, 0, (*state)->tag, NULL); pf_send_tcp(NULL, (*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, 1, 0, NULL); - (*state)->src.seqdiff = (*state)->dst.seqhi - + src->seqhi + 1, src->seqlo + 1, + TH_ACK, dst->max_win, 0, 0, 1, 0, NULL); + src->seqdiff = dst->seqhi - (*state)->src.seqlo; - (*state)->dst.seqdiff = (*state)->src.seqhi - + dst->seqdiff = src->seqhi - (*state)->dst.seqlo; - (*state)->src.seqhi = (*state)->src.seqlo + + src->seqhi = src->seqlo + (*state)->dst.max_win; - (*state)->dst.seqhi = (*state)->dst.seqlo + + dst->seqhi = dst->seqlo + (*state)->src.max_win; - (*state)->src.wscale = (*state)->dst.wscale = 0; - (*state)->src.state = (*state)->dst.state = + src->wscale = dst->wscale = 0; + src->state = dst->state = TCPS_ESTABLISHED; REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); @@ -4403,37 +4687,61 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, printf("\n"); } /* XXX make sure it's the same direction ?? */ - (*state)->src.state = (*state)->dst.state = TCPS_CLOSED; + src->state = dst->state = TCPS_CLOSED; pf_unlink_state(*state, PF_ENTER_LOCKED); *state = NULL; return (PF_DROP); } - if ((*state)->state_flags & PFSTATE_SLOPPY) { + /*if ((*state)->state_flags & PFSTATE_SLOPPY) {*/ if (pf_tcp_track_sloppy(src, dst, state, pd, reason) == PF_DROP) return (PF_DROP); +#if 0 } else { if (pf_tcp_track_full(src, dst, state, kif, m, off, pd, reason, ©back) == PF_DROP) return (PF_DROP); } +#endif /* translate source/destination address, if necessary */ if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { - struct pf_state_key *nk = (*state)->key[pd->didx]; - - if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || - nk->port[pd->sidx] != th->th_sport) - 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); + struct pf_state_key *nk = + (*state)->key[(*state)->key[PF_SK_WIRE]->af != + (*state)->key[PF_SK_STACK]->af && + (*state)->key[PF_SK_WIRE]->af != pd->af ? pd->sidx : + pd->didx]; + struct pf_addr *nsaddr = + &nk->addr[pd->af == nk->af ? pd->sidx : pd->didx]; + struct pf_addr *ndaddr = + &nk->addr[pd->af == nk->af ? pd->didx : pd->sidx]; + u_int16_t nsport = + nk->port[pd->af == nk->af ? pd->sidx : pd->didx]; + u_int16_t ndport = + nk->port[pd->af == nk->af ? pd->didx : pd->sidx]; + struct pf_addr src = *pd->src; + struct pf_addr dst = *pd->dst; + + if (pd->af != nk->af || + PF_ANEQ(pd->src, nsaddr, pd->af) || nsport != th->th_sport) + pf_change_ap(m, pd->src, &th->th_sport, pd->ip_sum, + &th->th_sum, nsaddr, nsport, 0, pd->af, nk->af); + + if (pd->af != nk->af || + PF_ANEQ(pd->dst, ndaddr, pd->af) || ndport != th->th_dport) + pf_change_ap(m, pd->dst, &th->th_dport, pd->ip_sum, + &th->th_sum, ndaddr, ndport, 0, pd->af, nk->af); + m_copyback(m, off, sizeof(*th), (caddr_t)th); - if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || - nk->port[pd->didx] != th->th_dport) - 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); - copyback = 1; + if (pd->af != nk->af) { + if (pd->af == AF_INET) + return pf_nat64_ipv4(m, off, pd, nk); + else if (pd->af == AF_INET6) + return pf_nat64_ipv6(m, off, pd, nk); + } else { + *pd->src = src; + *pd->dst = dst; + } } /* Copyback sequence modulation or stateful scrub changes if needed */ @@ -4468,7 +4776,9 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(kif, &key, direction, *state, pd); - if (direction == (*state)->direction) { + if (direction == (*state)->direction && + ((*state)->key[0]->af == (*state)->key[1]->af || + pd->af == (*state)->key[0]->af)) { src = &(*state)->src; dst = &(*state)->dst; } else { @@ -4491,20 +4801,44 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, /* translate source/destination address, if necessary */ if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { - struct pf_state_key *nk = (*state)->key[pd->didx]; - - if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || - nk->port[pd->sidx] != uh->uh_sport) + struct pf_state_key *nk = + (*state)->key[(*state)->key[PF_SK_WIRE]->af != + (*state)->key[PF_SK_STACK]->af && + (*state)->key[PF_SK_WIRE]->af != pd->af ? pd->sidx : + pd->didx]; + struct pf_addr *nsaddr = + &nk->addr[pd->af == nk->af ? pd->sidx : pd->didx]; + struct pf_addr *ndaddr = + &nk->addr[pd->af == nk->af ? pd->didx : pd->sidx]; + u_int16_t nsport = + nk->port[pd->af == nk->af ? pd->sidx : pd->didx]; + u_int16_t ndport = + nk->port[pd->af == nk->af ? pd->didx : pd->sidx]; + struct pf_addr src = *pd->src; + struct pf_addr dst = *pd->dst; + + if (pd->af != nk->af || + PF_ANEQ(pd->src, nsaddr, pd->af) || nsport != uh->uh_sport) 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); + &uh->uh_sum, nsaddr, nsport, 1, pd->af, nk->af); - if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || - nk->port[pd->didx] != uh->uh_dport) + if (pd->af != nk->af || + PF_ANEQ(pd->dst, ndaddr, pd->af) || ndport != uh->uh_dport) 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); + &uh->uh_sum, ndaddr, ndport, 1, pd->af, nk->af); + + m_copyback(m, off, sizeof(*uh), (caddr_t)uh); + + if (pd->af != nk->af) { + if (pd->af == AF_INET) + return pf_nat64_ipv4(m, off, pd, nk); + else if (pd->af == AF_INET6) + return pf_nat64_ipv6(m, off, pd, nk); + } else { + *pd->src = src; + *pd->dst = dst; + } } return (PF_PASS); @@ -5922,6 +6256,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) pd.af = AF_INET; pd.tos = h->ip_tos; pd.tot_len = ntohs(h->ip_len); + pd.ttl = h->ip_ttl; /* handle fragments that didn't get reassembled by normalization */ if (h->ip_off & htons(IP_MF | IP_OFFMASK)) { @@ -5978,7 +6313,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) goto done; } action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); - if (action == PF_PASS) { + if (action == PF_PASS || action == PF_DEFER) { if (pfsync_update_state_ptr != NULL) pfsync_update_state_ptr(s); r = s->rule.ptr; @@ -6313,6 +6648,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) pd.af = AF_INET6; pd.tos = 0; pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); + pd.ttl = h->ip6_hlim; off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); pd.proto = h->ip6_nxt; diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h index ac0e0fb..362bcab 100644 --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -45,7 +45,8 @@ enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD }; enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT, - PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER }; + PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_NAT64, PF_NONAT64, + PF_SYNPROXY_DROP, PF_DEFER }; enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT, PF_RULESET_BINAT, PF_RULESET_RDR, PF_RULESET_MAX }; enum { PF_OP_NONE, PF_OP_IRG, PF_OP_EQ, PF_OP_NE, PF_OP_LT, diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index cf7f6f2..a887ef0 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -1265,9 +1265,9 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td } pf_mv_pool(&V_pf_pabuf, &rule->rpool.list); - if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || - (rule->action == PF_BINAT)) && rule->anchor == NULL) || - (rule->rt > PF_FASTROUTE)) && + if (((((rule->action == PF_NAT) || (rule->action == PF_NAT64) + || (rule->action == PF_RDR) || (rule->action == PF_BINAT)) + && rule->anchor == NULL) || (rule->rt > PF_FASTROUTE)) && (TAILQ_FIRST(&rule->rpool.list) == NULL)) error = EINVAL; @@ -1525,6 +1525,7 @@ DIOCADDRULE_error: pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list); if (((((newrule->action == PF_NAT) || + (newrule->action == PF_NAT64) || (newrule->action == PF_RDR) || (newrule->action == PF_BINAT) || (newrule->rt > PF_FASTROUTE)) && @@ -1857,6 +1858,7 @@ DIOCGETSTATES_full: break; } + /* BABAK - this should be updated for NAT64 perhaps */ case DIOCNATLOOK: { struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; struct pf_state_key *sk; @@ -3285,7 +3287,8 @@ pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; sp->proto = st->key[PF_SK_WIRE]->proto; - sp->af = st->key[PF_SK_WIRE]->af; + /* BABAK - commented the line below to figure out what is the right thing to do */ + //sp->af = st->key[PF_SK_WIRE]->af; /* copy from state */ strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index 6cb5840..99cd9d8 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -205,7 +205,8 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, M_SETFIB(m, rtableid); if (rm != NULL && (rm->action == PF_NONAT || - rm->action == PF_NORDR || rm->action == PF_NOBINAT)) + rm->action == PF_NORDR || rm->action == PF_NOBINAT || + rm->action == PF_NONAT64)) return (NULL); return (rm); } @@ -320,13 +321,13 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, route address, use this address. A zeroed address is found if the src node was created just a moment ago in pf_create_state and it needs to be filled in with routing decision calculated here. */ - if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) { - PF_ACPY(naddr, &(*sn)->raddr, af); + if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, rpool->af)) { + PF_ACPY(naddr, &(*sn)->raddr, rpool->af); if (V_pf_status.debug >= PF_DEBUG_MISC) { printf("pf_map_addr: src tracking maps "); pf_print_host(saddr, 0, af); printf(" to "); - pf_print_host(naddr, 0, af); + pf_print_host(naddr, 0, rpool->af); printf("\n"); } return (0); @@ -337,7 +338,7 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, if (rpool->cur->addr.type == PF_ADDR_NOROUTE) return (1); if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - switch (af) { + switch (rpool->af) { #ifdef INET case AF_INET: if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 && @@ -369,14 +370,15 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, switch (rpool->opts & PF_POOL_TYPEMASK) { case PF_POOL_NONE: - PF_ACPY(naddr, raddr, af); + PF_ACPY(naddr, raddr, rpool->af); break; case PF_POOL_BITMASK: + KASSERT(af == rpool->af, ("af != rpool-af")); PF_POOLMASK(naddr, raddr, rmask, saddr, af); break; case PF_POOL_RANDOM: - if (init_addr != NULL && PF_AZERO(init_addr, af)) { - switch (af) { + if (init_addr != NULL && PF_AZERO(init_addr, rpool->af)) { + switch (rpool->af) { #ifdef INET case AF_INET: rpool->counter.addr32[0] = htonl(arc4random()); @@ -405,18 +407,18 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, break; #endif /* INET6 */ } - PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af); - PF_ACPY(init_addr, naddr, af); + PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, rpool->af); + PF_ACPY(init_addr, naddr, rpool->af); } else { - PF_AINC(&rpool->counter, af); - PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af); + PF_AINC(&rpool->counter, rpool->af); + PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, rpool->af); } break; case PF_POOL_SRCHASH: { unsigned char hash[16]; - + KASSERT(af == rpool->af, ("af != rpool->af")); pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af); PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af); break; @@ -448,13 +450,13 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, if (rpool->cur->addr.type == PF_ADDR_TABLE) { if (!pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af)) + &rpool->tblidx, &rpool->counter, rpool->af)) goto get_addr; } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af)) + &rpool->tblidx, &rpool->counter, rpool->af)) goto get_addr; - } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af)) + } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, rpool->af)) goto get_addr; try_next: @@ -465,8 +467,8 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, if (rpool->cur->addr.type == PF_ADDR_TABLE) { rpool->tblidx = -1; if (pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af)) { - /* table contains no address of type 'af' */ + &rpool->tblidx, &rpool->counter, rpool->af)) { + /* table contains no address of type 'rpool->af' */ if (rpool->cur != acur) goto try_next; return (1); @@ -474,8 +476,8 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { rpool->tblidx = -1; if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af)) { - /* table contains no address of type 'af' */ + &rpool->tblidx, &rpool->counter, rpool->af)) { + /* table contains no address of type 'rpool->af' */ if (rpool->cur != acur) goto try_next; return (1); @@ -483,24 +485,24 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, } else { raddr = &rpool->cur->addr.v.a.addr; rmask = &rpool->cur->addr.v.a.mask; - PF_ACPY(&rpool->counter, raddr, af); + PF_ACPY(&rpool->counter, raddr, rpool->af); } get_addr: - PF_ACPY(naddr, &rpool->counter, af); - if (init_addr != NULL && PF_AZERO(init_addr, af)) - PF_ACPY(init_addr, naddr, af); - PF_AINC(&rpool->counter, af); + PF_ACPY(naddr, &rpool->counter, rpool->af); + if (init_addr != NULL && PF_AZERO(init_addr, rpool->af)) + PF_ACPY(init_addr, naddr, rpool->af); + PF_AINC(&rpool->counter, rpool->af); break; } } if (*sn != NULL) - PF_ACPY(&(*sn)->raddr, naddr, af); + PF_ACPY(&(*sn)->raddr, naddr, rpool->af); if (V_pf_status.debug >= PF_DEBUG_MISC && (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { printf("pf_map_addr: selected address "); - pf_print_host(naddr, 0, af); + pf_print_host(naddr, 0, rpool->af); printf("\n"); } @@ -515,9 +517,11 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, uint16_t sport, uint16_t dport, struct pf_anchor_stackframe *anchor_stack) { struct pf_rule *r = NULL; - struct pf_addr *naddr; - uint16_t *nport; - + struct pf_addr *nsaddr; + u_int16_t *nsport; + struct pf_addr *ndaddr; + u_int16_t *ndport; + PF_RULES_RASSERT(); KASSERT(*skp == NULL, ("*skp not NULL")); KASSERT(*nkp == NULL, ("*nkp not NULL")); @@ -543,12 +547,13 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, switch (r->action) { case PF_NONAT: + case PF_NONAT64: case PF_NOBINAT: case PF_NORDR: return (NULL); } - *skp = pf_state_key_setup(pd, saddr, daddr, sport, dport); + *skp = pf_state_key_setup(pd, saddr, daddr, sport, dport, r); if (*skp == NULL) return (NULL); *nkp = pf_state_key_clone(*skp); @@ -558,20 +563,26 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, return (NULL); } - /* XXX We only modify one side for now. */ - naddr = &(*nkp)->addr[1]; - nport = &(*nkp)->port[1]; + nsaddr = &(*nkp)->addr[pd->sidx]; + nsport = &(*nkp)->port[pd->sidx]; + ndaddr = &(*nkp)->addr[pd->didx]; + ndport = &(*nkp)->port[pd->didx]; switch (r->action) { case PF_NAT: + case PF_NAT64: if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, daddr, - dport, naddr, nport, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], sn)) { + dport, nsaddr, nsport, + r->rpool.proxy_port[0], + r->rpool.proxy_port[1], sn)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: NAT proxy port allocation (%u-%u) failed\n", r->rpool.proxy_port[0], r->rpool.proxy_port[1])); goto notrans; } + if (r->action == PF_NAT64) + ndaddr->v4.s_addr = + (*skp)->addr[pd->didx].addr32[3]; break; case PF_BINAT: switch (direction) { @@ -583,7 +594,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, if (r->rpool.cur->addr.p.dyn-> pfid_acnt4 < 1) goto notrans; - PF_POOLMASK(naddr, + PF_POOLMASK(nsaddr, &r->rpool.cur->addr.p.dyn-> pfid_addr4, &r->rpool.cur->addr.p.dyn-> @@ -595,7 +606,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, if (r->rpool.cur->addr.p.dyn-> pfid_acnt6 < 1) goto notrans; - PF_POOLMASK(naddr, + PF_POOLMASK(nsaddr, &r->rpool.cur->addr.p.dyn-> pfid_addr6, &r->rpool.cur->addr.p.dyn-> @@ -604,7 +615,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, #endif /* INET6 */ } } else - PF_POOLMASK(naddr, + PF_POOLMASK(nsaddr, &r->rpool.cur->addr.v.a.addr, &r->rpool.cur->addr.v.a.mask, saddr, pd->af); @@ -616,7 +627,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, case AF_INET: if (r->src.addr.p.dyn-> pfid_acnt4 < 1) goto notrans; - PF_POOLMASK(naddr, + PF_POOLMASK(ndaddr, &r->src.addr.p.dyn->pfid_addr4, &r->src.addr.p.dyn->pfid_mask4, daddr, AF_INET); @@ -626,7 +637,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, case AF_INET6: if (r->src.addr.p.dyn->pfid_acnt6 < 1) goto notrans; - PF_POOLMASK(naddr, + PF_POOLMASK(ndaddr, &r->src.addr.p.dyn->pfid_addr6, &r->src.addr.p.dyn->pfid_mask6, daddr, AF_INET6); @@ -634,31 +645,31 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, #endif /* INET6 */ } } else - PF_POOLMASK(naddr, &r->src.addr.v.a.addr, + PF_POOLMASK(ndaddr, &r->src.addr.v.a.addr, &r->src.addr.v.a.mask, daddr, pd->af); break; } break; case PF_RDR: { - if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn)) + if (pf_map_addr(pd->af, r, saddr, ndaddr, NULL, sn)) goto notrans; if ((r->rpool.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK) - PF_POOLMASK(naddr, naddr, &r->rpool.cur->addr.v.a.mask, + PF_POOLMASK(ndaddr, ndaddr, &r->rpool.cur->addr.v.a.mask, daddr, pd->af); if (r->rpool.proxy_port[1]) { - uint32_t tmp_nport; + uint32_t tmp_ndport; - tmp_nport = ((ntohs(dport) - ntohs(r->dst.port[0])) % + tmp_ndport = ((ntohs(dport) - ntohs(r->dst.port[0])) % (r->rpool.proxy_port[1] - r->rpool.proxy_port[0] + 1)) + r->rpool.proxy_port[0]; /* Wrap around if necessary. */ - if (tmp_nport > 65535) - tmp_nport -= 65535; - *nport = htons((uint16_t)tmp_nport); + if (tmp_ndport > 65535) + tmp_ndport -= 65535; + *ndport = htons((uint16_t)tmp_ndport); } else if (r->rpool.proxy_port[0]) - *nport = htons(r->rpool.proxy_port[0]); + *ndport = htons(r->rpool.proxy_port[0]); break; } default: diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c index 61da586..24c85d2 100644 --- a/sys/netpfil/pf/pf_ruleset.c +++ b/sys/netpfil/pf/pf_ruleset.c @@ -124,6 +124,8 @@ pf_get_ruleset_number(u_int8_t action) case PF_DROP: return (PF_RULESET_FILTER); break; + case PF_NAT64: /* BABAK - are you sure these belong to here? patch:1701 */ + case PF_NONAT64: case PF_NAT: case PF_NONAT: return (PF_RULESET_NAT);