diff options
-rw-r--r-- | sbin/pfctl/parse.y | 44 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.c | 41 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 41 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.h | 5 | ||||
-rw-r--r-- | share/man/man5/nat.conf.5 | 15 | ||||
-rw-r--r-- | sys/net/pf.c | 318 | ||||
-rw-r--r-- | sys/net/pfvar.h | 32 |
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 = ≺ 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 |