Date: Wed, 17 Feb 2021 18:19:31 GMT From: Neel Chauhan <nc@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: ab65c43e2620 - stable/12 - Allow setting alias port ranges in libalias and ipfw. Message-ID: <202102171819.11HIJVhn071965@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by nc (ports committer): URL: https://cgit.FreeBSD.org/src/commit/?id=ab65c43e2620722bc3232590f74d2e015d8b6e25 commit ab65c43e2620722bc3232590f74d2e015d8b6e25 Author: Neel Chauhan <nc@FreeBSD.org> AuthorDate: 2021-02-02 21:24:17 +0000 Commit: Neel Chauhan <nc@FreeBSD.org> CommitDate: 2021-02-17 18:19:02 +0000 Allow setting alias port ranges in libalias and ipfw. This will allow a system to be a true RFC 6598 NAT444 setup, where each network segment (e.g. user, subnet) can have their own dedicated port aliasing ranges. Reviewed by: donner, kp Approved by: 0mp (mentor), donner, kp Differential Revision: https://reviews.freebsd.org/D23450 (cherry picked from commit a08cdb6cfb1c84b80b5337d46c574b55d0e15c63) --- sbin/ipfw/ipfw.8 | 3 +++ sbin/ipfw/ipfw2.h | 1 + sbin/ipfw/main.c | 3 ++- sbin/ipfw/nat.c | 41 ++++++++++++++++++++++++++++++++++++++ sys/netinet/ip_fw.h | 2 ++ sys/netinet/libalias/alias.h | 1 + sys/netinet/libalias/alias_db.c | 29 ++++++++++++++++++++++++--- sys/netinet/libalias/alias_local.h | 4 ++++ sys/netpfil/ipfw/ip_fw_nat.c | 7 +++++++ 9 files changed, 87 insertions(+), 4 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index e77930355094..d2c4885bc119 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -3271,6 +3271,9 @@ Reverse the way libalias handles aliasing. Obey transparent proxy rules only, packet aliasing is not performed. .It Cm skip_global Skip instance in case of global state lookup (see below). +.It Cm port_range Ar lower-upper +Set the aliasing ports between the ranges given. Upper port has to be greater +than lower. .El .Pp Some specials value can be supplied instead of diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 764e5176e8ef..42e4f4777792 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -285,6 +285,7 @@ enum tokens { TOK_STATES_CHUNKS, TOK_JMAXLEN, TOK_PORT_RANGE, + TOK_PORT_ALIAS, TOK_HOST_DEL_AGE, TOK_PG_DEL_AGE, TOK_TCP_SYN_AGE, diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c index dc55d0bfa416..89f21062811c 100644 --- a/sbin/ipfw/main.c +++ b/sbin/ipfw/main.c @@ -45,7 +45,8 @@ help(void) "[pipe|queue] {zero|delete|show} [N{,N}]\n" "nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|unreg_cgn|\n" " reset|reverse|proxy_only|redirect_addr linkspec|\n" -" redirect_port linkspec|redirect_proto linkspec}\n" +" redirect_port linkspec|redirect_proto linkspec|\n" +" port_range lower-upper}\n" "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" "set N {show|list|zero|resetlog|delete} [N{,N}] | flush\n" "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" diff --git a/sbin/ipfw/nat.c b/sbin/ipfw/nat.c index bbf5be666ea0..1076e1038b8a 100644 --- a/sbin/ipfw/nat.c +++ b/sbin/ipfw/nat.c @@ -65,6 +65,7 @@ static struct _s_x nat_params[] = { { "reset", TOK_RESET_ADDR }, { "reverse", TOK_ALIAS_REV }, { "proxy_only", TOK_PROXY_ONLY }, + { "port_range", TOK_PORT_ALIAS }, { "redirect_addr", TOK_REDIR_ADDR }, { "redirect_port", TOK_REDIR_PORT }, { "redirect_proto", TOK_REDIR_PROTO }, @@ -753,12 +754,35 @@ nat_show_cfg(struct nat44_cfg_nat *n, void *arg __unused) printf("\n"); } +static int +nat_port_alias_parse(char *str, u_short *lpout, u_short *hpout) { + long lp, hp; + char *ptr; + /* Lower port parsing */ + lp = (long) strtol(str, &ptr, 10); + if (lp < 1024 || lp > 65535) + return 0; + if (!ptr || *ptr != '-') + return 0; + /* Upper port parsing */ + hp = (long) strtol(ptr, &ptr, 10); + if (hp < 1024 || hp > 65535) + return 0; + if (ptr) + return 0; + + *lpout = (u_short) lp; + *hpout = (u_short) hp; + return 1; +} + void ipfw_config_nat(int ac, char **av) { ipfw_obj_header *oh; struct nat44_cfg_nat *n; /* Nat instance configuration. */ int i, off, tok, ac1; + u_short lp, hp; char *id, *buf, **av1, *end; size_t len; @@ -786,6 +810,7 @@ ipfw_config_nat(int ac, char **av) switch (tok) { case TOK_IP: case TOK_IF: + case TOK_PORT_ALIAS: ac1--; av1++; break; @@ -925,8 +950,24 @@ ipfw_config_nat(int ac, char **av) n->redir_cnt++; off += i; break; + case TOK_PORT_ALIAS: + if (ac == 0) + errx(EX_DATAERR, "missing option"); + if (!nat_port_alias_parse(av[0], &lp, &hp)) + errx(EX_DATAERR, + "You need a range of port(s) from 1024 <= x < 65536"); + if (lp >= hp) + errx(EX_DATAERR, + "Upper port has to be greater than lower port"); + n->alias_port_lo = lp; + n->alias_port_hi = hp; + ac--; + av++; + break; } } + if (n->mode & PKT_ALIAS_SAME_PORTS && n->alias_port_lo) + errx(EX_DATAERR, "same_ports and port_range cannot both be selected"); i = do_set3(IP_FW_NAT44_XCONFIG, &oh->opheader, len); if (i != 0) diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 7a01c82ba58b..8b6055e64a6d 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -550,6 +550,8 @@ struct nat44_cfg_nat { struct in_addr ip; /* nat IPv4 address */ uint32_t mode; /* aliasing mode */ uint32_t redir_cnt; /* number of entry in spool chain */ + u_short alias_port_lo; /* low range for port aliasing */ + u_short alias_port_hi; /* high range for port aliasing */ }; /* Nat command. */ diff --git a/sys/netinet/libalias/alias.h b/sys/netinet/libalias/alias.h index 41cd7b2c23d1..c252c823ced8 100644 --- a/sys/netinet/libalias/alias.h +++ b/sys/netinet/libalias/alias.h @@ -86,6 +86,7 @@ struct alias_link; /* Initialization and control functions. */ struct libalias *LibAliasInit(struct libalias *); void LibAliasSetAddress(struct libalias *, struct in_addr _addr); +void LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, u_short port_hi); void LibAliasSetFWBase(struct libalias *, unsigned int _base, unsigned int _num); void LibAliasSetSkinnyPort(struct libalias *, unsigned int _port); unsigned int diff --git a/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c index cf85f40161e7..b3792c748c56 100644 --- a/sys/netinet/libalias/alias_db.c +++ b/sys/netinet/libalias/alias_db.c @@ -605,6 +605,11 @@ GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) */ port_net = lnk->src_port; port_sys = ntohs(port_net); + } else if (la->aliasPortLower) { + /* First trial is a random port in the aliasing range. */ + port_sys = la->aliasPortLower + + (arc4random() % la->aliasPortLength); + port_net = htons(port_sys); } else { /* First trial and all subsequent are random. */ port_sys = arc4random() & ALIAS_PORT_MASK; @@ -658,9 +663,15 @@ GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) } #endif } - port_sys = arc4random() & ALIAS_PORT_MASK; - port_sys += ALIAS_PORT_BASE; - port_net = htons(port_sys); + if (la->aliasPortLower) { + port_sys = la->aliasPortLower + + (arc4random() % la->aliasPortLength); + port_net = htons(port_sys); + } else { + port_sys = arc4random() & ALIAS_PORT_MASK; + port_sys += ALIAS_PORT_BASE; + port_net = htons(port_sys); + } } #ifdef LIBALIAS_DEBUG @@ -2447,6 +2458,18 @@ LibAliasSetAddress(struct libalias *la, struct in_addr addr) } +void +LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, + u_short port_high) +{ + + LIBALIAS_LOCK(la); + la->aliasPortLower = port_low; + /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */ + la->aliasPortLength = port_high - port_low + 1; + LIBALIAS_UNLOCK(la); +} + void LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) { diff --git a/sys/netinet/libalias/alias_local.h b/sys/netinet/libalias/alias_local.h index c29294256413..94eb26978658 100644 --- a/sys/netinet/libalias/alias_local.h +++ b/sys/netinet/libalias/alias_local.h @@ -163,6 +163,10 @@ struct libalias { struct in_addr true_addr; /* in network byte order. */ u_short true_port; /* in host byte order. */ + /* Port ranges for aliasing. */ + u_short aliasPortLower; + u_short aliasPortLength; + /* * sctp code support */ diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c index 1c445f72aee9..9e15e9addbe5 100644 --- a/sys/netpfil/ipfw/ip_fw_nat.c +++ b/sys/netpfil/ipfw/ip_fw_nat.c @@ -94,6 +94,8 @@ struct cfg_nat { /* chain of redir instances */ LIST_HEAD(redir_chain, cfg_redir) redir_chain; char if_name[IF_NAMESIZE]; /* interface name */ + u_short alias_port_lo; /* low range for port aliasing */ + u_short alias_port_hi; /* high range for port aliasing */ }; static eventhandler_tag ifaddr_event_tag; @@ -527,9 +529,12 @@ nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg) ptr->ip = ucfg->ip; ptr->redir_cnt = ucfg->redir_cnt; ptr->mode = ucfg->mode; + ptr->alias_port_lo = ucfg->alias_port_lo; + ptr->alias_port_hi = ucfg->alias_port_hi; strlcpy(ptr->if_name, ucfg->if_name, sizeof(ptr->if_name)); LibAliasSetMode(ptr->lib, ptr->mode, ~0); LibAliasSetAddress(ptr->lib, ptr->ip); + LibAliasSetAliasPortRange(ptr->lib, ptr->alias_port_lo, ptr->alias_port_hi); /* * Redir and LSNAT configuration. @@ -657,6 +662,8 @@ export_nat_cfg(struct cfg_nat *ptr, struct nat44_cfg_nat *ucfg) ucfg->ip = ptr->ip; ucfg->redir_cnt = ptr->redir_cnt; ucfg->mode = ptr->mode; + ucfg->alias_port_lo = ptr->alias_port_lo; + ucfg->alias_port_hi = ptr->alias_port_hi; strlcpy(ucfg->if_name, ptr->if_name, sizeof(ucfg->if_name)); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102171819.11HIJVhn071965>