socket-default plugin allocates random ports if configured to 0.
authorTobias Brunner <tobias@strongswan.org>
Fri, 20 Apr 2012 12:58:02 +0000 (14:58 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 8 Aug 2012 13:30:27 +0000 (15:30 +0200)
Also added strongswan.conf options to change the ports.

configure.in
man/strongswan.conf.5.in
src/libcharon/plugins/socket_default/socket_default_socket.c

index 5ee3b87..3a7d5b7 100644 (file)
@@ -73,7 +73,7 @@ AC_ARG_WITH(
 
 AC_ARG_WITH(
        [charon-udp-port],
-       AS_HELP_STRING([--with-charon-udp-port=port],[UDP port used by charon locally (default 500).]),
+       AS_HELP_STRING([--with-charon-udp-port=port],[UDP port used by charon locally (default 500). Set to 0 to allocate randomly.]),
        [AC_DEFINE_UNQUOTED(CHARON_UDP_PORT, [$withval], [UDP port used by charon locally])
         AC_SUBST(charon_udp_port, [$withval])],
        [AC_SUBST(charon_udp_port, 500)]
@@ -81,14 +81,14 @@ AC_ARG_WITH(
 
 AC_ARG_WITH(
        [charon-natt-port],
-       AS_HELP_STRING([--with-charon-natt-port=port],[UDP port used by charon locally in case a NAT is detected (must be different from charon-udp-port, default 4500)]),
+       AS_HELP_STRING([--with-charon-natt-port=port],[UDP port used by charon locally in case a NAT is detected (must be different from charon-udp-port, default 4500). Set to 0 to allocate randomly.]),
        [AC_DEFINE_UNQUOTED(CHARON_NATT_PORT, [$withval], [UDP post used by charon locally in case a NAT is detected])
         AC_SUBST(charon_natt_port, [$withval])],
        [AC_SUBST(charon_natt_port, 4500)]
 )
 
 AC_MSG_CHECKING([configured UDP ports ($charon_udp_port, $charon_natt_port)])
-if test x$charon_udp_port == x$charon_natt_port; then
+if test x$charon_udp_port != x0 -a x$charon_udp_port = x$charon_natt_port; then
        AC_MSG_ERROR(the ports have to be different)
 else
        AC_MSG_RESULT(ok)
index 4dd818b..8fcba4a 100644 (file)
@@ -210,6 +210,15 @@ Enable multiple authentication exchanges (RFC 4739)
 .BR charon.nbns2
 WINS servers assigned to peer via configuration payload (CP)
 .TP
+.BR charon.port " [500]"
+UDP port used locally. If set to 0 a random port will be allocated.
+.TP
+.BR charon.port_nat_t " [4500]"
+UDP port used locally in case of NAT-T. If set to 0 a random port will be
+allocated.  Has to be different from
+.BR charon.port ,
+otherwise a random port will be allocated.
+.TP
 .BR charon.process_route " [yes]"
 Process RTM_NEWROUTE and RTM_DELROUTE events
 .TP
index beab3ea..a7da2cc 100644 (file)
@@ -83,22 +83,32 @@ struct private_socket_default_socket_t {
        socket_default_socket_t public;
 
        /**
-        * IPv4 socket (500)
+        * Configured port (or random, if initially 0)
+        */
+       u_int16_t port;
+
+       /**
+        * Configured port for NAT-T (or random, if initially 0)
+        */
+       u_int16_t natt;
+
+       /**
+        * IPv4 socket (500 or port)
         */
        int ipv4;
 
        /**
-        * IPv4 socket for NATT (4500)
+        * IPv4 socket for NAT-T (4500 or natt)
         */
        int ipv4_natt;
 
        /**
-        * IPv6 socket (500)
+        * IPv6 socket (500 or port)
         */
        int ipv6;
 
        /**
-        * IPv6 socket for NATT (4500)
+        * IPv6 socket for NAT-T (4500 or natt)
         */
        int ipv6_natt;
 
@@ -153,22 +163,22 @@ METHOD(socket_t, receiver, status_t,
 
        if (FD_ISSET(this->ipv4, &rfds))
        {
-               port = CHARON_UDP_PORT;
+               port = this->port;
                selected = this->ipv4;
        }
        if (FD_ISSET(this->ipv4_natt, &rfds))
        {
-               port = CHARON_NATT_PORT;
+               port = this->natt;
                selected = this->ipv4_natt;
        }
        if (FD_ISSET(this->ipv6, &rfds))
        {
-               port = CHARON_UDP_PORT;
+               port = this->port;
                selected = this->ipv6;
        }
        if (FD_ISSET(this->ipv6_natt, &rfds))
        {
-               port = CHARON_NATT_PORT;
+               port = this->natt;
                selected = this->ipv6_natt;
        }
        if (selected)
@@ -305,7 +315,7 @@ METHOD(socket_t, sender, status_t,
        /* send data */
        sport = src->get_port(src);
        family = dst->get_family(dst);
-       if (sport == 0 || sport == CHARON_UDP_PORT)
+       if (sport == 0 || sport == this->port)
        {
                if (family == AF_INET)
                {
@@ -316,7 +326,7 @@ METHOD(socket_t, sender, status_t,
                        skt = this->ipv6;
                }
        }
-       else if (sport == CHARON_NATT_PORT)
+       else if (sport == this->natt)
        {
                if (family == AF_INET)
                {
@@ -408,14 +418,14 @@ METHOD(socket_t, sender, status_t,
 METHOD(socket_t, get_port, u_int16_t,
        private_socket_default_socket_t *this, bool nat_t)
 {
-       return nat_t ? CHARON_NATT_PORT : CHARON_UDP_PORT;
+       return nat_t ? this->natt : this->port;
 }
 
 /**
  * open a socket to send and receive packets
  */
 static int open_socket(private_socket_default_socket_t *this,
-                                          int family, u_int16_t port)
+                                          int family, u_int16_t *port)
 {
        int on = TRUE;
        struct sockaddr_storage addr;
@@ -432,7 +442,7 @@ static int open_socket(private_socket_default_socket_t *this,
                {
                        struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
                        htoun32(&sin->sin_addr.s_addr, INADDR_ANY);
-                       htoun16(&sin->sin_port, port);
+                       htoun16(&sin->sin_port, *port);
                        addrlen = sizeof(struct sockaddr_in);
                        sol = SOL_IP;
 #ifdef IP_PKTINFO
@@ -446,7 +456,7 @@ static int open_socket(private_socket_default_socket_t *this,
                {
                        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
                        memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
-                       htoun16(&sin6->sin6_port, port);
+                       htoun16(&sin6->sin6_port, *port);
                        addrlen = sizeof(struct sockaddr_in6);
                        sol = SOL_IPV6;
                        pktinfo = IPV6_RECVPKTINFO;
@@ -477,6 +487,32 @@ static int open_socket(private_socket_default_socket_t *this,
                return 0;
        }
 
+       /* retrieve randomly allocated port if needed */
+       if (*port == 0)
+       {
+               if (getsockname(skt, (struct sockaddr *)&addr, &addrlen) < 0)
+               {
+                       DBG1(DBG_NET, "unable to determine port: %s", strerror(errno));
+                       close(skt);
+                       return 0;
+               }
+               switch (family)
+               {
+                       case AF_INET:
+                       {
+                               struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+                               *port = untoh16(&sin->sin_port);
+                               break;
+                       }
+                       case AF_INET6:
+                       {
+                               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+                               *port = untoh16(&sin6->sin6_port);
+                               break;
+                       }
+               }
+       }
+
        /* get additional packet info on receive */
        if (pktinfo > 0)
        {
@@ -493,15 +529,6 @@ static int open_socket(private_socket_default_socket_t *this,
        {
                DBG1(DBG_NET, "installing IKE bypass policy failed");
        }
-
-       /* enable UDP decapsulation globally, only for one socket needed */
-       if (family == AF_INET && port == CHARON_NATT_PORT &&
-               !hydra->kernel_interface->enable_udp_decap(hydra->kernel_interface,
-                                                                                                  skt, family, port))
-       {
-               DBG1(DBG_NET, "enabling UDP decapsulation failed");
-       }
-
        return skt;
 }
 
@@ -543,35 +570,48 @@ socket_default_socket_t *socket_default_socket_create()
                                .destroy = _destroy,
                        },
                },
+               .port = lib->settings->get_int(lib->settings,
+                                                       "%s.port", CHARON_UDP_PORT, charon->name),
+               .natt = lib->settings->get_int(lib->settings,
+                                                       "%s.port_nat_t", CHARON_NATT_PORT, charon->name),
                .max_packet = lib->settings->get_int(lib->settings,
-                                                                       "%s.max_packet", MAX_PACKET, charon->name),
+                                                       "%s.max_packet", MAX_PACKET, charon->name),
        );
 
-       this->ipv4 = open_socket(this, AF_INET, CHARON_UDP_PORT);
-       if (this->ipv4 == 0)
+       if (this->port && this->port == this->natt)
        {
-               DBG1(DBG_NET, "could not open IPv4 socket, IPv4 disabled");
+               DBG1(DBG_NET, "IKE ports can't be equal, will allocate NAT-T "
+                        "port randomly");
+               this->natt = 0;
+       }
+
+       /* we allocate IPv6 sockets first as that will reserve randomly allocated
+        * ports also for IPv4 */
+       this->ipv6 = open_socket(this, AF_INET6, &this->port);
+       if (this->ipv6 == 0)
+       {
+               DBG1(DBG_NET, "could not open IPv6 socket, IPv6 disabled");
        }
        else
        {
-               this->ipv4_natt = open_socket(this, AF_INET, CHARON_NATT_PORT);
-               if (this->ipv4_natt == 0)
+               this->ipv6_natt = open_socket(this, AF_INET6, &this->natt);
+               if (this->ipv6_natt == 0)
                {
-                       DBG1(DBG_NET, "could not open IPv4 NAT-T socket");
+                       DBG1(DBG_NET, "could not open IPv6 NAT-T socket");
                }
        }
 
-       this->ipv6 = open_socket(this, AF_INET6, CHARON_UDP_PORT);
-       if (this->ipv6 == 0)
+       this->ipv4 = open_socket(this, AF_INET, &this->port);
+       if (this->ipv4 == 0)
        {
-               DBG1(DBG_NET, "could not open IPv6 socket, IPv6 disabled");
+               DBG1(DBG_NET, "could not open IPv4 socket, IPv4 disabled");
        }
        else
        {
-               this->ipv6_natt = open_socket(this, AF_INET6, CHARON_NATT_PORT);
-               if (this->ipv6_natt == 0)
+               this->ipv4_natt = open_socket(this, AF_INET, &this->natt);
+               if (this->ipv4_natt == 0)
                {
-                       DBG1(DBG_NET, "could not open IPv6 NAT-T socket");
+                       DBG1(DBG_NET, "could not open IPv4 NAT-T socket");
                }
        }
 
@@ -581,6 +621,14 @@ socket_default_socket_t *socket_default_socket_create()
                destroy(this);
                return NULL;
        }
+
+       /* enable UDP decapsulation globally, only for one socket needed */
+       if (!hydra->kernel_interface->enable_udp_decap(hydra->kernel_interface,
+                                                       this->ipv6_natt ?: this->ipv4_natt,
+                                                       this->ipv6_natt ? AF_INET6 : AF_INET, this->natt))
+       {
+               DBG1(DBG_NET, "enabling UDP decapsulation failed");
+       }
        return &this->public;
 }