mirror of
https://github.com/opnsense/src.git
synced 2026-06-05 23:04:36 -04:00
pf: nat64
Since the IPv6 madness is not enough introduce NAT64 -- which is actually
"af-to" a generic IP version translator for pf(4).
Not everything perfect yet but lets fix these things in the tree.
Insane amount of work done by sperreault@, mikeb@ and reyk@.
Looked over by mcbride@ henning@ and myself at eurobsdcon.
OK mcbride@ and general put it in from deraadt@
Obtained from: OpenBSD, claudio <claudio@openbsd.org>, 97326e01c9
Sponsored by: Rubicon Communications, LLC ("Netgate")
Differential Revision: https://reviews.freebsd.org/D47786
This commit is contained in:
parent
e4e0f49742
commit
fcdb520c1b
11 changed files with 1522 additions and 180 deletions
|
|
@ -4559,6 +4559,7 @@ netpfil/pf/pf_table.c optional pf inet
|
|||
netpfil/pf/pflow.c optional pflow pf inet
|
||||
netpfil/pf/pfsync_nv.c optional pfsync pf inet
|
||||
netpfil/pf/in4_cksum.c optional pf inet
|
||||
netpfil/pf/inet_nat64.c optional pf inet
|
||||
netsmb/smb_conn.c optional netsmb
|
||||
netsmb/smb_crypt.c optional netsmb
|
||||
netsmb/smb_dev.c optional netsmb
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
KMOD= pf
|
||||
SRCS= pf.c pf_if.c pf_lb.c pf_osfp.c pf_ioctl.c pf_norm.c pf_table.c \
|
||||
pf_ruleset.c pf_nl.c pf_nv.c pf_syncookies.c in4_cksum.c \
|
||||
pf_ruleset.c pf_nl.c pf_nv.c pf_syncookies.c in4_cksum.c inet_nat64.c \
|
||||
bus_if.h device_if.h \
|
||||
opt_pf.h opt_inet.h opt_inet6.h opt_bpf.h opt_sctp.h opt_global.h \
|
||||
opt_kern_tls.h
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ struct pfloghdr {
|
|||
uid_t rule_uid;
|
||||
pid_t rule_pid;
|
||||
u_int8_t dir;
|
||||
u_int8_t pad[3];
|
||||
u_int8_t pad1; /* rewritten, on OpenBSD */
|
||||
sa_family_t naf;
|
||||
u_int8_t pad[1];
|
||||
u_int32_t ridentifier;
|
||||
u_int8_t reserve; /* Appease broken software like Wireshark. */
|
||||
u_int8_t pad2[3];
|
||||
|
|
|
|||
|
|
@ -864,6 +864,7 @@ struct pf_krule {
|
|||
u_int8_t flush;
|
||||
u_int8_t prio;
|
||||
u_int8_t set_prio[2];
|
||||
sa_family_t naf;
|
||||
|
||||
struct {
|
||||
struct pf_addr addr;
|
||||
|
|
@ -986,6 +987,10 @@ struct pf_state_key {
|
|||
TAILQ_HEAD(, pf_kstate) states[2];
|
||||
};
|
||||
|
||||
#define PF_REVERSED_KEY(key, family) \
|
||||
((key[PF_SK_WIRE]->af != key[PF_SK_STACK]->af) && \
|
||||
(key[PF_SK_WIRE]->af != (family)))
|
||||
|
||||
/* Keep synced with struct pf_kstate. */
|
||||
struct pf_state_cmp {
|
||||
u_int64_t id;
|
||||
|
|
@ -1630,6 +1635,7 @@ struct pf_pdesc {
|
|||
#define PF_VPROTO_FRAGMENT 256
|
||||
int extoff;
|
||||
sa_family_t af;
|
||||
sa_family_t naf;
|
||||
u_int8_t proto;
|
||||
u_int8_t tos;
|
||||
u_int8_t ttl;
|
||||
|
|
@ -2429,6 +2435,9 @@ int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kkif *,
|
|||
int);
|
||||
int pf_socket_lookup(struct pf_pdesc *);
|
||||
struct pf_state_key *pf_alloc_state_key(int);
|
||||
int pf_translate(struct pf_pdesc *, struct pf_addr *, u_int16_t,
|
||||
struct pf_addr *, u_int16_t, u_int16_t, int);
|
||||
int pf_translate_af(struct pf_pdesc *);
|
||||
void pfr_initialize(void);
|
||||
void pfr_cleanup(void);
|
||||
int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);
|
||||
|
|
@ -2642,18 +2651,23 @@ int pf_step_out_of_keth_anchor(struct pf_keth_anchor_stackframe *,
|
|||
|
||||
u_short pf_map_addr(u_int8_t, struct pf_krule *,
|
||||
struct pf_addr *, struct pf_addr *,
|
||||
struct pfi_kkif **nkif, struct pf_addr *);
|
||||
struct pfi_kkif **nkif, struct pf_addr *,
|
||||
struct pf_kpool *);
|
||||
u_short pf_map_addr_sn(u_int8_t, struct pf_krule *,
|
||||
struct pf_addr *, struct pf_addr *,
|
||||
struct pfi_kkif **nkif, struct pf_addr *,
|
||||
struct pf_ksrc_node **, struct pf_srchash **);
|
||||
struct pf_ksrc_node **, struct pf_srchash **,
|
||||
struct pf_kpool *);
|
||||
int pf_get_transaddr_af(struct pf_krule *,
|
||||
struct pf_pdesc *);
|
||||
u_short pf_get_translation(struct pf_pdesc *,
|
||||
int, struct pf_state_key **, struct pf_state_key **,
|
||||
struct pf_kanchor_stackframe *, struct pf_krule **,
|
||||
struct pf_udp_mapping **udp_mapping);
|
||||
|
||||
struct pf_state_key *pf_state_key_setup(struct pf_pdesc *,
|
||||
u_int16_t, u_int16_t);
|
||||
int pf_state_key_setup(struct pf_pdesc *,
|
||||
u_int16_t, u_int16_t,
|
||||
struct pf_state_key **sk, struct pf_state_key **nk);
|
||||
struct pf_state_key *pf_state_key_clone(const struct pf_state_key *);
|
||||
void pf_rule_to_actions(struct pf_krule *,
|
||||
struct pf_rule_actions *);
|
||||
|
|
@ -2665,6 +2679,17 @@ void pf_scrub(struct pf_pdesc *);
|
|||
struct pfi_kkif *pf_kkif_create(int);
|
||||
void pf_kkif_free(struct pfi_kkif *);
|
||||
void pf_kkif_zero(struct pfi_kkif *);
|
||||
|
||||
|
||||
/* NAT64 functions. */
|
||||
int inet_nat64(int, const void *, void *, const void *, u_int8_t);
|
||||
int inet_nat64_inet(const void *, void *, const void *, u_int8_t);
|
||||
int inet_nat64_inet6(const void *, void *, const void *, u_int8_t);
|
||||
|
||||
int inet_nat46(int, const void *, void *, const void *, u_int8_t);
|
||||
int inet_nat46_inet(const void *, void *, const void *, u_int8_t);
|
||||
int inet_nat46_inet6(const void *, void *, const void *, u_int8_t);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _NET_PFVAR_H_ */
|
||||
|
|
|
|||
204
sys/netpfil/pf/inet_nat64.c
Normal file
204
sys/netpfil/pf/inet_nat64.c
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/* $OpenBSD: inet_nat64.c,v 1.1 2011/10/13 18:23:40 claudio Exp $ */
|
||||
/* $vantronix: inet_nat64.c,v 1.2 2011/02/28 14:57:58 mike Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Reyk Floeter <reyk@vantronix.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
union inet_nat64_addr {
|
||||
u_int32_t u32[4];
|
||||
u_int8_t u8[16];
|
||||
};
|
||||
|
||||
static u_int32_t
|
||||
inet_nat64_mask(u_int32_t src, u_int32_t pfx, u_int8_t pfxlen)
|
||||
{
|
||||
u_int32_t u32;
|
||||
if (pfxlen == 0)
|
||||
return (src);
|
||||
else if (pfxlen > 32)
|
||||
pfxlen = 32;
|
||||
u32 =
|
||||
(src & ~htonl(0xffffffff << (32 - pfxlen))) |
|
||||
(pfx & htonl(0xffffffff << (32 - pfxlen)));
|
||||
return (u32);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
inet_nat64(int af, const void *src, void *dst,
|
||||
const void *pfx, u_int8_t pfxlen)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_nat64_inet(src, dst, pfx, pfxlen));
|
||||
case AF_INET6:
|
||||
return (inet_nat64_inet6(src, dst, pfx, pfxlen));
|
||||
default:
|
||||
#ifndef _KERNEL
|
||||
errno = EAFNOSUPPORT;
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
inet_nat64_inet(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
|
||||
{
|
||||
const union inet_nat64_addr *s = src;
|
||||
const union inet_nat64_addr *p = pfx;
|
||||
union inet_nat64_addr *d = dst;
|
||||
int i, j;
|
||||
|
||||
switch (pfxlen) {
|
||||
case 32:
|
||||
case 40:
|
||||
case 48:
|
||||
case 56:
|
||||
case 64:
|
||||
case 96:
|
||||
i = pfxlen / 8;
|
||||
break;
|
||||
default:
|
||||
if (pfxlen < 96 || pfxlen > 128) {
|
||||
#ifndef _KERNEL
|
||||
errno = EINVAL;
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* as an extension, mask out any other bits */
|
||||
d->u32[0] = inet_nat64_mask(s->u32[3], p->u32[3],
|
||||
(u_int8_t)(32 - (128 - pfxlen)));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* fill the octets with the source and skip reserved octet 8 */
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (i == 8)
|
||||
i++;
|
||||
d->u8[j] = s->u8[i++];
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
inet_nat64_inet6(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
|
||||
{
|
||||
const union inet_nat64_addr *s = src;
|
||||
const union inet_nat64_addr *p = pfx;
|
||||
union inet_nat64_addr *d = dst;
|
||||
int i, j;
|
||||
|
||||
/* first copy the prefix octets to the destination */
|
||||
*d = *p;
|
||||
|
||||
switch (pfxlen) {
|
||||
case 32:
|
||||
case 40:
|
||||
case 48:
|
||||
case 56:
|
||||
case 64:
|
||||
case 96:
|
||||
i = pfxlen / 8;
|
||||
break;
|
||||
default:
|
||||
if (pfxlen < 96 || pfxlen > 128) {
|
||||
#ifndef _KERNEL
|
||||
errno = EINVAL;
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* as an extension, mask out any other bits */
|
||||
d->u32[3] = inet_nat64_mask(s->u32[0], p->u32[3],
|
||||
(u_int8_t)(32 - (128 - pfxlen)));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* octet 8 is reserved and must be set to zero */
|
||||
d->u8[8] = 0;
|
||||
|
||||
/* fill the other octets with the source and skip octet 8 */
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (i == 8)
|
||||
i++;
|
||||
d->u8[i++] = s->u8[j];
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
inet_nat46(int af, const void *src, void *dst,
|
||||
const void *pfx, u_int8_t pfxlen)
|
||||
{
|
||||
if (pfxlen > 32) {
|
||||
#ifndef _KERNEL
|
||||
errno = EINVAL;
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_nat46_inet(src, dst, pfx, pfxlen));
|
||||
case AF_INET6:
|
||||
return (inet_nat46_inet6(src, dst, pfx, pfxlen));
|
||||
default:
|
||||
#ifndef _KERNEL
|
||||
errno = EAFNOSUPPORT;
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
inet_nat46_inet(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
|
||||
{
|
||||
const union inet_nat64_addr *s = src;
|
||||
const union inet_nat64_addr *p = pfx;
|
||||
union inet_nat64_addr *d = dst;
|
||||
|
||||
/* set the remaining bits to the source */
|
||||
d->u32[0] = inet_nat64_mask(s->u32[3], p->u32[0], pfxlen);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
inet_nat46_inet6(const void *src, void *dst, const void *pfx, u_int8_t pfxlen)
|
||||
{
|
||||
const union inet_nat64_addr *s = src;
|
||||
const union inet_nat64_addr *p = pfx;
|
||||
union inet_nat64_addr *d = dst;
|
||||
|
||||
/* set the initial octets to zero */
|
||||
d->u32[0] = d->u32[1] = d->u32[2] = 0;
|
||||
|
||||
/* now set the remaining bits to the source */
|
||||
d->u32[3] = inet_nat64_mask(s->u32[0], p->u32[0], pfxlen);
|
||||
|
||||
return (0);
|
||||
}
|
||||
1209
sys/netpfil/pf/pf.c
1209
sys/netpfil/pf/pf.c
File diff suppressed because it is too large
Load diff
|
|
@ -49,7 +49,7 @@
|
|||
enum { PF_INOUT, PF_IN, PF_OUT };
|
||||
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_MATCH };
|
||||
PF_MATCH, PF_AFRT };
|
||||
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,
|
||||
|
|
@ -126,7 +126,7 @@ enum { PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM,
|
|||
PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN };
|
||||
enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
|
||||
PF_ADDR_TABLE, PF_ADDR_URPFFAILED,
|
||||
PF_ADDR_RANGE };
|
||||
PF_ADDR_RANGE, PF_ADDR_NONE };
|
||||
#define PF_POOL_TYPEMASK 0x0f
|
||||
#define PF_POOL_STICKYADDR 0x20
|
||||
#define PF_POOL_ENDPI 0x40
|
||||
|
|
@ -673,6 +673,7 @@ struct pf_src_node {
|
|||
u_int32_t creation;
|
||||
u_int32_t expire;
|
||||
sa_family_t af;
|
||||
sa_family_t naf;
|
||||
u_int8_t ruletype;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -611,6 +611,7 @@ pf_free_rule(struct pf_krule *rule)
|
|||
pfi_kkif_unref(rule->rcv_kif);
|
||||
pf_kanchor_remove(rule);
|
||||
pf_empty_kpool(&rule->rdr.list);
|
||||
pf_empty_kpool(&rule->nat.list);
|
||||
|
||||
pf_krule_free(rule);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,10 +48,20 @@
|
|||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/vnet.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <net/if_pflog.h>
|
||||
|
||||
#ifdef INET
|
||||
#include <netinet/in_var.h>
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet6/in6_var.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Limit the amount of work we do to find a free source port for redirects that
|
||||
* introduce a state conflict.
|
||||
|
|
@ -67,7 +77,7 @@ static struct pf_krule *pf_match_translation(struct pf_pdesc *,
|
|||
int, struct pf_kanchor_stackframe *);
|
||||
static int pf_get_sport(struct pf_pdesc *, struct pf_krule *,
|
||||
struct pf_addr *, uint16_t *, uint16_t, uint16_t, struct pf_ksrc_node **,
|
||||
struct pf_srchash **, struct pf_udp_mapping **);
|
||||
struct pf_srchash **, struct pf_kpool *, struct pf_udp_mapping **);
|
||||
static bool pf_islinklocal(const sa_family_t, const struct pf_addr *);
|
||||
|
||||
#define mix(a,b,c) \
|
||||
|
|
@ -220,14 +230,22 @@ static int
|
|||
pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
||||
struct pf_addr *naddr, uint16_t *nport, uint16_t low,
|
||||
uint16_t high, struct pf_ksrc_node **sn,
|
||||
struct pf_srchash **sh, struct pf_udp_mapping **udp_mapping)
|
||||
struct pf_srchash **sh, struct pf_kpool *rpool,
|
||||
struct pf_udp_mapping **udp_mapping)
|
||||
{
|
||||
struct pf_state_key_cmp key;
|
||||
struct pf_addr init_addr;
|
||||
|
||||
bzero(&init_addr, sizeof(init_addr));
|
||||
|
||||
MPASS(*udp_mapping == NULL);
|
||||
if (! TAILQ_EMPTY(&r->nat.list) &&
|
||||
pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, NULL, &init_addr,
|
||||
sn, sh, &r->nat))
|
||||
return (1);
|
||||
|
||||
if (udp_mapping) {
|
||||
MPASS(*udp_mapping == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are UDP and have an existing mapping we can get source port
|
||||
|
|
@ -241,26 +259,29 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
udp_source.af = pd->af;
|
||||
PF_ACPY(&udp_source.addr, &pd->nsaddr, pd->af);
|
||||
udp_source.port = pd->nsport;
|
||||
*udp_mapping = pf_udp_mapping_find(&udp_source);
|
||||
if (*udp_mapping) {
|
||||
PF_ACPY(naddr, &(*udp_mapping)->endpoints[1].addr, pd->af);
|
||||
*nport = (*udp_mapping)->endpoints[1].port;
|
||||
/* Try to find a src_node as per pf_map_addr(). */
|
||||
if (*sn == NULL && r->rdr.opts & PF_POOL_STICKYADDR &&
|
||||
(r->rdr.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE)
|
||||
*sn = pf_find_src_node(&pd->nsaddr, r, pd->af, sh, false);
|
||||
if (*sn != NULL)
|
||||
PF_SRC_NODE_UNLOCK(*sn);
|
||||
return (0);
|
||||
} else {
|
||||
*udp_mapping = pf_udp_mapping_create(pd->af, &pd->nsaddr,
|
||||
pd->nsport, &init_addr, 0);
|
||||
if (*udp_mapping == NULL)
|
||||
return (1);
|
||||
if (udp_mapping) {
|
||||
*udp_mapping = pf_udp_mapping_find(&udp_source);
|
||||
if (*udp_mapping) {
|
||||
PF_ACPY(naddr, &(*udp_mapping)->endpoints[1].addr, pd->af);
|
||||
*nport = (*udp_mapping)->endpoints[1].port;
|
||||
/* Try to find a src_node as per pf_map_addr(). */
|
||||
if (*sn == NULL && r->rdr.opts & PF_POOL_STICKYADDR &&
|
||||
(r->rdr.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE)
|
||||
*sn = pf_find_src_node(&pd->nsaddr, r, pd->af, sh, false);
|
||||
if (*sn != NULL)
|
||||
PF_SRC_NODE_UNLOCK(*sn);
|
||||
return (0);
|
||||
} else {
|
||||
*udp_mapping = pf_udp_mapping_create(pd->af, &pd->nsaddr,
|
||||
pd->nsport, &init_addr, 0);
|
||||
if (*udp_mapping == NULL)
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL, &init_addr, sn, sh))
|
||||
if (pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL, &init_addr,
|
||||
sn, sh, rpool))
|
||||
goto failed;
|
||||
|
||||
if (pd->proto == IPPROTO_ICMP) {
|
||||
|
|
@ -281,14 +302,14 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
#endif /* INET6 */
|
||||
|
||||
bzero(&key, sizeof(key));
|
||||
key.af = pd->af;
|
||||
key.af = pd->naf;
|
||||
key.proto = pd->proto;
|
||||
key.port[0] = pd->ndport;
|
||||
PF_ACPY(&key.addr[0], &pd->ndaddr, key.af);
|
||||
|
||||
do {
|
||||
PF_ACPY(&key.addr[1], naddr, key.af);
|
||||
if (*udp_mapping)
|
||||
if (udp_mapping && *udp_mapping)
|
||||
PF_ACPY(&(*udp_mapping)->endpoints[1].addr, naddr, pd->af);
|
||||
|
||||
/*
|
||||
|
|
@ -317,7 +338,7 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
} else if (low == high) {
|
||||
key.port[1] = htons(low);
|
||||
if (!pf_find_state_all_exists(&key, PF_IN)) {
|
||||
if (*udp_mapping != NULL) {
|
||||
if (udp_mapping && *udp_mapping != NULL) {
|
||||
(*udp_mapping)->endpoints[1].port = htons(low);
|
||||
if (pf_udp_mapping_insert(*udp_mapping) == 0) {
|
||||
*nport = htons(low);
|
||||
|
|
@ -341,7 +362,7 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
cut = arc4random() % (1 + high - low) + low;
|
||||
/* low <= cut <= high */
|
||||
for (tmp = cut; tmp <= high && tmp <= 0xffff; ++tmp) {
|
||||
if (*udp_mapping != NULL) {
|
||||
if (udp_mapping && *udp_mapping != NULL) {
|
||||
(*udp_mapping)->endpoints[1].port = htons(tmp);
|
||||
if (pf_udp_mapping_insert(*udp_mapping) == 0) {
|
||||
*nport = htons(tmp);
|
||||
|
|
@ -358,7 +379,8 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
tmp = cut;
|
||||
for (tmp -= 1; tmp >= low && tmp <= 0xffff; --tmp) {
|
||||
if (pd->proto == IPPROTO_UDP &&
|
||||
(r->rdr.opts & PF_POOL_ENDPI)) {
|
||||
(r->rdr.opts & PF_POOL_ENDPI &&
|
||||
udp_mapping != NULL)) {
|
||||
(*udp_mapping)->endpoints[1].port = htons(tmp);
|
||||
if (pf_udp_mapping_insert(*udp_mapping) == 0) {
|
||||
*nport = htons(tmp);
|
||||
|
|
@ -383,7 +405,7 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
*/
|
||||
(*sn) = NULL;
|
||||
if (pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL,
|
||||
&init_addr, sn, sh))
|
||||
&init_addr, sn, sh, &r->rdr))
|
||||
return (1);
|
||||
break;
|
||||
case PF_POOL_NONE:
|
||||
|
|
@ -392,11 +414,14 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
default:
|
||||
return (1);
|
||||
}
|
||||
} while (! PF_AEQ(&init_addr, naddr, pd->af) );
|
||||
} while (! PF_AEQ(&init_addr, naddr, pd->naf) );
|
||||
|
||||
failed:
|
||||
uma_zfree(V_pf_udp_mapping_z, *udp_mapping);
|
||||
*udp_mapping = NULL;
|
||||
if (udp_mapping) {
|
||||
uma_zfree(V_pf_udp_mapping_z, *udp_mapping);
|
||||
*udp_mapping = NULL;
|
||||
}
|
||||
|
||||
return (1); /* none available */
|
||||
}
|
||||
|
||||
|
|
@ -432,13 +457,15 @@ pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
for (i = cut; i <= ahigh; i++) {
|
||||
low = (i << ashift) | psmask;
|
||||
if (!pf_get_sport(pd, r,
|
||||
naddr, nport, low, low | highmask, sn, sh, udp_mapping))
|
||||
naddr, nport, low, low | highmask, sn, sh, &r->rdr,
|
||||
udp_mapping))
|
||||
return (0);
|
||||
}
|
||||
for (i = cut - 1; i > 0; i--) {
|
||||
low = (i << ashift) | psmask;
|
||||
if (!pf_get_sport(pd, r,
|
||||
naddr, nport, low, low | highmask, sn, sh, udp_mapping))
|
||||
naddr, nport, low, low | highmask, sn, sh, &r->rdr,
|
||||
udp_mapping))
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
|
|
@ -446,10 +473,10 @@ pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r,
|
|||
|
||||
u_short
|
||||
pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
|
||||
struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr)
|
||||
struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr,
|
||||
struct pf_kpool *rpool)
|
||||
{
|
||||
u_short reason = PFRES_MATCH;
|
||||
struct pf_kpool *rpool = &r->rdr;
|
||||
struct pf_addr *raddr = NULL, *rmask = NULL;
|
||||
|
||||
mtx_lock(&rpool->mtx);
|
||||
|
|
@ -621,10 +648,9 @@ done_pool_mtx:
|
|||
u_short
|
||||
pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
|
||||
struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr,
|
||||
struct pf_ksrc_node **sn, struct pf_srchash **sh)
|
||||
struct pf_ksrc_node **sn, struct pf_srchash **sh, struct pf_kpool *rpool)
|
||||
{
|
||||
u_short reason = 0;
|
||||
struct pf_kpool *rpool = &r->rdr;
|
||||
|
||||
KASSERT(*sn == NULL, ("*sn not NULL"));
|
||||
|
||||
|
|
@ -667,7 +693,7 @@ pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
|
|||
* Source node has not been found. Find a new address and store it
|
||||
* in variables given by the caller.
|
||||
*/
|
||||
if (pf_map_addr(af, r, saddr, naddr, nkif, init_addr) != 0) {
|
||||
if (pf_map_addr(af, r, saddr, naddr, nkif, init_addr, rpool) != 0) {
|
||||
/* pf_map_addr() sets reason counters on its own */
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -732,15 +758,8 @@ pf_get_translation(struct pf_pdesc *pd, int off,
|
|||
return (PFRES_MAX);
|
||||
}
|
||||
|
||||
*skp = pf_state_key_setup(pd, pd->nsport, pd->ndport);
|
||||
if (*skp == NULL)
|
||||
if (pf_state_key_setup(pd, pd->nsport, pd->ndport, skp, nkp))
|
||||
return (PFRES_MEMORY);
|
||||
*nkp = pf_state_key_clone(*skp);
|
||||
if (*nkp == NULL) {
|
||||
uma_zfree(V_pf_state_key_z, *skp);
|
||||
*skp = NULL;
|
||||
return (PFRES_MEMORY);
|
||||
}
|
||||
|
||||
naddr = &(*nkp)->addr[1];
|
||||
nportp = &(*nkp)->port[1];
|
||||
|
|
@ -767,7 +786,7 @@ pf_get_translation(struct pf_pdesc *pd, int off,
|
|||
goto notrans;
|
||||
}
|
||||
} else if (pf_get_sport(pd, r, naddr, nportp, low, high, &sn,
|
||||
&sh, udp_mapping)) {
|
||||
&sh, &r->rdr, udp_mapping)) {
|
||||
DPFPRINTF(PF_DEBUG_MISC,
|
||||
("pf: NAT proxy port allocation (%u-%u) failed\n",
|
||||
r->rdr.proxy_port[0], r->rdr.proxy_port[1]));
|
||||
|
|
@ -855,7 +874,7 @@ pf_get_translation(struct pf_pdesc *pd, int off,
|
|||
uint16_t cut, low, high, nport;
|
||||
|
||||
reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL,
|
||||
NULL, &sn, &sh);
|
||||
NULL, &sn, &sh, &r->rdr);
|
||||
if (reason != 0)
|
||||
goto notrans;
|
||||
if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
|
||||
|
|
@ -965,3 +984,132 @@ notrans:
|
|||
|
||||
return (reason);
|
||||
}
|
||||
|
||||
int
|
||||
pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd)
|
||||
{
|
||||
#if defined(INET) && defined(INET6)
|
||||
struct pf_addr ndaddr, nsaddr, naddr;
|
||||
u_int16_t nport = 0;
|
||||
int prefixlen = 96;
|
||||
struct pf_srchash *sh = NULL;
|
||||
struct pf_ksrc_node *sns = NULL;
|
||||
|
||||
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
||||
printf("pf: af-to %s %s, ",
|
||||
pd->naf == AF_INET ? "inet" : "inet6",
|
||||
TAILQ_EMPTY(&r->rdr.list) ? "nat" : "rdr");
|
||||
pf_print_host(&pd->nsaddr, pd->nsport, pd->af);
|
||||
printf(" -> ");
|
||||
pf_print_host(&pd->ndaddr, pd->ndport, pd->af);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (TAILQ_EMPTY(&r->nat.list))
|
||||
panic("pf_get_transaddr_af: no nat pool for source address");
|
||||
|
||||
/* get source address and port */
|
||||
if (pf_get_sport(pd, r, &nsaddr, &nport,
|
||||
r->nat.proxy_port[0], r->nat.proxy_port[1], &sns, &sh, &r->nat, NULL)) {
|
||||
DPFPRINTF(PF_DEBUG_MISC,
|
||||
("pf: af-to NAT proxy port allocation (%u-%u) failed",
|
||||
r->nat.proxy_port[0], r->nat.proxy_port[1]));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (pd->proto == IPPROTO_ICMPV6 && pd->naf == AF_INET) {
|
||||
if (pd->dir == PF_IN) {
|
||||
NTOHS(pd->ndport);
|
||||
if (pd->ndport == ICMP6_ECHO_REQUEST)
|
||||
pd->ndport = ICMP_ECHO;
|
||||
else if (pd->ndport == ICMP6_ECHO_REPLY)
|
||||
pd->ndport = ICMP_ECHOREPLY;
|
||||
HTONS(pd->ndport);
|
||||
} else {
|
||||
NTOHS(pd->nsport);
|
||||
if (pd->nsport == ICMP6_ECHO_REQUEST)
|
||||
pd->nsport = ICMP_ECHO;
|
||||
else if (pd->nsport == ICMP6_ECHO_REPLY)
|
||||
pd->nsport = ICMP_ECHOREPLY;
|
||||
HTONS(pd->nsport);
|
||||
}
|
||||
} else if (pd->proto == IPPROTO_ICMP && pd->naf == AF_INET6) {
|
||||
if (pd->dir == PF_IN) {
|
||||
NTOHS(pd->ndport);
|
||||
if (pd->ndport == ICMP_ECHO)
|
||||
pd->ndport = ICMP6_ECHO_REQUEST;
|
||||
else if (pd->ndport == ICMP_ECHOREPLY)
|
||||
pd->ndport = ICMP6_ECHO_REPLY;
|
||||
HTONS(pd->ndport);
|
||||
} else {
|
||||
NTOHS(pd->nsport);
|
||||
if (pd->nsport == ICMP_ECHO)
|
||||
pd->nsport = ICMP6_ECHO_REQUEST;
|
||||
else if (pd->nsport == ICMP_ECHOREPLY)
|
||||
pd->nsport = ICMP6_ECHO_REPLY;
|
||||
HTONS(pd->nsport);
|
||||
}
|
||||
}
|
||||
|
||||
/* get the destination address and port */
|
||||
if (! TAILQ_EMPTY(&r->rdr.list)) {
|
||||
if (pf_map_addr_sn(pd->naf, r, &nsaddr, &naddr, NULL, NULL,
|
||||
&sns, NULL, &r->rdr))
|
||||
return (-1);
|
||||
if (r->rdr.proxy_port[0])
|
||||
pd->ndport = htons(r->rdr.proxy_port[0]);
|
||||
|
||||
if (pd->naf == AF_INET) {
|
||||
/* The prefix is the IPv4 rdr address */
|
||||
prefixlen = in_mask2len(
|
||||
(struct in_addr *)&r->rdr.cur->addr.v.a.mask);
|
||||
inet_nat46(pd->naf, &pd->ndaddr, &ndaddr, &naddr,
|
||||
prefixlen);
|
||||
} else {
|
||||
/* The prefix is the IPv6 rdr address */
|
||||
prefixlen = in6_mask2len(
|
||||
(struct in6_addr *)&r->rdr.cur->addr.v.a.mask, NULL);
|
||||
inet_nat64(pd->naf, &pd->ndaddr, &ndaddr, &naddr,
|
||||
prefixlen);
|
||||
}
|
||||
} else {
|
||||
if (pd->naf == AF_INET) {
|
||||
/* The prefix is the IPv6 dst address */
|
||||
prefixlen = in6_mask2len(
|
||||
(struct in6_addr *)&r->dst.addr.v.a.mask, NULL);
|
||||
if (prefixlen < 32)
|
||||
prefixlen = 96;
|
||||
inet_nat64(pd->naf, &pd->ndaddr, &ndaddr, &pd->ndaddr,
|
||||
prefixlen);
|
||||
} else {
|
||||
/*
|
||||
* The prefix is the IPv6 nat address
|
||||
* (that was stored in pd->nsaddr)
|
||||
*/
|
||||
prefixlen = in6_mask2len(
|
||||
(struct in6_addr *)&r->nat.cur->addr.v.a.mask, NULL);
|
||||
if (prefixlen > 96)
|
||||
prefixlen = 96;
|
||||
inet_nat64(pd->naf, &pd->ndaddr, &ndaddr, &nsaddr,
|
||||
prefixlen);
|
||||
}
|
||||
}
|
||||
|
||||
PF_ACPY(&pd->nsaddr, &nsaddr, pd->naf);
|
||||
PF_ACPY(&pd->ndaddr, &ndaddr, pd->naf);
|
||||
|
||||
if (V_pf_status.debug >= PF_DEBUG_MISC) {
|
||||
printf("pf: af-to %s done, prefixlen %d, ",
|
||||
pd->naf == AF_INET ? "inet" : "inet6",
|
||||
prefixlen);
|
||||
pf_print_host(&pd->nsaddr, pd->nsport, pd->naf);
|
||||
printf(" -> ");
|
||||
pf_print_host(&pd->ndaddr, pd->ndport, pd->naf);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return (0);
|
||||
#else
|
||||
return (-1);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -733,6 +733,7 @@ static const struct nlattr_parser nla_p_rule[] = {
|
|||
{ .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
|
||||
{ .type = PF_RT_MAX_SRC_CONN, .off = _OUT(max_src_conn), .cb = nlattr_get_uint32 },
|
||||
{ .type = PF_RT_RPOOL_NAT, .off = _OUT(nat), .arg = &pool_parser, .cb = nlattr_get_nested },
|
||||
{ .type = PF_RT_NAF, .off = _OUT(naf), .cb = nlattr_get_uint8 },
|
||||
};
|
||||
NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
|
||||
#undef _OUT
|
||||
|
|
@ -960,6 +961,7 @@ pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
|||
nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
|
||||
|
||||
nlattr_add_u8(nw, PF_RT_AF, rule->af);
|
||||
nlattr_add_u8(nw, PF_RT_NAF, rule->naf);
|
||||
nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
|
||||
nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
|
||||
nlattr_add_u8(nw, PF_RT_CODE, rule->code);
|
||||
|
|
|
|||
|
|
@ -263,6 +263,7 @@ enum pf_rule_type_t {
|
|||
PF_RT_RCV_IFNAME = 73, /* string */
|
||||
PF_RT_MAX_SRC_CONN = 74, /* u32 */
|
||||
PF_RT_RPOOL_NAT = 75, /* nested, pf_rpool_type_t */
|
||||
PF_RT_NAF = 76, /* u8 */
|
||||
};
|
||||
|
||||
enum pf_addrule_type_t {
|
||||
|
|
|
|||
Loading…
Reference in a new issue