randomize source port

View: New views
8 Messages — Rating Filter:   Alert me  

randomize source port

by Jeremy C. Reed :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

As a quick test, I did the following:

--- in_pcb.c    5 May 2008 17:11:17 -0000       1.125
+++ in_pcb.c    11 Jul 2008 15:33:49 -0000
@@ -332,6 +332,8 @@
                        mymax = swp;
                }
 
+               *lastport = mymax - (arc4random() % (mymax - mymin));
+
                lport = *lastport - 1;
                for (cnt = mymax - mymin + 1; cnt; cnt--, lport--) {
                        if (lport < mymin || lport > mymax)


With default sysctl:

net.inet.ip.anonportmin = 49152
net.inet.ip.anonportmax = 65535

Using gethostbyname2(3), I did many lookups (some simultaneously) to one
of my local nameservers.

Before my patch, the source port counted down from 65026 to 64845.

After my patch, the source port, I didn't see any noticable sequence of
counting down, such as:

52362
59398
64223
51205
55882
...
50004
64005
64193
51223
53918

And the range of 49202 to 65491.


By the way, FreeBSD has these sysctl tunables:

net.inet.ip.portrange.randomized
        Enable random port allocation. (Default is on.)

net.inet.ip.portrange.randomcps
        Maximum number of random port allocations in last second
        before switching to a sequental one. (Default is 10.)

net.inet.ip.portrange.randomtime
  Minimum time to keep sequental port allocation (while randomcps
        is not reached) before switching back to a random one. (Default
        is 45 seconds.)


Re: randomize source port

by Steven M. Bellovin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, 11 Jul 2008 11:00:21 -0500 (CDT)
"Jeremy C. Reed" <reed@...> wrote:

> As a quick test, I did the following:
>
> --- in_pcb.c    5 May 2008 17:11:17 -0000       1.125
> +++ in_pcb.c    11 Jul 2008 15:33:49 -0000
> @@ -332,6 +332,8 @@
>                         mymax = swp;
>                 }
>  
> +               *lastport = mymax - (arc4random() % (mymax - mymin));
> +
>                 lport = *lastport - 1;
>                 for (cnt = mymax - mymin + 1; cnt; cnt--, lport--) {
>                         if (lport < mymin || lport > mymax)
>
>
How easy would it be to do a timing test?  For example, assume a simple
program that just counted how many UDP ports it could bind to in ten
seconds?  I expect some impact, but not a big one; arc4 is very cheap,
but measurement is always good.

More seriously -- when at boot time does urandom have enough entropy to
seed the PRNG?  I've had problems on some server systems with things
like that.


                --Steve Bellovin, http://www.cs.columbia.edu/~smb

Re: randomize source port

by Joerg Sonnenberger :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Jul 11, 2008 at 11:00:21AM -0500, Jeremy C. Reed wrote:
> As a quick test, I did the following:

I'm not sure if directly randomising the port is a good idea.
I think it should at least be a random shuffle for the same reason that
the TCP sequence numbers are not using a direct PRNG. Note that a random
shuffle also avoids most of the motivation for moving to a sequential
numbers, at least if short living connections are concerned.

Joerg

Re: randomize source port

by Steven M. Bellovin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, 11 Jul 2008 18:22:45 +0200
Joerg Sonnenberger <joerg@...> wrote:

> On Fri, Jul 11, 2008 at 11:00:21AM -0500, Jeremy C. Reed wrote:
> > As a quick test, I did the following:
>
> I'm not sure if directly randomising the port is a good idea.
> I think it should at least be a random shuffle for the same reason
> that the TCP sequence numbers are not using a direct PRNG.

I don't see the similarity.  For sequence numbers, there's a
requirement in the RFC for a 4 microsecond counter; there's also
analysis concerning defense against old packets lying around the
network.

The possible issue here is consecutive use of the same port number; I
don't think it's a real concern.

> Note that
> a random shuffle also avoids most of the motivation for moving to a
> sequential numbers, at least if short living connections are
> concerned.
>
I don't understand.



                --Steve Bellovin, http://www.cs.columbia.edu/~smb

Re: randomize source port

by Joerg Sonnenberger :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Jul 11, 2008 at 12:46:24PM -0400, Steven M. Bellovin wrote:

> On Fri, 11 Jul 2008 18:22:45 +0200
> Joerg Sonnenberger <joerg@...> wrote:
>
> > On Fri, Jul 11, 2008 at 11:00:21AM -0500, Jeremy C. Reed wrote:
> > > As a quick test, I did the following:
> >
> > I'm not sure if directly randomising the port is a good idea.
> > I think it should at least be a random shuffle for the same reason
> > that the TCP sequence numbers are not using a direct PRNG.
>
> I don't see the similarity.  For sequence numbers, there's a
> requirement in the RFC for a 4 microsecond counter; there's also
> analysis concerning defense against old packets lying around the
> network.

Reusing the port number early increases both the chance of a collission
with an existing port and the chance that you can still hit the query id
case (for the special case of DNS).

Joerg

Re: randomize source port

by Jeremy C. Reed :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

If anyone wants to test timing, the attached patch also allows you to
toggle via sysctl.

I tested by doing a loop of socket and connect and close 500000 times but
didn't notice anything yet. (In fact, I can't detect more than one source
port so probably done wrong. See second attachment.) I used time to time
it with net.inet.ip.randomport as 0 and 1.
Index: netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.83
diff -u -r1.83 in.h
--- netinet/in.h 25 Jan 2008 21:12:14 -0000 1.83
+++ netinet/in.h 11 Jul 2008 17:57:49 -0000
@@ -142,6 +142,7 @@
  */
 
 #define IPPORT_RESERVED 1024
