On Thu, Mar 3, 2011 at 12:00 AM, Bjoern A. Zeeb <bzeeb-li...@lists.zabbadoz.net> wrote: > On Sat, 5 Feb 2011, Giorgos Keramidas wrote: > > Hi, > >> On Fri, 28 Jan 2011 11:00:40 -0800, Doug Barton <do...@freebsd.org> wrote: >>> >>> I haven't reviewed the patch in detail yet but I wanted to first thank >>> you for taking on this work, and being so responsive to Fernando's >>> request (which I agreed with, and you updated before I even had a >>> chance to say so). :) >> >> Thanks from me too. >> >>> My one comment so far is on the name of the sysctl's. There are 2 >>> problems with sysctl/variable names that use an rfc title. The first is >>> that they are not very descriptive to the 99.9% of users who are not >>> familiar with that particular doc. The second is more esoteric, but if >>> the rfc is subsequently updated or obsoleted we're stuck with either an >>> anachronism or updating code (both of which have their potential areas >>> of confusion). >>> >>> So in order to avoid this issue, and make it more consistent with the >>> existing: >>> >>> net.inet.ip.portrange.randomtime >>> net.inet.ip.portrange.randomcps >>> net.inet.ip.portrange.randomized >>> >>> How does net.inet.ip.portrange.randomalg sound? I would also suggest >>> that the second sysctl be named >>> net.inet.ip.portrange.randomalg.alg5_tradeoff so that one could do >>> sysctl net.inet.ip.portrange.randomalg' and see both values. But I won't >>> quibble on that. :) >> >> It's a usability issue too, so I'd certainly support renaming the >> sysctls to something human-friendly. It's always bad enough to go >> through look at a search engine to find out what net.inet.rfc1234 >> means. It's worse when RFC 1234 has been obsoleted a few years ago >> and now it's called RFC 54321. > > has anything of that ever happened and led to an updated patch again?
Yes. Those recommendations are reflected in the latest version of the patch I supplied. I attach it again for reference. It is against RELENG-8 as of 2011-01-31. However, if you need -CURRENT-based patch, please let me know, so I can prepare it asap. > /bz > > -- > Bjoern A. Zeeb You have to have visions! > Stop bit received. Insert coin for new address family. > _______________________________________________ > freebsd-net@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-net > To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org" >
diff -r 0d67f9c982f7 src/sys/netinet/in_pcb.c --- a/src/sys/netinet/in_pcb.c Mon Jan 31 11:35:24 2011 +0200 +++ b/src/sys/netinet/in_pcb.c Mon Jan 31 14:29:52 2011 +0200 @@ -81,6 +81,8 @@ #include <netipsec/key.h> #endif /* IPSEC */ +#include <sys/md5.h> + #include <security/mac/mac_framework.h> /* @@ -109,6 +111,8 @@ VNET_DEFINE(int, ipport_stoprandom); /* toggled by ipport_tick */ VNET_DEFINE(int, ipport_tcpallocs); static VNET_DEFINE(int, ipport_tcplastcount); +VNET_DEFINE(u_int, ipport_randomalg_ver) = 1; /* user controlled via sysctl */ +VNET_DEFINE(u_int, ipport_randomalg_alg5_tradeoff) = 500; /* user controlled via sysctl */ #define V_ipport_tcplastcount VNET(ipport_tcplastcount) @@ -141,7 +145,68 @@ #undef RANGECHK +/* + * Updates V_ipport_randomalg_ver to the provided value + * and ensures it is in the supported range (1 - 5) + */ +static int +sysctl_net_randomalg_version_check(SYSCTL_HANDLER_ARGS) +{ + u_int algorithm = *(u_int *)arg1; + int error; + +#ifdef VIMAGE + error = vnet_sysctl_handle_uint(oidp, &algorithm, 0, req); +#else + error = sysctl_handle_int(oidp, &algorithm, 0, req); +#endif + + if (error == 0) { + switch (algorithm) { + case INP_RFC6056_ALG_1: + case INP_RFC6056_ALG_2: + case INP_RFC6056_ALG_3: + case INP_RFC6056_ALG_4: + case INP_RFC6056_ALG_5: + V_ipport_randomalg_ver = algorithm; + break; + default: + return (EINVAL); + } + } + + return (error); +} + +/* + * Updates V_ipport_randomalg_alg5_tradeoff to provided value + * and ensures it is in the supported range (1 - 65536) + */ +static int +sysctl_net_randomalg_alg5_tradeoff_check(SYSCTL_HANDLER_ARGS) +{ + u_int tradeoff = *(u_int *)arg1; + int error; + +#ifdef VIMAGE + error = vnet_sysctl_handle_uint(oidp, &tradeoff, 0, req); +#else + error = sysctl_handle_int(oidp, &tradeoff, 0, req); +#endif + + if (error == 0) { + if (tradeoff < 1 || tradeoff > 65536) + return (EINVAL); + else + V_ipport_randomalg_alg5_tradeoff = tradeoff; + } + + return (error); +} + SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports"); +SYSCTL_NODE(_net_inet_ip_portrange, IPPROTO_IP, randomalg, CTLFLAG_RW, 0, + "Port Randomization Algorithms"); SYSCTL_VNET_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW, &VNET_NAME(ipport_lowfirstauto), 0, @@ -174,6 +239,15 @@ &VNET_NAME(ipport_randomtime), 0, "Minimum time to keep sequental port " "allocation before switching to a random one"); +SYSCTL_VNET_PROC(_net_inet_ip_portrange_randomalg, OID_AUTO, version, + CTLTYPE_UINT|CTLFLAG_RW, &VNET_NAME(ipport_randomalg_ver), 0, + &sysctl_net_randomalg_version_check, "IU", + "RFC 6056 Port randomization algorithm"); +SYSCTL_VNET_PROC(_net_inet_ip_portrange_randomalg, OID_AUTO, + alg5_tradeoff, CTLTYPE_UINT|CTLFLAG_RW, + &VNET_NAME(ipport_randomalg_alg5_tradeoff), 0, + &sysctl_net_randomalg_alg5_tradeoff_check, "IU", + "RFC 6056 Algorithm 5 computational trade-off"); /* * in_pcb.c: manage the Protocol Control Blocks. @@ -468,21 +542,177 @@ last = aux; } - if (dorandom) - *lastport = first + - (arc4random() % (last - first)); - count = last - first; - do { - if (count-- < 0) /* completely used? */ - return (EADDRNOTAVAIL); - ++*lastport; - if (*lastport < first || *lastport > last) - *lastport = first; - lport = htons(*lastport); - } while (in_pcblookup_local(pcbinfo, laddr, - lport, wild, cred)); + /* + * According to RFC 6056 there are 5 (five) possible algorithms + * for random port allocation. Usage of a particular algorithm + * is specified with the 'net.inet.ip.portrange.randomalg.version' + * sysctl variable. Default value is 1, which represents the + * legacy random port allocation algorithm in FreeBSD. + */ + if (dorandom) { + switch (V_ipport_randomalg_ver) { + case INP_RFC6056_ALG_5: /* Random-Increments Port Selection */ + do { + if (count-- < 0) /* completely used? */ + return (EADDRNOTAVAIL); + + *lastport = first + ((arc4random() % 65536) + + (arc4random() % V_ipport_randomalg_alg5_tradeoff) + 1); + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup_local(pcbinfo, laddr, + lport, wild, cred)); + break; + case INP_RFC6056_ALG_4: /* Double-Hash Port Selection Algorithm */ + { + MD5_CTX f_ctx; + MD5_CTX g_ctx; + u_int32_t F[4] = { 0, 0, 0, 0 }; + u_int32_t G[4] = { 0, 0, 0, 0 }; + u_int32_t secret_f[4] = { 0, 0, 0, 0 }; + u_int32_t secret_g[4] = { 0, 0, 0, 0 }; + u_int16_t table[16]; + u_int32_t index = 0; + u_int32_t offset = 0; + + secret_f[0] = arc4random(); + secret_f[1] = arc4random(); + secret_f[2] = arc4random(); + secret_f[3] = arc4random(); + + secret_g[0] = arc4random(); + secret_g[1] = arc4random(); + secret_g[2] = arc4random(); + secret_g[3] = arc4random(); + + for (index = 0; index < sizeof(table); index++) + table[index] = arc4random() % 65536; + + MD5Init(&f_ctx); + MD5Update(&f_ctx, (u_char *)&inp->inp_laddr, + sizeof(inp->inp_laddr)); + MD5Update(&f_ctx, (u_char *)&inp->inp_faddr, + sizeof(inp->inp_faddr)); + MD5Update(&f_ctx, (u_char *)&inp->inp_fport, + sizeof(inp->inp_fport)); + MD5Update(&f_ctx, (u_char *)secret_f, + sizeof(secret_f)); + MD5Final((u_char *)&F, &f_ctx); + + offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3])); + + MD5Init(&g_ctx); + MD5Update(&g_ctx, (u_char *)&inp->inp_laddr, + sizeof(inp->inp_laddr)); + MD5Update(&g_ctx, (u_char *)&inp->inp_faddr, + sizeof(inp->inp_faddr)); + MD5Update(&g_ctx, (u_char *)&inp->inp_fport, + sizeof(inp->inp_fport)); + MD5Update(&g_ctx, (u_char *)secret_g, + sizeof(secret_g)); + MD5Final((u_char *)&G, &g_ctx); + + index = ((G[0] ^ G[1]) ^ (G[2] ^ G[3])) % sizeof(table); + + do { + if (count-- < 0) /* completely used? */ + return (EADDRNOTAVAIL); + + *lastport = first + + (offset + table[index]++) % count; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup_local(pcbinfo, laddr, + lport, wild, cred)); + } + break; + case INP_RFC6056_ALG_3: /* Simple Hash-Based Port Selection Algorithm */ + { + MD5_CTX f_ctx; + u_int32_t F[4] = { 0, 0, 0, 0 }; + u_int32_t secret_f[4] = { 0, 0, 0, 0 }; + u_int32_t offset = 0; + + secret_f[0] = arc4random(); + secret_f[1] = arc4random(); + secret_f[2] = arc4random(); + secret_f[3] = arc4random(); + + MD5Init(&f_ctx); + MD5Update(&f_ctx, (u_char *)&inp->inp_laddr, + sizeof(inp->inp_laddr)); + MD5Update(&f_ctx, (u_char *)&inp->inp_faddr, + sizeof(inp->inp_faddr)); + MD5Update(&f_ctx, (u_char *)&inp->inp_fport, + sizeof(inp->inp_fport)); + MD5Update(&f_ctx, (u_char *)secret_f, + sizeof(secret_f)); + MD5Final((u_char *)&F, &f_ctx); + + offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3])); + + do { + if (count-- < 0) /* completely used? */ + return (EADDRNOTAVAIL); + + *lastport = first + ((arc4random() % 65536) + + (offset % 65536)) % count; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup_local(pcbinfo, laddr, + lport, wild, cred)); + } + break; + case INP_RFC6056_ALG_2: /* Simple Port Randomization Algorithm II */ + do { + if (count-- < 0) /* completely used? */ + return (EADDRNOTAVAIL); + + *lastport = first + (arc4random() % (last - first)); + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup_local(pcbinfo, laddr, + lport, wild, cred)); + break; + case INP_RFC6056_ALG_1: /* Simple Port Randomization Algorithm I */ + default: + *lastport = first + (arc4random() % (last - first)); + + do { + if (count-- < 0) /* completely used? */ + return (EADDRNOTAVAIL); + + ++*lastport; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup_local(pcbinfo, laddr, + lport, wild, cred)); + } + } else { + do { + if (count-- < 0) /* completely used? */ + return (EADDRNOTAVAIL); + + ++*lastport; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup_local(pcbinfo, laddr, + lport, wild, cred)); + } } *laddrp = laddr.s_addr; *lportp = lport; diff -r 0d67f9c982f7 src/sys/netinet/in_pcb.h --- a/src/sys/netinet/in_pcb.h Mon Jan 31 11:35:24 2011 +0200 +++ b/src/sys/netinet/in_pcb.h Mon Jan 31 14:29:52 2011 +0200 @@ -452,6 +452,15 @@ #define INP_CHECK_SOCKAF(so, af) (INP_SOCKAF(so) == af) +/* + * RFC6056 Port Randomization Algorithms + */ +#define INP_RFC6056_ALG_1 1 /* Simple Port Randomization Algorithm I */ +#define INP_RFC6056_ALG_2 2 /* Simple Port Randomization Algorithm II */ +#define INP_RFC6056_ALG_3 3 /* Simple Hash-Based Port Selection Algorithm */ +#define INP_RFC6056_ALG_4 4 /* Double-Hash Port Selection Algorithm */ +#define INP_RFC6056_ALG_5 5 /* Random-Increments Port Selection Algorithm */ + #ifdef _KERNEL VNET_DECLARE(int, ipport_reservedhigh); VNET_DECLARE(int, ipport_reservedlow); @@ -466,6 +475,8 @@ VNET_DECLARE(int, ipport_randomtime); VNET_DECLARE(int, ipport_stoprandom); VNET_DECLARE(int, ipport_tcpallocs); +VNET_DECLARE(u_int, ipport_randomalg_ver); +VNET_DECLARE(u_int, ipport_randomalg_alg5_tradeoff); #define V_ipport_reservedhigh VNET(ipport_reservedhigh) #define V_ipport_reservedlow VNET(ipport_reservedlow) @@ -480,6 +491,8 @@ #define V_ipport_randomtime VNET(ipport_randomtime) #define V_ipport_stoprandom VNET(ipport_stoprandom) #define V_ipport_tcpallocs VNET(ipport_tcpallocs) +#define V_ipport_randomalg_ver VNET(ipport_randomalg_ver) +#define V_ipport_randomalg_alg5_tradeoff VNET(ipport_randomalg_alg5_tradeoff) extern struct callout ipport_tick_callout; diff -r 0d67f9c982f7 src/sys/netinet6/in6_src.c --- a/src/sys/netinet6/in6_src.c Mon Jan 31 11:35:24 2011 +0200 +++ b/src/sys/netinet6/in6_src.c Mon Jan 31 14:29:52 2011 +0200 @@ -108,6 +108,8 @@ #include <netinet6/scope6_var.h> #include <netinet6/nd6.h> +#include <sys/md5.h> + static struct mtx addrsel_lock; #define ADDRSEL_LOCK_INIT() mtx_init(&addrsel_lock, "addrsel_lock", NULL, MTX_DEF) #define ADDRSEL_LOCK() mtx_lock(&addrsel_lock) @@ -919,23 +921,195 @@ last = aux; } - if (dorandom) - *lastport = first + (arc4random() % (last - first)); - count = last - first; - do { - if (count-- < 0) { /* completely used? */ - /* Undo an address bind that may have occurred. */ - inp->in6p_laddr = in6addr_any; - return (EADDRNOTAVAIL); + /* + * According to RFC 6056 there are 5 (five) possible algorithms + * for random port allocation. Usage of a particular algorithm + * is specified with the 'net.inet.ip.portrange.randomalg.version' + * sysctl variable. Default value is 1, which represents the + * legacy random port allocation algorithm in FreeBSD. + */ + if (dorandom) { + switch (V_ipport_randomalg_ver) { + case INP_RFC6056_ALG_5: /* Random-Increments Port Selection */ + do { + if (count-- < 0) { /* completely used? */ + /* Undo an address bind that may have occurred. */ + inp->in6p_laddr = in6addr_any; + return (EADDRNOTAVAIL); + } + + *lastport = first + ((arc4random() % 65536) + + (arc4random() % V_ipport_randomalg_alg5_tradeoff) + 1); + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, + lport, wild, cred)); + break; + case INP_RFC6056_ALG_4: /* Double-Hash Port Selection Algorithm */ + { + MD5_CTX f_ctx; + MD5_CTX g_ctx; + u_int32_t F[4] = { 0, 0, 0, 0 }; + u_int32_t G[4] = { 0, 0, 0, 0 }; + u_int32_t secret_f[4] = { 0, 0, 0, 0 }; + u_int32_t secret_g[4] = { 0, 0, 0, 0 }; + u_int16_t table[16]; + u_int32_t index = 0; + u_int32_t offset = 0; + + secret_f[0] = arc4random(); + secret_f[1] = arc4random(); + secret_f[2] = arc4random(); + secret_f[3] = arc4random(); + + secret_g[0] = arc4random(); + secret_g[1] = arc4random(); + secret_g[2] = arc4random(); + secret_g[3] = arc4random(); + + for (index = 0; index < sizeof(table); index++) + table[index] = arc4random() % 65536; + + MD5Init(&f_ctx); + MD5Update(&f_ctx, (u_char *)&inp->in6p_laddr, + sizeof(inp->in6p_laddr)); + MD5Update(&f_ctx, (u_char *)&inp->in6p_faddr, + sizeof(inp->in6p_faddr)); + MD5Update(&f_ctx, (u_char *)&inp->inp_fport, + sizeof(inp->inp_fport)); + MD5Update(&f_ctx, (u_char *)secret_f, + sizeof(secret_f)); + MD5Final((u_char *)&F, &f_ctx); + + offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3])); + + MD5Init(&g_ctx); + MD5Update(&g_ctx, (u_char *)&inp->in6p_laddr, + sizeof(inp->in6p_laddr)); + MD5Update(&g_ctx, (u_char *)&inp->in6p_faddr, + sizeof(inp->in6p_faddr)); + MD5Update(&g_ctx, (u_char *)&inp->inp_fport, + sizeof(inp->inp_fport)); + MD5Update(&g_ctx, (u_char *)secret_g, + sizeof(secret_g)); + MD5Final((u_char *)&G, &g_ctx); + + index = ((G[0] ^ G[1]) ^ (G[2] ^ G[3])) % sizeof(table); + + do { + if (count-- < 0) { /* completely used? */ + /* Undo an address bind that may have occurred. */ + inp->in6p_laddr = in6addr_any; + return (EADDRNOTAVAIL); + } + + *lastport = first + + (offset + table[index]++) % count; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, + lport, wild, cred)); + } + break; + case INP_RFC6056_ALG_3: /* Simple Hash-Based Port Selection Algorithm */ + { + MD5_CTX f_ctx; + u_int32_t F[4] = { 0, 0, 0, 0 }; + u_int32_t secret_f[4] = { 0, 0, 0, 0 }; + u_int32_t offset = 0; + + secret_f[0] = arc4random(); + secret_f[1] = arc4random(); + secret_f[2] = arc4random(); + secret_f[3] = arc4random(); + + MD5Init(&f_ctx); + MD5Update(&f_ctx, (u_char *)&inp->in6p_laddr, + sizeof(inp->in6p_laddr)); + MD5Update(&f_ctx, (u_char *)&inp->in6p_faddr, + sizeof(inp->in6p_faddr)); + MD5Update(&f_ctx, (u_char *)&inp->inp_fport, + sizeof(inp->inp_fport)); + MD5Update(&f_ctx, (u_char *)secret_f, + sizeof(secret_f)); + MD5Final((u_char *)&F, &f_ctx); + + offset = ((F[0] ^ F[1]) ^ (F[2] ^ F[3])); + + do { + if (count-- < 0) { /* completely used? */ + /* Undo an address bind that may have occurred. */ + inp->in6p_laddr = in6addr_any; + return (EADDRNOTAVAIL); + } + + *lastport = first + ((arc4random() % 65536) + + (offset % 65536)) % count; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, + lport, wild, cred)); + } + break; + case INP_RFC6056_ALG_2: /* Simple Port Randomization Algorithm II */ + do { + if (count-- < 0) { /* completely used? */ + /* Undo an address bind that may have occurred. */ + inp->in6p_laddr = in6addr_any; + return (EADDRNOTAVAIL); + } + + *lastport = first + (arc4random() % (last - first)); + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, + lport, wild, cred)); + break; + case INP_RFC6056_ALG_1: /* Simple Port Randomization Algorithm I */ + default: + *lastport = first + (arc4random() % (last - first)); + + do { + if (count-- < 0) { /* completely used? */ + /* Undo an address bind that may have occurred. */ + inp->in6p_laddr = in6addr_any; + return (EADDRNOTAVAIL); + } + + ++*lastport; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, + lport, wild, cred)); } - ++*lastport; - if (*lastport < first || *lastport > last) - *lastport = first; - lport = htons(*lastport); - } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, - lport, wild, cred)); + } else { + do { + if (count-- < 0) { /* completely used? */ + /* Undo an address bind that may have occurred. */ + inp->in6p_laddr = in6addr_any; + return (EADDRNOTAVAIL); + } + + ++*lastport; + + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, + lport, wild, cred)); + } inp->inp_lport = lport; if (in_pcbinshash(inp) != 0) {
_______________________________________________ freebsd-net@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-net To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"