summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjasoni <jasoni@cvs.openbsd.org>2001-09-06 18:05:47 +0000
committerjasoni <jasoni@cvs.openbsd.org>2001-09-06 18:05:47 +0000
commit4a538e249bf00fca90b9036971f51198ce5f9294 (patch)
tree34f5a207a8c9566af8febfa8c6093274e12ddcaa
parent60e3409ed149bdefcb774fa1336bcbf86d8d7a50 (diff)
1:1 bidrectional NAT (binat); ok dhartmei@ and frantzen@
-rw-r--r--sbin/pfctl/parse.y44
-rw-r--r--sbin/pfctl/pfctl.c41
-rw-r--r--sbin/pfctl/pfctl_parser.c41
-rw-r--r--sbin/pfctl/pfctl_parser.h5
-rw-r--r--share/man/man5/nat.conf.515
-rw-r--r--sys/net/pf.c318
-rw-r--r--sys/net/pfvar.h32
7 files changed, 474 insertions, 22 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index fc95032633d..3d3a1b0632a 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.28 2001/09/04 13:47:51 dhartmei Exp $ */
+/* $OpenBSD: parse.y,v 1.29 2001/09/06 18:05:46 jasoni Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -140,7 +140,7 @@ typedef struct {
%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS
%token RETURNRST RETURNICMP PROTO ALL ANY ICMPTYPE CODE KEEP MODULATE STATE
-%token PORT RDR NAT ARROW NODF MINTTL ERROR
+%token PORT RDR NAT ARROW NODF MINTTL ERROR BINAT
%token <v.string> STRING
%token <v.number> NUMBER
%token <v.i> PORTUNARY PORTBINARY
@@ -160,6 +160,7 @@ ruleset : /* empty */
| ruleset '\n'
| ruleset pfrule '\n'
| ruleset natrule '\n'
+ | ruleset binatrule '\n'
| ruleset rdrrule '\n'
| ruleset varset '\n'
| ruleset error '\n' { errors++; }
@@ -550,6 +551,44 @@ natrule : NAT interface proto FROM ipspec TO ipspec ARROW address
}
;
+binatrule : BINAT interface proto FROM ipspec TO ipspec ARROW address
+ {
+ struct pf_binat binat;
+
+ if (!natmode) {
+ yyerror("binat rule not permitted in filter mode");
+ YYERROR;
+ }
+ memset(&binat, 0, sizeof(binat));
+
+ if ($2 != NULL) {
+ memcpy(binat.ifname, $2->ifname,
+ sizeof(binat.ifname));
+ }
+ if ($3 != NULL) {
+ binat.proto = $3->proto;
+ free($3);
+ }
+ if ($5 != NULL) {
+ binat.saddr = $5->addr;
+ free($5);
+ }
+ if ($7 != NULL) {
+ binat.daddr = $7->addr;
+ binat.dmask = $7->mask;
+ binat.dnot = $7->not;
+ free($7);
+ }
+
+ if ($9 == NULL) {
+ yyerror("binat rule requires redirection address");
+ YYERROR;
+ }
+ binat.raddr = $9->addr;
+ free($9);
+ pfctl_add_binat(pf, &binat);
+ }
+
rdrrule : RDR interface proto FROM ipspec TO ipspec dport ARROW address rport
{
struct pf_rdr rdr;
@@ -819,6 +858,7 @@ lookup(char *s)
} keywords[] = {
{ "all", ALL},
{ "any", ANY},
+ { "binat", BINAT},
{ "block", BLOCK},
{ "code", CODE},
{ "flags", FLAGS},
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 524cae198a5..438ec5dc6ad 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.38 2001/08/28 00:02:43 frantzen Exp $ */
+/* $OpenBSD: pfctl.c,v 1.39 2001/09/06 18:05:46 jasoni Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -170,12 +170,17 @@ int
pfctl_clear_nat(int dev, int opts)
{
struct pfioc_nat pn;
+ struct pfioc_binat pb;
struct pfioc_rdr pr;
if (ioctl(dev, DIOCBEGINNATS, &pn.ticket))
err(1, "DIOCBEGINNATS");
else if (ioctl(dev, DIOCCOMMITNATS, &pn.ticket))
err(1, "DIOCCOMMITNATS");
+ if (ioctl(dev, DIOCBEGINBINATS, &pb.ticket))
+ err(1, "DIOCBEGINBINATS");
+ else if (ioctl(dev, DIOCCOMMITBINATS, &pb.ticket))
+ err(1, "DIOCCOMMITBINATS");
else if (ioctl(dev, DIOCBEGINRDRS, &pr.ticket))
err(1, "DIOCBEGINRDRS");
else if (ioctl(dev, DIOCCOMMITRDRS, &pr.ticket))
@@ -226,6 +231,7 @@ pfctl_show_nat(int dev)
{
struct pfioc_nat pn;
struct pfioc_rdr pr;
+ struct pfioc_binat pb;
u_int32_t mnr, nr;
if (ioctl(dev, DIOCGETNATS, &pn)) {
@@ -254,6 +260,19 @@ pfctl_show_nat(int dev)
}
print_rdr(&pr.rdr);
}
+ if (ioctl(dev, DIOCGETBINATS, &pb)) {
+ warnx("DIOCGETBINATS");
+ return (-1);
+ }
+ mnr = pb.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pb.nr = nr;
+ if (ioctl(dev, DIOCGETBINAT, &pb)) {
+ warnx("DIOCGETBINAT");
+ return (-1);
+ }
+ print_binat(&pb.binat);
+ }
return (0);
}
@@ -339,6 +358,19 @@ pfctl_add_nat(struct pfctl *pf, struct pf_nat *n)
}
int
+pfctl_add_binat(struct pfctl *pf, struct pf_binat *b)
+{
+ memcpy(&pf->pbinat->binat, b, sizeof(pf->pbinat->binat));
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCADDBINAT, pf->pbinat))
+ err(1, "DIOCADDBINAT");
+ }
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_binat(&pf->pbinat->binat);
+ return 0;
+}
+
+int
pfctl_add_rdr(struct pfctl *pf, struct pf_rdr *r)
{
memcpy(&pf->prdr->rdr, r, sizeof(pf->prdr->rdr));
@@ -395,6 +427,7 @@ pfctl_nat(int dev, char *filename, int opts)
{
FILE *fin;
struct pfioc_nat pn;
+ struct pfioc_binat pb;
struct pfioc_rdr pr;
struct pfctl pf;
@@ -413,11 +446,14 @@ pfctl_nat(int dev, char *filename, int opts)
err(1, "DIOCBEGINNATS");
if (ioctl(dev, DIOCBEGINRDRS, &pr.ticket))
err(1, "DIOCBEGINRDRS");
+ if (ioctl(dev, DIOCBEGINBINATS, &pb.ticket))
+ err(1, "DIOCBEGINBINATS");
}
/* fill in callback data */
pf.dev = dev;
pf.opts = opts;
pf.pnat = &pn;
+ pf.pbinat = &pb;
pf.prdr = &pr;
if (parse_nat(fin, &pf) < 0)
errx(1, "syntax error in file: nat rules not loaded");
@@ -426,10 +462,13 @@ pfctl_nat(int dev, char *filename, int opts)
err(1, "DIOCCOMMITNATS");
if (ioctl(dev, DIOCCOMMITRDRS, &pr.ticket))
err(1, "DIOCCOMMITRDRS");
+ if (ioctl(dev, DIOCCOMMITBINATS, &pb.ticket))
+ err(1, "DIOCCOMMITBINATS");
#if 0
if ((opts & PF_OPT_QUIET) == 0) {
printf("%u nat entries loaded\n", n);
printf("%u rdr entries loaded\n", r);
+ printf("%u binat entries loaded\n", b);
}
#endif
}
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index c852395394c..859d9402b5b 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.46 2001/09/02 15:15:31 dhartmei Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.47 2001/09/06 18:05:46 jasoni Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -291,6 +291,45 @@ print_nat(struct pf_nat *n)
}
void
+print_binat(struct pf_binat *b)
+{
+ printf("@binat ");
+ if (b->ifname[0]) {
+ printf("on ");
+ printf("%s ", b->ifname);
+ }
+ switch (b->proto) {
+ case IPPROTO_TCP:
+ printf("proto tcp ");
+ break;
+ case IPPROTO_UDP:
+ printf("proto udp ");
+ break;
+ case IPPROTO_ICMP:
+ printf("proto icmp ");
+ break;
+ }
+ printf("from ");
+ print_addr(b->saddr);
+ printf(" ");
+ printf("to ");
+ if (b->daddr || b->dmask) {
+ if (b->dnot)
+ printf("! ");
+ print_addr(b->daddr);
+ if (b->dmask != 0xFFFFFFFF) {
+ printf("/");
+ print_addr(b->dmask);
+ }
+ printf(" ");
+ } else
+ printf("any ");
+ printf("-> ");
+ print_addr(b->raddr);
+ printf("\n");
+}
+
+void
print_rdr(struct pf_rdr *r)
{
printf("@rdr ");
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index f89a94ce917..19ec3c76760 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.8 2001/08/23 04:10:51 deraadt Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.9 2001/09/06 18:05:46 jasoni Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -38,11 +38,13 @@ struct pfctl {
int opts;
struct pfioc_rule *prule;
struct pfioc_nat *pnat;
+ struct pfioc_binat *pbinat;
struct pfioc_rdr *prdr;
};
int pfctl_add_rule(struct pfctl *, struct pf_rule *);
int pfctl_add_nat(struct pfctl *, struct pf_nat *);
+int pfctl_add_binat(struct pfctl *, struct pf_binat *);
int pfctl_add_rdr(struct pfctl *, struct pf_rdr *);
int parse_rules(FILE *, struct pfctl *);
@@ -51,6 +53,7 @@ int parse_flags(char *);
void print_rule(struct pf_rule *);
void print_nat(struct pf_nat *);
+void print_binat(struct pf_binat *);
void print_rdr(struct pf_rdr *);
void print_state(struct pf_state *);
void print_status(struct pf_status *);
diff --git a/share/man/man5/nat.conf.5 b/share/man/man5/nat.conf.5
index 7636855323b..ecfa1354bf9 100644
--- a/share/man/man5/nat.conf.5
+++ b/share/man/man5/nat.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: nat.conf.5,v 1.9 2001/08/22 17:42:24 beck Exp $
+.\" $OpenBSD: nat.conf.5,v 1.10 2001/09/06 18:05:46 jasoni Exp $
.\"
.\" Copyright (c) 2001 Ian Darwin. All rights reserved.
.\"
@@ -57,11 +57,14 @@ to another host and optionally a different port.
.Sh GRAMMAR
Syntax for filter rules in BNF:
.Bd -literal
-rule = nat_rule | rdr_rule
+rule = nat_rule | binat_rule | rdr_rule
nat_rule = "nat" "on" [ "!" ] ifname [ protospec ] "from" ipspec
"to" ipspec "->" address
+binat_rule = "binat" "on" ifname [ protospec ] "from" ipspec
+ "to" ipspec "->" address
+
rdr_rule = "rdr" "on" [ "!" ] ifname [ protospec ] "from" ipspec
"to" ipspec portspec "->" address portspec
@@ -126,6 +129,14 @@ fake internal 144.19.74.* network, and a routable external IP of 204.92.77.100:
nat on fxp1 from 144.19.74/24 to any -> 204.92.77.100
.Ed
.Pp
+In the example below, fxp0 is the outside interface; a 1:1
+bidirectional map is created between the private address 192.168.1.5
+and the routable external address 204.92.77.113. (Thus, incoming
+traffic to 204.92.77.113 is mapped to the internal address 192.168.1.5.)
+.Bd -literal
+binat on fxp0 from 192.168.1.5/32 to any -> 204.92.77.113
+.Ed
+.Pp
This longer example uses both a NAT and a redirection. Interface
kue0 is the outside interface, and its external address is 157.161.48.183.
Interface fxp0 is the inside interface, and we are running
diff --git a/sys/net/pf.c b/sys/net/pf.c
index d5185395b07..284008a346c 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.146 2001/09/05 19:12:59 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.147 2001/09/06 18:05:46 jasoni Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -90,12 +90,15 @@ LIST_HEAD(pf_port_list, pf_port_node);
*/
TAILQ_HEAD(pf_natqueue, pf_nat) pf_nats[2];
+TAILQ_HEAD(pf_binatqueue, pf_binat) pf_binats[2];
TAILQ_HEAD(pf_rdrqueue, pf_rdr) pf_rdrs[2];
struct pf_rulequeue pf_rules[2];
struct pf_rulequeue *pf_rules_active;
struct pf_rulequeue *pf_rules_inactive;
struct pf_natqueue *pf_nats_active;
struct pf_natqueue *pf_nats_inactive;
+struct pf_binatqueue *pf_binats_active;
+struct pf_binatqueue *pf_binats_inactive;
struct pf_rdrqueue *pf_rdrs_active;
struct pf_rdrqueue *pf_rdrs_inactive;
struct pf_tree_node *tree_lan_ext, *tree_ext_gwy;
@@ -108,6 +111,8 @@ u_int32_t ticket_rules_active;
u_int32_t ticket_rules_inactive;
u_int32_t ticket_nats_active;
u_int32_t ticket_nats_inactive;
+u_int32_t ticket_binats_active;
+u_int32_t ticket_binats_inactive;
u_int32_t ticket_rdrs_active;
u_int32_t ticket_rdrs_inactive;
struct pf_port_list pf_tcp_ports;
@@ -142,13 +147,15 @@ int *pftm_timeouts[PFTM_MAX] = { &pftm_tcp_first_packet,
struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl, pf_sport_pl;
-struct pool pf_rdr_pl, pf_state_pl;
+struct pool pf_rdr_pl, pf_state_pl, pf_binat_pl;
int pf_tree_key_compare(struct pf_tree_key *,
struct pf_tree_key *);
int pf_compare_rules(struct pf_rule *,
struct pf_rule *);
int pf_compare_nats(struct pf_nat *, struct pf_nat *);
+int pf_compare_binats(struct pf_binat *,
+ struct pf_binat *);
int pf_compare_rdrs(struct pf_rdr *, struct pf_rdr *);
void pf_tree_rotate_left(struct pf_tree_node **);
void pf_tree_rotate_right(struct pf_tree_node **);
@@ -182,6 +189,8 @@ void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t);
u_int16_t pf_map_port_range(struct pf_rdr *, u_int16_t);
struct pf_nat *pf_get_nat(struct ifnet *, u_int8_t, u_int32_t,
u_int32_t);
+struct pf_binat *pf_get_binat(int direction, struct ifnet *, u_int8_t,
+ u_int32_t, u_int32_t);
struct pf_rdr *pf_get_rdr(struct ifnet *, u_int8_t, u_int32_t,
u_int32_t, u_int16_t);
int pf_test_tcp(int, struct ifnet *, struct mbuf *,
@@ -301,6 +310,21 @@ pf_compare_nats(struct pf_nat *a, struct pf_nat *b)
}
int
+pf_compare_binats(struct pf_binat *a, struct pf_binat *b)
+{
+ if (a->saddr != b->saddr ||
+ a->daddr != b->daddr ||
+ a->dmask != b->dmask ||
+ a->raddr != b->raddr ||
+ a->proto != b->proto ||
+ a->dnot != b->dnot)
+ return (1);
+ if (strcmp(a->ifname, b->ifname))
+ return (1);
+ return (0);
+}
+
+int
pf_compare_rdrs(struct pf_rdr *a, struct pf_rdr *b)
{
if (a->saddr != b->saddr ||
@@ -758,6 +782,8 @@ pfattach(int num)
0, NULL, NULL, 0);
pool_init(&pf_nat_pl, sizeof(struct pf_nat), 0, 0, 0, "pfnatpl",
0, NULL, NULL, 0);
+ pool_init(&pf_binat_pl, sizeof(struct pf_binat), 0, 0, 0, "pfbinatpl",
+ 0, NULL, NULL, 0);
pool_init(&pf_rdr_pl, sizeof(struct pf_rdr), 0, 0, 0, "pfrdrpl",
0, NULL, NULL, 0);
pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
@@ -769,12 +795,16 @@ pfattach(int num)
TAILQ_INIT(&pf_rules[1]);
TAILQ_INIT(&pf_nats[0]);
TAILQ_INIT(&pf_nats[1]);
+ TAILQ_INIT(&pf_binats[0]);
+ TAILQ_INIT(&pf_binats[1]);
TAILQ_INIT(&pf_rdrs[0]);
TAILQ_INIT(&pf_rdrs[1]);
pf_rules_active = &pf_rules[0];
pf_rules_inactive = &pf_rules[1];
pf_nats_active = &pf_nats[0];
pf_nats_inactive = &pf_nats[1];
+ pf_binats_active = &pf_binats[0];
+ pf_binats_inactive = &pf_binats[1];
pf_rdrs_active = &pf_rdrs[0];
pf_rdrs_inactive = &pf_rdrs[1];
@@ -819,6 +849,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCBEGINNATS:
case DIOCADDNAT:
case DIOCCOMMITNATS:
+ case DIOCBEGINBINATS:
+ case DIOCADDBINAT:
+ case DIOCCOMMITBINATS:
case DIOCBEGINRDRS:
case DIOCADDRDR:
case DIOCCOMMITRDRS:
@@ -1222,6 +1255,178 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ case DIOCBEGINBINATS: {
+ u_int32_t *ticket = (u_int32_t *)addr;
+ struct pf_binat *binat;
+
+ while ((binat = TAILQ_FIRST(pf_binats_inactive)) != NULL) {
+ TAILQ_REMOVE(pf_binats_inactive, binat, entries);
+ pool_put(&pf_binat_pl, binat);
+ }
+ *ticket = ++ticket_binats_inactive;
+ break;
+ }
+
+ case DIOCADDBINAT: {
+ struct pfioc_binat *pb = (struct pfioc_binat *)addr;
+ struct pf_binat *binat;
+
+ if (pb->ticket != ticket_binats_inactive) {
+ error = EBUSY;
+ break;
+ }
+ binat = pool_get(&pf_binat_pl, PR_NOWAIT);
+ if (binat == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bcopy(&pb->binat, binat, sizeof(struct pf_binat));
+ if (binat->ifname[0]) {
+ binat->ifp = ifunit(binat->ifname);
+ if (binat->ifp == NULL) {
+ pool_put(&pf_binat_pl, binat);
+ error = EINVAL;
+ break;
+ }
+ } else
+ binat->ifp = NULL;
+ TAILQ_INSERT_TAIL(pf_binats_inactive, binat, entries);
+ break;
+ }
+
+ case DIOCCOMMITBINATS: {
+ u_int32_t *ticket = (u_int32_t *)addr;
+ struct pf_binatqueue *old_binats;
+ struct pf_binat *binat;
+
+ if (*ticket != ticket_binats_inactive) {
+ error = EBUSY;
+ break;
+ }
+
+ /* Swap binats, keep the old. */
+ s = splsoftnet();
+ old_binats = pf_binats_active;
+ pf_binats_active = pf_binats_inactive;
+ pf_binats_inactive = old_binats;
+ ticket_binats_active = ticket_binats_inactive;
+ splx(s);
+
+ /* Purge the old binat list */
+ while ((binat = TAILQ_FIRST(old_binats)) != NULL) {
+ TAILQ_REMOVE(old_binats, binat, entries);
+ pool_put(&pf_binat_pl, binat);
+ }
+ break;
+ }
+
+ case DIOCGETBINATS: {
+ struct pfioc_binat *pb = (struct pfioc_binat *)addr;
+ struct pf_binat *binat;
+
+ pb->nr = 0;
+ s = splsoftnet();
+ TAILQ_FOREACH(binat, pf_binats_active, entries)
+ pb->nr++;
+ pb->ticket = ticket_binats_active;
+ splx(s);
+ break;
+ }
+
+ case DIOCGETBINAT: {
+ struct pfioc_binat *pb = (struct pfioc_binat *)addr;
+ struct pf_binat *binat;
+ u_int32_t nr;
+
+ if (pb->ticket != ticket_binats_active) {
+ error = EBUSY;
+ break;
+ }
+ nr = 0;
+ s = splsoftnet();
+ binat = TAILQ_FIRST(pf_binats_active);
+ while ((binat != NULL) && (nr < pb->nr)) {
+ binat = TAILQ_NEXT(binat, entries);
+ nr++;
+ }
+ if (binat == NULL) {
+ error = EBUSY;
+ splx(s);
+ break;
+ }
+ bcopy(binat, &pb->binat, sizeof(struct pf_binat));
+ splx(s);
+ break;
+ }
+
+ case DIOCCHANGEBINAT: {
+ struct pfioc_changebinat *pcn = (struct pfioc_changebinat *)addr;
+ struct pf_binat *oldbinat = NULL, *newbinat = NULL;
+
+ if (pcn->action < PF_CHANGE_ADD_HEAD ||
+ pcn->action > PF_CHANGE_REMOVE) {
+ error = EINVAL;
+ break;
+ }
+
+ if (pcn->action != PF_CHANGE_REMOVE) {
+ newbinat = pool_get(&pf_binat_pl, PR_NOWAIT);
+ if (newbinat == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bcopy(&pcn->newbinat, newbinat,
+ sizeof(struct pf_binat));
+ newbinat->ifp = NULL;
+ if (newbinat->ifname[0]) {
+ newbinat->ifp = ifunit(newbinat->ifname);
+ if (newbinat->ifp == NULL) {
+ pool_put(&pf_binat_pl, newbinat);
+ error = EINVAL;
+ break;
+ }
+ }
+ }
+
+ s = splsoftnet();
+
+ if (pcn->action == PF_CHANGE_ADD_HEAD)
+ oldbinat = TAILQ_FIRST(pf_binats_active);
+ else if (pcn->action == PF_CHANGE_ADD_TAIL)
+ oldbinat = TAILQ_LAST(pf_binats_active, pf_binatqueue);
+ else {
+ oldbinat = TAILQ_FIRST(pf_binats_active);
+ while ((oldbinat != NULL) && pf_compare_binats(oldbinat,
+ &pcn->oldbinat))
+ oldbinat = TAILQ_NEXT(oldbinat, entries);
+ if (oldbinat == NULL) {
+ error = EINVAL;
+ splx(s);
+ break;
+ }
+ }
+
+ if (pcn->action == PF_CHANGE_REMOVE) {
+ TAILQ_REMOVE(pf_binats_active, oldbinat, entries);
+ pool_put(&pf_binat_pl, oldbinat);
+ } else {
+ if (oldbinat == NULL)
+ TAILQ_INSERT_TAIL(pf_binats_active, newbinat,
+ entries);
+ else if (pcn->action == PF_CHANGE_ADD_HEAD ||
+ pcn->action == PF_CHANGE_ADD_BEFORE)
+ TAILQ_INSERT_BEFORE(oldbinat, newbinat,
+ entries);
+ else
+ TAILQ_INSERT_AFTER(pf_binats_active, oldbinat,
+ newbinat, entries);
+ }
+
+ ticket_binats_active++;
+ splx(s);
+ break;
+ }
+
case DIOCBEGINRDRS: {
u_int32_t *ticket = (u_int32_t *)addr;
struct pf_rdr *rdr;
@@ -1959,6 +2164,30 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr)
return (nm);
}
+struct pf_binat *
+pf_get_binat(int direction, struct ifnet *ifp, u_int8_t proto,
+ u_int32_t saddr, u_int32_t daddr)
+{
+ struct pf_binat *b, *bm = NULL;
+
+ b = TAILQ_FIRST(pf_binats_active);
+ while (b && bm == NULL) {
+ if (direction == PF_OUT && b->ifp == ifp &&
+ (!b->proto || b->proto == proto) &&
+ pf_match_addr(0, b->saddr, 0xffffffff, saddr) &&
+ pf_match_addr(b->dnot, b->daddr, b->dmask, daddr))
+ bm = b;
+ else if (direction == PF_IN && b->ifp == ifp &&
+ (!b->proto || b->proto == proto) &&
+ pf_match_addr(0, b->raddr, 0xffffffff, saddr) &&
+ pf_match_addr(b->dnot, b->daddr, b->dmask, daddr))
+ bm = b;
+ else
+ b = TAILQ_NEXT(b, entries);
+ }
+ return (bm);
+}
+
struct pf_rdr *
pf_get_rdr(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr,
u_int16_t dport)
@@ -1999,6 +2228,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m,
int ipoff, int off, struct ip *h, struct tcphdr *th)
{
struct pf_nat *nat = NULL;
+ struct pf_binat *binat = NULL;
struct pf_rdr *rdr = NULL;
u_int32_t baddr;
u_int16_t bport, nport = 0;
@@ -2007,8 +2237,18 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m,
int rewrite = 0, error;
if (direction == PF_OUT) {
+ /* check outgoing packet for BINAT */
+ if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_TCP,
+ h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) {
+ baddr = h->ip_src.s_addr;
+ bport = th->th_sport;
+ pf_change_ap(&h->ip_src.s_addr, &th->th_sport,
+ &h->ip_sum, &th->th_sum, binat->raddr,
+ th->th_sport, 0);
+ rewrite++;
+ }
/* check outgoing packet for NAT */
- if ((nat = pf_get_nat(ifp, IPPROTO_TCP,
+ else if ((nat = pf_get_nat(ifp, IPPROTO_TCP,
h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) {
baddr = h->ip_src.s_addr;
bport = th->th_sport;
@@ -2036,6 +2276,16 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m,
&h->ip_sum, &th->th_sum, rdr->raddr, nport, 0);
rewrite++;
}
+ /* check incoming packet for BINAT */
+ if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_TCP,
+ h->ip_dst.s_addr, h->ip_dst.s_addr)) != NULL) {
+ baddr = h->ip_dst.s_addr;
+ bport = th->th_dport;
+ pf_change_ap(&h->ip_dst.s_addr, &th->th_dport,
+ &h->ip_sum, &th->th_sum, binat->saddr,
+ th->th_dport, 0);
+ rewrite++;
+ }
}
r = TAILQ_FIRST(pf_rules_active);
@@ -2108,7 +2358,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m,
}
}
- if (((rm != NULL) && rm->keep_state) || nat != NULL || rdr != NULL) {
+ if (((rm != NULL) && rm->keep_state) || nat != NULL || binat != NULL || rdr != NULL) {
/* create new state */
u_int16_t len;
struct pf_state *s;
@@ -2130,7 +2380,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m,
s->gwy.port = th->th_sport; /* sport */
s->ext.addr = h->ip_dst.s_addr;
s->ext.port = th->th_dport;
- if (nat != NULL) {
+ if (nat != NULL || binat != NULL) {
s->lan.addr = baddr;
s->lan.port = bport;
} else {
@@ -2142,7 +2392,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m,
s->lan.port = th->th_dport;
s->ext.addr = h->ip_src.s_addr;
s->ext.port = th->th_sport;
- if (rdr != NULL) {
+ if (binat != NULL || rdr != NULL) {
s->gwy.addr = baddr;
s->gwy.port = bport;
} else {
@@ -2193,6 +2443,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m,
int ipoff, int off, struct ip *h, struct udphdr *uh)
{
struct pf_nat *nat = NULL;
+ struct pf_binat *binat = NULL;
struct pf_rdr *rdr = NULL;
u_int32_t baddr;
u_int16_t bport, nport = 0;
@@ -2201,8 +2452,18 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m,
int rewrite = 0, error;
if (direction == PF_OUT) {
+ /* check outgoing packet for BINAT */
+ if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_UDP,
+ h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) {
+ baddr = h->ip_src.s_addr;
+ bport = uh->uh_sport;
+ pf_change_ap(&h->ip_src.s_addr, &uh->uh_sport,
+ &h->ip_sum, &uh->uh_sum, binat->raddr,
+ uh->uh_sport, 1);
+ rewrite++;
+ }
/* check outgoing packet for NAT */
- if ((nat = pf_get_nat(ifp, IPPROTO_UDP,
+ else if ((nat = pf_get_nat(ifp, IPPROTO_UDP,
h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) {
baddr = h->ip_src.s_addr;
bport = uh->uh_sport;
@@ -2232,6 +2493,16 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m,
rewrite++;
}
+ /* check incoming packet for BINAT */
+ if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_UDP,
+ h->ip_dst.s_addr, h->ip_dst.s_addr)) != NULL) {
+ baddr = h->ip_dst.s_addr;
+ bport = uh->uh_dport;
+ pf_change_ap(&h->ip_dst.s_addr, &uh->uh_dport,
+ &h->ip_sum, &uh->uh_sum, binat->saddr,
+ uh->uh_dport, 1);
+ rewrite++;
+ }
}
r = TAILQ_FIRST(pf_rules_active);
@@ -2298,7 +2569,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m,
}
}
- if ((rm != NULL && rm->keep_state) || nat != NULL || rdr != NULL) {
+ if ((rm != NULL && rm->keep_state) || nat != NULL || binat != NULL || rdr != NULL) {
/* create new state */
u_int16_t len;
struct pf_state *s;
@@ -2320,7 +2591,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m,
s->gwy.port = uh->uh_sport;
s->ext.addr = h->ip_dst.s_addr;
s->ext.port = uh->uh_dport;
- if (nat != NULL) {
+ if (nat != NULL || binat != NULL) {
s->lan.addr = baddr;
s->lan.port = bport;
} else {
@@ -2332,7 +2603,7 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m,
s->lan.port = uh->uh_dport;
s->ext.addr = h->ip_src.s_addr;
s->ext.port = uh->uh_sport;
- if (rdr != NULL) {
+ if (binat != NULL || rdr != NULL) {
s->gwy.addr = baddr;
s->gwy.port = bport;
} else {
@@ -2369,17 +2640,33 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m,
int ipoff, int off, struct ip *h, struct icmp *ih)
{
struct pf_nat *nat = NULL;
+ struct pf_binat *binat = NULL;
u_int32_t baddr;
struct pf_rule *r, *rm = NULL;
u_short reason;
if (direction == PF_OUT) {
+ /* check outgoing packet for BINAT */
+ if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_ICMP,
+ h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) {
+ baddr = h->ip_src.s_addr;
+ pf_change_a(&h->ip_src.s_addr, &h->ip_sum,
+ binat->raddr, 0);
+ }
/* check outgoing packet for NAT */
- if ((nat = pf_get_nat(ifp, IPPROTO_ICMP,
+ else if ((nat = pf_get_nat(ifp, IPPROTO_ICMP,
h->ip_src.s_addr, h->ip_dst.s_addr)) != NULL) {
baddr = h->ip_src.s_addr;
pf_change_a(&h->ip_src.s_addr, &h->ip_sum, nat->raddr, 0);
}
+ } else {
+ /* check incoming packet for BINAT */
+ if ((binat = pf_get_binat(PF_IN, ifp, IPPROTO_ICMP,
+ h->ip_dst.s_addr, h->ip_src.s_addr)) != NULL) {
+ baddr = h->ip_dst.s_addr;
+ pf_change_a(&h->ip_dst.s_addr, &h->ip_sum,
+ binat->saddr, 0);
+ }
}
r = TAILQ_FIRST(pf_rules_active);
@@ -2426,7 +2713,7 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m,
return (PF_DROP);
}
- if ((rm != NULL && rm->keep_state) || nat != NULL) {
+ if ((rm != NULL && rm->keep_state) || nat != NULL || binat != NULL) {
/* create new state */
u_int16_t len;
u_int16_t id;
@@ -2447,7 +2734,7 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m,
s->gwy.port = id;
s->ext.addr = h->ip_dst.s_addr;
s->ext.port = id;
- if (nat != NULL)
+ if (nat != NULL || binat != NULL)
s->lan.addr = baddr;
else
s->lan.addr = s->gwy.addr;
@@ -2457,7 +2744,10 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m,
s->lan.port = id;
s->ext.addr = h->ip_src.s_addr;
s->ext.port = id;
- s->gwy.addr = s->lan.addr;
+ if (binat != NULL)
+ s->gwy.addr = baddr;
+ else
+ s->gwy.addr = s->lan.addr;
s->gwy.port = id;
}
s->src.seqlo = 0;
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 2506d414ef4..2f761dd6687 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.49 2001/09/05 12:42:31 dhartmei Exp $ */
+/* $OpenBSD: pfvar.h,v 1.50 2001/09/06 18:05:46 jasoni Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -151,6 +151,18 @@ struct pf_nat {
u_int8_t ifnot;
};
+struct pf_binat {
+ char ifname[IFNAMSIZ];
+ struct ifnet *ifp;
+ TAILQ_ENTRY(pf_binat) entries;
+ u_int32_t saddr;
+ u_int32_t daddr;
+ u_int32_t dmask;
+ u_int32_t raddr;
+ u_int8_t proto;
+ u_int8_t dnot;
+};
+
struct pf_rdr {
char ifname[IFNAMSIZ];
struct ifnet *ifp;
@@ -279,6 +291,18 @@ struct pfioc_natlook {
u_int8_t direction;
};
+struct pfioc_binat {
+ u_int32_t ticket;
+ u_int32_t nr;
+ struct pf_binat binat;
+};
+
+struct pfioc_changebinat {
+ u_int32_t action;
+ struct pf_binat oldbinat;
+ struct pf_binat newbinat;
+};
+
struct pfioc_rdr {
u_int32_t ticket;
u_int32_t nr;
@@ -349,6 +373,12 @@ struct pfioc_tm {
#define DIOCCHANGERDR _IOWR('D', 28, struct pfioc_changerdr)
#define DIOCSETTIMEOUT _IOWR('D', 29, struct pfioc_tm)
#define DIOCGETTIMEOUT _IOWR('D', 30, struct pfioc_tm)
+#define DIOCBEGINBINATS _IOWR('D', 31, u_int32_t)
+#define DIOCADDBINAT _IOWR('D', 32, struct pfioc_binat)
+#define DIOCCOMMITBINATS _IOWR('D', 33, u_int32_t)
+#define DIOCGETBINATS _IOWR('D', 34, struct pfioc_binat)
+#define DIOCGETBINAT _IOWR('D', 35, struct pfioc_binat)
+#define DIOCCHANGEBINAT _IOWR('D', 36, struct pfioc_changebinat)
#ifdef _KERNEL