+#define IPPORT_RANDOM 0 /* don't randomize by default */
 #define IPPORT_ANONMIN 49152
 #define IPPORT_ANONMAX 65535
 #define IPPORT_RESERVEDMIN 600
@@ -451,7 +452,8 @@
 #define IPCTL_RANDOMID       22 /* use random IP ids (if configured) */
 #define IPCTL_LOOPBACKCKSUM    23 /* do IP checksum on loopback */
 #define IPCTL_STATS 24 /* IP statistics */
-#define IPCTL_MAXID       25
+#define IPCTL_RANDOMPORT       25 /* enable randomized source port */
+#define IPCTL_MAXID       26
 
 #define IPCTL_NAMES { \
  { 0, 0 }, \
@@ -479,6 +481,7 @@
  { "random_id", CTLTYPE_INT }, \
  { "do_loopback_cksum", CTLTYPE_INT }, \
  { "stats", CTLTYPE_STRUCT }, \
+ { "randomport", CTLTYPE_INT }, \
 }
 #endif /* _NETBSD_SOURCE */
 
Index: netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.125
diff -u -r1.125 in_pcb.c
--- netinet/in_pcb.c 5 May 2008 17:11:17 -0000 1.125
+++ netinet/in_pcb.c 11 Jul 2008 17:57:49 -0000
@@ -146,6 +146,7 @@
     ((ntohl((faddr).s_addr) + ntohs(fport)) + \
      (ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_connecthash]
 
+int randomport  = IPPORT_RANDOM;
 int anonportmin = IPPORT_ANONMIN;
 int anonportmax = IPPORT_ANONMAX;
 int lowportmin  = IPPORT_RESERVEDMIN;
@@ -332,6 +333,9 @@
  mymax = swp;
  }
 
+ if (randomport != 0)
+ *lastport = mymax - (arc4random() % (mymax - mymin));
+
  lport = *lastport - 1;
  for (cnt = mymax - mymin + 1; cnt; cnt--, lport--) {
  if (lport < mymin || lport > mymax)
Index: netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.272
diff -u -r1.272 ip_input.c
--- netinet/ip_input.c 5 May 2008 17:11:17 -0000 1.272
+++ netinet/ip_input.c 11 Jul 2008 17:57:49 -0000
@@ -2412,6 +2412,13 @@
        sysctl_net_inet_ip_stats, 0, NULL, 0,
        CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS,
        CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+       CTLTYPE_INT, "randomport",
+       SYSCTL_DESCR("Enable source port randomization"),
+       NULL, 0, &randomport, 0,
+       CTL_NET, PF_INET, IPPROTO_IP,
+       IPCTL_RANDOMPORT, CTL_EOL);
 }
 
 void
Index: netinet/ip_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_var.h,v
retrieving revision 1.87
diff -u -r1.87 ip_var.h
--- netinet/ip_var.h 12 Apr 2008 05:58:22 -0000 1.87
+++ netinet/ip_var.h 11 Jul 2008 17:57:49 -0000
@@ -183,6 +183,7 @@
 extern int   ipforwarding; /* ip forwarding */
 extern int   ip_mtudisc; /* mtu discovery */
 extern int   ip_mtudisc_timeout; /* seconds to timeout mtu discovery */
+extern int   randomport; /* randomize source port */
 extern int   anonportmin; /* minimum ephemeral port */
 extern int   anonportmax; /* maximum ephemeral port */
 extern int   lowportmin; /* minimum reserved port */

#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>

int s, t;
struct sockaddr_in server;

main ()

{

  for (t=0; t<500000; t++) {
        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

        memset((char *) &server, 0, sizeof(server));
        server.sin_addr.s_addr = inet_addr("127.0.0.1");
        server.sin_family = AF_INET;
        server.sin_port = htons(68);

        if (connect (s, (struct sockaddr *)&server, sizeof(server))) {
                perror ("connect");
        }

        close(s);
  }
  printf("%d\n", t);
}

Re: randomize source port

by Darren Reed-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Steven M. Bellovin wrote:
> ...
> How easy would it be to do a timing test?  For example, assume a simple
> program that just counted how many UDP ports it could bind to in ten
> seconds?  I expect some impact, but not a big one; arc4 is very cheap,
> but measurement is always good.
>  

Semi-related to this, I've been looking at this at work.
On a Sun Ultra20, I think it was ~2,000,000/second.
Compared with the libc random on Solaris, which was
10 or 100x that number.

But really it isn't how many per second you can do but
how much CPU it takes to do one and how much CPU
you have left for other things.

For example, with NAT using arc4random, it couldn't
hope to create 2,000,000 sessions per second.

I think you'd be lucky to be doing 200,000 bind()'s per
second to new ports :)


> More seriously -- when at boot time does urandom have enough entropy to
> seed the PRNG?  I've had problems on some server systems with things
> like that.
>  

arc4random, as per libkern, reseeds itself either every 5 minutes or 16k
calls.

If arc4random is too CPU intensive, is it worth using libc's rand and
seeding
that automatically in the kernel as we do with arc4random?

Darren


Re: randomize source port

by Joerg Sonnenberger :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jul 24, 2008 at 03:29:04AM -0700, Darren Reed wrote:
> If arc4random is too CPU intensive, is it worth using libc's rand and  
> seeding that automatically in the kernel as we do with arc4random?

It would be better to use the Mersenne twister or something like sober
as prng in that case. Both are cryptographhically strong PRNGs and can
be a lot faster than arc4random.

Joerg