From b2e5ab0e0fbf50909c74b8c819ec38eca710d485 Mon Sep 17 00:00:00 2001 From: Daniel Hartmeier Date: Mon, 9 Jul 2001 10:30:59 +0000 Subject: Extend nat/rdr syntax. Add source/destination selection. Make interface optional. Suggested by rdump@river.com. nat [on [!] ] from (any | [!] [/]) to (any | [!] [/]) -> [proto (tcp | udp | icmp)] rdr [on [!] ] from (any | [!] [/]) to (any | [!] [/]) port [:] -> port [:*] [proto (tcp | udp | icmp)] --- etc/nat.conf | 6 +- sbin/pfctl/pfctl_parser.c | 238 ++++++++++++++++++++++++++++++++++------------ sys/net/pf.c | 83 +++++++++------- sys/net/pfvar.h | 12 ++- 4 files changed, 236 insertions(+), 103 deletions(-) diff --git a/etc/nat.conf b/etc/nat.conf index d8779f242d3..463b0089c1e 100644 --- a/etc/nat.conf +++ b/etc/nat.conf @@ -1,4 +1,4 @@ -# $OpenBSD: nat.conf,v 1.2 2001/06/26 22:58:31 smart Exp $ +# $OpenBSD: nat.conf,v 1.3 2001/07/09 10:30:58 dhartmei Exp $ # # See nat.conf(5) for syntax and examples # @@ -9,10 +9,10 @@ # translated as coming from 192.168.1.1. a state is created for such packets, # and incoming packets will be redirected to the internal address. -# nat ext0 10.0.0.0/8 -> 192.168.1.1 +# nat on ext0 from 10.0.0.0/8 to any -> 192.168.1.1 # rdr: packets coming in through ext0 with destination 192.168.1.1:1234 will # be redirected to 10.1.1.1:5678. a state is created for such packets, and # outgoing packets will be translated as coming from the external address. -# rdr ext0 192.168.1.1/32 port 1234 -> 10.1.1.1 port 5678 proto tcp +# rdr on ext0 from any to 192.168.1.1/32 port 1234 -> 10.1.1.1 port 5678 proto tcp diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 6a979969a9a..1c2d39e8752 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.28 2001/07/06 21:19:54 chris Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.29 2001/07/09 10:30:58 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -263,27 +263,48 @@ void print_nat(struct pf_nat *n) { printf("nat "); - if (n->ifnot) - printf("! "); - printf("%s ", n->ifname); - if (n->not) - printf("! "); - print_addr(n->saddr); - if (n->smask != 0xFFFFFFFF) { - printf("/"); - print_addr(n->smask); + if (n->ifname[0]) { + printf("on "); + if (n->ifnot) + printf("! "); + printf("%s ", n->ifname); } - printf(" -> "); - print_addr(n->daddr); + printf("from "); + if (n->saddr || n->smask) { + if (n->snot) + printf("! "); + print_addr(n->saddr); + if (n->smask != 0xFFFFFFFF) { + printf("/"); + print_addr(n->smask); + } + printf(" "); + } else + printf("any "); + printf("to "); + if (n->daddr || n->dmask) { + if (n->dnot) + printf("! "); + print_addr(n->daddr); + if (n->dmask != 0xFFFFFFFF) { + printf("/"); + print_addr(n->dmask); + } + printf(" "); + } else + printf("any "); + printf("-> "); + print_addr(n->raddr); + printf(" "); switch (n->proto) { case IPPROTO_TCP: - printf(" proto tcp"); + printf("proto tcp"); break; case IPPROTO_UDP: - printf(" proto udp"); + printf("proto udp"); break; case IPPROTO_ICMP: - printf(" proto icmp"); + printf("proto icmp"); break; } printf("\n"); @@ -293,30 +314,52 @@ void print_rdr(struct pf_rdr *r) { printf("rdr "); - if (r->ifnot) - printf("! "); - printf("%s ", r->ifname); - if (r->not) - printf("! "); - print_addr(r->daddr); - if (r->dmask != 0xFFFFFFFF) { - printf("/"); - print_addr(r->dmask); + if (r->ifname[0]) { + printf("on "); + if (r->ifnot) + printf("! "); + printf("%s ", r->ifname); } - printf(" port %u", ntohs(r->dport)); + printf("from "); + if (r->saddr || r->smask) { + if (r->snot) + printf("! "); + print_addr(r->saddr); + if (r->smask != 0xFFFFFFFF) { + printf("/"); + print_addr(r->smask); + } + printf(" "); + } else + printf("any "); + printf("to "); + if (r->daddr || r->dmask) { + if (r->dnot) + printf("! "); + print_addr(r->daddr); + if (r->dmask != 0xFFFFFFFF) { + printf("/"); + print_addr(r->dmask); + } + printf(" "); + } else + printf("any "); + printf("port %u", ntohs(r->dport)); if (r->opts & PF_DPORT_RANGE) printf(":%u", ntohs(r->dport2)); printf(" -> "); print_addr(r->raddr); - printf(" port %u", ntohs(r->rport)); + printf(" "); + printf("port %u", ntohs(r->rport)); if (r->opts & PF_RPORT_RANGE) printf(":*"); + printf(" "); switch (r->proto) { case IPPROTO_TCP: - printf(" proto tcp"); + printf("proto tcp"); break; case IPPROTO_UDP: - printf(" proto udp"); + printf("proto udp"); break; } printf("\n"); @@ -982,29 +1025,66 @@ parse_nat(int n, char *l, struct pf_nat *nat) } w = next_word(&l); - /* if */ - if (!strcmp(w, "!")) { - nat->ifnot = 1; + /* interface */ + if (!strcmp(w, "on")) { + w = next_word(&l); + if (!strcmp(w, "!")) { + nat->ifnot = 1; + w = next_word(&l); + } + strncpy(nat->ifname, w, 16); w = next_word(&l); } - strncpy(nat->ifname, w, 16); - w = next_word(&l); - /* internal addr/mask */ - if (!strcmp(w, "!")) { - nat->not = 1; - w = next_word(&l); + /* source addr/mask */ + if (strcmp(w, "from")) { + error(n, "expected from, got %s\n", w); + return (0); } - nat->saddr = next_addr(&w); - if (!*w) - nat->smask = 0xFFFFFFFF; - else if (*w == '/') - nat->smask = rule_mask(next_number(&w)); + w = next_word(&l); + if (!strcmp(w, "any")) + w = next_word(&l); else { - error(n, "expected /, got '%c'\n", *w); + if (!strcmp(w, "!")) { + nat->snot = 1; + w = next_word(&l); + } + nat->saddr = next_addr(&w); + if (!*w) + nat->smask = 0xFFFFFFFF; + else if (*w == '/') + nat->smask = rule_mask(next_number(&w)); + else { + error(n, "expected /, get '%c'\n", *w); + return (0); + } + w = next_word(&l); + } + + /* destination addr/mask */ + if (strcmp(w, "to")) { + error(n, "expected to, got %s\n", w); return (0); } w = next_word(&l); + if (!strcmp(w, "any")) + w = next_word(&l); + else { + if (!strcmp(w, "!")) { + nat->dnot = 1; + w = next_word(&l); + } + nat->daddr = next_addr(&w); + if (!*w) + nat->dmask = 0xFFFFFFFF; + else if (*w == '/') + nat->dmask = rule_mask(next_number(&w)); + else { + error(n, "expected /, get '%c'\n", *w); + return (0); + } + w = next_word(&l); + } /* -> */ if (strcmp(w, "->")) { @@ -1014,7 +1094,7 @@ parse_nat(int n, char *l, struct pf_nat *nat) w = next_word(&l); /* external addr */ - nat->daddr = next_addr(&w); + nat->raddr = next_addr(&w); w = next_word(&l); /* proto */ @@ -1057,31 +1137,68 @@ parse_rdr(int n, char *l, struct pf_rdr *rdr) } w = next_word(&l); - /* if */ - if (!strcmp(w, "!")) { - rdr->ifnot = 1; + /* interface */ + if (!strcmp(w, "on")) { + w = next_word(&l); + if (!strcmp(w, "!")) { + rdr->ifnot = 1; + w = next_word(&l); + } + strncpy(rdr->ifname, w, 16); w = next_word(&l); } - strncpy(rdr->ifname, w, 16); - w = next_word(&l); - /* external addr/mask */ - if (!strcmp(w, "!")) { - rdr->not = 1; - w = next_word(&l); + /* source addr/mask */ + if (strcmp(w, "from")) { + error(n, "expected from, got %s\n", w); + return (0); } - rdr->daddr = next_addr(&w); - if (!*w) - rdr->dmask = 0xFFFFFFFF; - else if (*w == '/') - rdr->dmask = rule_mask(next_number(&w)); + w = next_word(&l); + if (!strcmp(w, "any")) + w = next_word(&l); else { - error(n, "expected /, got '%c'\n", *w); + if (!strcmp(w, "!")) { + rdr->snot = 1; + w = next_word(&l); + } + rdr->saddr = next_addr(&w); + if (!*w) + rdr->smask = 0xFFFFFFFF; + else if (*w == '/') + rdr->smask = rule_mask(next_number(&w)); + else { + error(n, "expected /, get '%c'\n", *w); + return (0); + } + w = next_word(&l); + } + + /* external addr/mask */ + if (strcmp(w, "to")) { + error(n, "expected to, got %s\n", w); return (0); } w = next_word(&l); + if (!strcmp(w, "any")) + w = next_word(&l); + else { + if (!strcmp(w, "!")) { + rdr->dnot = 1; + w = next_word(&l); + } + rdr->daddr = next_addr(&w); + if (!*w) + rdr->dmask = 0xFFFFFFFF; + else if (*w == '/') + rdr->dmask = rule_mask(next_number(&w)); + else { + error(n, "expected /, get '%c'\n", *w); + return (0); + } + w = next_word(&l); + } - /* external port */ + /* external port (range) */ if (strcmp(w, "port")) { error(n, "expected port, got %s\n", w); return (0); @@ -1097,7 +1214,6 @@ parse_rdr(int n, char *l, struct pf_rdr *rdr) rdr->dport2 = htons(next_number(&s)); rdr->opts |= PF_DPORT_RANGE; } - w = next_word(&l); /* -> */ diff --git a/sys/net/pf.c b/sys/net/pf.c index 9313f50dd85..8e4f35cf0e1 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.106 2001/07/07 01:56:09 marc Exp $ */ +/* $OpenBSD: pf.c,v 1.107 2001/07/09 10:30:57 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -176,9 +176,10 @@ int pf_match_addr(u_int8_t, u_int32_t, u_int32_t, int pf_match_port(u_int8_t, u_int16_t, u_int16_t, u_int16_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); +struct pf_nat *pf_get_nat(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_int16_t); + u_int32_t, u_int16_t); int pf_test_tcp(int, struct ifnet *, struct mbuf *, int, int, struct ip *, struct tcphdr *); int pf_test_udp(int, struct ifnet *, struct mbuf *, @@ -797,7 +798,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - } + } else + rule->ifp = NULL; TAILQ_INSERT_TAIL(pf_rules_inactive, rule, entries); break; } @@ -898,12 +900,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pn->nat, nat, sizeof(struct pf_nat)); - nat->ifp = ifunit(nat->ifname); - if (nat->ifp == NULL) { - pool_put(&pf_nat_pl, nat); - error = EINVAL; - break; - } + if (nat->ifname[0]) { + nat->ifp = ifunit(nat->ifname); + if (nat->ifp == NULL) { + pool_put(&pf_nat_pl, nat); + error = EINVAL; + break; + } + } else + nat->ifp = NULL; TAILQ_INSERT_TAIL(pf_nats_inactive, nat, entries); break; } @@ -999,12 +1004,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pr->rdr, rdr, sizeof(struct pf_rdr)); - rdr->ifp = ifunit(rdr->ifname); - if (rdr->ifp == NULL) { - pool_put(&pf_rdr_pl, rdr); - error = EINVAL; - break; - } + if (rdr->ifname[0]) { + rdr->ifp = ifunit(rdr->ifname); + if (rdr->ifp == NULL) { + pool_put(&pf_rdr_pl, rdr); + error = EINVAL; + break; + } + } else + rdr->ifp = NULL; TAILQ_INSERT_TAIL(pf_rdrs_inactive, rdr, entries); break; } @@ -1389,16 +1397,17 @@ pf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p) } struct pf_nat * -pf_get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t addr) +pf_get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr) { struct pf_nat *n, *nm = NULL; n = TAILQ_FIRST(pf_nats_active); while (n && nm == NULL) { - if (((n->ifp == ifp && !n->ifnot) || + if (((n->ifp == NULL) || (n->ifp == ifp && !n->ifnot) || (n->ifp != ifp && n->ifnot)) && (!n->proto || n->proto == proto) && - pf_match_addr(n->not, n->saddr, n->smask, addr)) + pf_match_addr(n->snot, n->saddr, n->smask, saddr) && + pf_match_addr(n->dnot, n->daddr, n->dmask, daddr)) nm = n; else n = TAILQ_NEXT(n, entries); @@ -1407,18 +1416,20 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t addr) } struct pf_rdr * -pf_get_rdr(struct ifnet *ifp, u_int8_t proto, u_int32_t addr, u_int16_t port) +pf_get_rdr(struct ifnet *ifp, u_int8_t proto, u_int32_t saddr, u_int32_t daddr, + u_int16_t dport) { struct pf_rdr *r, *rm = NULL; r = TAILQ_FIRST(pf_rdrs_active); while (r && rm == NULL) { - if (((r->ifp == ifp && !r->ifnot) || + if (((r->ifp == NULL) || (r->ifp == ifp && !r->ifnot) || (r->ifp != ifp && r->ifnot)) && (!r->proto || r->proto == proto) && - pf_match_addr(r->not, r->daddr, r->dmask, addr) && - (ntohs(port) >= ntohs(r->dport)) && - (ntohs(port) <= ntohs(r->dport2))) + pf_match_addr(r->snot, r->saddr, r->smask, saddr) && + pf_match_addr(r->dnot, r->daddr, r->dmask, daddr) && + (ntohs(dport) >= ntohs(r->dport)) && + (ntohs(dport) <= ntohs(r->dport2))) rm = r; else r = TAILQ_NEXT(r, entries); @@ -1467,18 +1478,18 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, if (direction == PF_OUT) { /* check outgoing packet for NAT */ if ((nat = pf_get_nat(ifp, IPPROTO_TCP, - h->ip_src.s_addr)) != NULL) { + 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, nat->daddr, + &h->ip_sum, &th->th_sum, nat->raddr, htons(pf_next_port_tcp)); rewrite++; } } else { /* check incoming packet for RDR */ - if ((rdr = pf_get_rdr(ifp, IPPROTO_TCP, h->ip_dst.s_addr, - th->th_dport)) != NULL) { + if ((rdr = pf_get_rdr(ifp, IPPROTO_TCP, h->ip_src.s_addr, + h->ip_dst.s_addr, th->th_dport)) != NULL) { baddr = h->ip_dst.s_addr; bport = th->th_dport; if (rdr->opts & PF_RPORT_RANGE) @@ -1621,19 +1632,19 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, if (direction == PF_OUT) { /* check outgoing packet for NAT */ - if ((nat = pf_get_nat(ifp, IPPROTO_UDP, h->ip_src.s_addr)) != - NULL) { + 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; pf_change_ap(&h->ip_src.s_addr, &uh->uh_sport, - &h->ip_sum, &uh->uh_sum, nat->daddr, + &h->ip_sum, &uh->uh_sum, nat->raddr, htons(pf_next_port_udp)); rewrite++; } } else { /* check incoming packet for RDR */ - if ((rdr = pf_get_rdr(ifp, IPPROTO_UDP, h->ip_dst.s_addr, - uh->uh_dport)) != NULL) { + if ((rdr = pf_get_rdr(ifp, IPPROTO_UDP, h->ip_src.s_addr, + h->ip_dst.s_addr, uh->uh_dport)) != NULL) { baddr = h->ip_dst.s_addr; bport = uh->uh_dport; if (rdr->opts & PF_RPORT_RANGE) @@ -1764,10 +1775,10 @@ pf_test_icmp(int direction, struct ifnet *ifp, struct mbuf *m, if (direction == PF_OUT) { /* check outgoing packet for NAT */ - if ((nat = pf_get_nat(ifp, IPPROTO_ICMP, h->ip_src.s_addr)) != - NULL) { + 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->daddr); + pf_change_a(&h->ip_src.s_addr, &h->ip_sum, nat->raddr); } } diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index b451207ff13..a7176ed8141 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.31 2001/07/06 21:19:56 chris Exp $ */ +/* $OpenBSD: pfvar.h,v 1.32 2001/07/09 10:30:56 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -124,8 +124,11 @@ struct pf_nat { u_int32_t saddr; u_int32_t smask; u_int32_t daddr; + u_int32_t dmask; + u_int32_t raddr; u_int8_t proto; - u_int8_t not; + u_int8_t snot; + u_int8_t dnot; u_int8_t ifnot; }; @@ -133,6 +136,8 @@ struct pf_rdr { char ifname[IFNAMSIZ]; struct ifnet *ifp; TAILQ_ENTRY(pf_rdr) entries; + u_int32_t saddr; + u_int32_t smask; u_int32_t daddr; u_int32_t dmask; u_int32_t raddr; @@ -140,7 +145,8 @@ struct pf_rdr { u_int16_t dport2; u_int16_t rport; u_int8_t proto; - u_int8_t not; + u_int8_t snot; + u_int8_t dnot; u_int8_t ifnot; u_int8_t opts; }; -- cgit v1.2.3