Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 May 2014 15:27:50 +0200
From:      Andreas Longwitz <longwitz@incore.de>
To:        freebsd-net@freebsd.org
Subject:   Support for IPSec VPN's with XAuth (tunnel mode) and L2TP (transport mode)
Message-ID:  <537F4CD6.8010305@incore.de>

next in thread | raw e-mail | index | archive | help
Hi, as continuation of
http://lists.freebsd.org/pipermail/freebsd-net/2012-September/033170.html
I like to give patches for two open problems:

The first kernel patch of the link above is not needed anymore, vanhu
pointed out:

> It may be cleaner to have racoon generate the good SP entry, rather
> than kernel trying to guess what is right in a SPDADD command.

I agree , therefore I now use the following patch for racoon in the
ipsec-tools-0.8.0_3 port:

--- src/racoon/isakmp_quick.c.orig  2011-03-14 18:18:13.000000000 +0100
+++ src/racoon/isakmp_quick.c       2014-05-12 00:52:25.000000000 +0200
@@ -2012,6 +2012,13 @@
                /* make inbound policy */
                iph2->src = dst;
                iph2->dst = src;
+#ifdef ENABLE_NATT
+               /* Without NAT the policies must include all ports. */
+               if( !(iph2->ph1->natt_flags & NAT_DETECTED)) {
+                       set_port(iph2->src, 0);
+                       set_port(iph2->dst, 0);
+               }
+#endif
                if (pk_sendspdupdate2(iph2) < 0) {
                        plog(LLV_ERROR, LOCATION, NULL,
                                "pfkey spdupdate2(inbound) failed.\n");

The other open task are IPSEC/L2TP (transport mode) connections from
some clients behind the same NAT router. I do not longer try to solve
this in the kernel and/or racoon, because it is a special "port 1701"
problem. My propose is to handle this with the help of a connect-script
introduced in mpd-5.6:

--- src/l2tp.c.orig     2011-12-21 15:58:49.000000000 +0100
+++ src/l2tp.c  2014-05-14 11:39:24.000000000 +0200
@@ -67,6 +67,7 @@
        struct u_range  peer_addr;    /* Peer IP addresses allowed */
        in_port_t       self_port;    /* self port */
        in_port_t       peer_port;    /* Peer port required (or zero) */
+       char            connect_script[IFACE_MAX_SCRIPT];
        struct optinfo  options;
        char            callingnum[64]; /* L2TP phone number to use */
        char            callednum[64];  /* L2TP phone number to use */
@@ -90,6 +91,7 @@
   enum {
     SET_SELFADDR,
     SET_PEERADDR,
+    SET_CONNECT_SCRIPT,
     SET_CALLINGNUM,
     SET_CALLEDNUM,
     SET_HOSTNAME,
@@ -202,6 +204,8 @@
        L2tpSetCommand, NULL, 2, (void *) SET_SELFADDR },
     { "peer {ip} [{port}]",            "Set remote IP address",
        L2tpSetCommand, NULL, 2, (void *) SET_PEERADDR },
+    { "connect-script [{progname}]",   "Set connect script",
+       L2tpSetCommand, NULL, 2, (void *) SET_CONNECT_SCRIPT },
     { "callingnum {number}",      "Set calling L2TP telephone number",
        L2tpSetCommand, NULL, 2, (void *) SET_CALLINGNUM },
     { "callednum {number}",       "Set called L2TP telephone number",
@@ -913,6 +917,8 @@
        Printf(", port %u", l2tp->conf.peer_port);
     Printf("\r\n");
     Printf("\tHostname     : %s\r\n", l2tp->conf.hostname);
+    Printf("\t  connect-script: \"%s\"\r\n",
+       *l2tp->conf.connect_script ? l2tp->conf.connect_script : "<none>");
     Printf("\tSecret       : %s\r\n",
(l2tp->conf.callingnum[0])?"******":"");
     Printf("\tCalling number: %s\r\n", l2tp->conf.callingnum);
     Printf("\tCalled number: %s\r\n", l2tp->conf.callednum);
@@ -1438,6 +1444,22 @@
                goto fail;
        }

+       /* Call "connect" script */
+       if (*pi->conf.connect_script) {
+               char    selfbuf[40],peerbuf[40];
+               int     res;
+
+               res = ExecCmd(LG_IFACE2, "label", "%s %s %d %s %d",
+                  pi->conf.connect_script,
+                  u_addrtoa(&tun->self_addr, selfbuf,
sizeof(selfbuf)),tun->self_port,
+                  u_addrtoa(&tun->peer_addr, peerbuf, sizeof(peerbuf)),
+                  tun->peer_port);
+               if (res != 0) {
+                  Log(LG_PHYS, ("L2TP: Error running connect-script"));
+                  goto fail;
+               }
+       }
+
        /* Create vendor name AVP */
        avps = ppp_l2tp_avp_list_create();

@@ -1747,6 +1769,18 @@
                l2tp->conf.peer_port = port;
            }
            break;
+       case SET_CONNECT_SCRIPT:
+           switch (ac) {
+               case 0:
+                   *l2tp->conf.connect_script = 0;
+                   break;
+               case 1:
+                   strlcpy(l2tp->conf.connect_script, av[0],
sizeof(l2tp->conf.connect_script));
+                   break;
+               default:
+                   return(-1);
+           }
+           break;
        case SET_CALLINGNUM:
            if (ac != 1)
                return(-1);

Now in mpd.conf a connect-script can be defined which will be called for
every new incoming L2TP packet:
    set l2tp connect-script   /usr/local/etc/mpd5/l2tpConnect

In /etc/ipsec.conf I only the policy for incoming packets is defined:
   spdadd 0.0.0.0/0[0] xx.xx.xx.xx[1701] udp -P in  ipsec
          esp/transport//require;
The policy for outgoing packets is created on the fly by the l2tpConnect
script, I give an example thats working for me:

set -- $*
local_ip=$1
local_port=$2  # always 1701
remote_ip=$3
remote_port=$4

checkSAs() {
 status=0;
 while read line; do
   set -- ${line}
   param1="$1"; param2="$2"; param3="$3"
   case ${status} in
    0)
     var1=${param1%[*}; var2=${param2%[*}
     if [ "${var1}" = "${local_ip}" -a "${var2}" = "${remote_ip}" ]; then
       dir=outbound; status=1
       if [ "${param1}" = "${var1}" ]; then
          nat=0; port="500"
       else
          nat=1; var2=${param2%]}; port=${var2#*[}
       fi
     fi
     if [ "${var2}" = "${local_ip}" -a "${var1}" = "${remote_ip}" ]; then
       dir=inbound; status=1
     fi
     ;;
    1)
     if [ "${param2}" != "mode=transport" ]; then
       status=0
     else
       var="${param3}"; var=${var%(*}; var=${var#*=}
       status=2
     fi
     ;;
    2)
     if [ "${param1}" = "allocated:" ]; then
       status=0
       if [ "${param2}" = "0" -a "${dir}" = "outbound" ]; then
         SA_remote_port=${port}; SA_nat=${nat}
       fi
      fi
      ;;
    esac
 done
 echo "${SA_nat} ${SA_remote_port}"
}

SA=$(/usr/local/sbin/setkey -D | checkSAs)
set -- ${SA}
SA_nat=$1; SA_remote_port=$2
if [ ${SA_nat} = "1" ]; then
   src_dst="${local_ip}[4500]-${remote_ip}[${SA_remote_port}]"
else
   src_dst="${local_ip}-${remote_ip}"
fi
echo "spdadd ${local_ip}[${local_port}] ${remote_ip}[${remote_port}] udp
      -P out ipsec esp/transport/${src_dst}/require;" |
      /usr/local/sbin/setkey -c

-- 
Andreas Longwitz




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?537F4CD6.8010305>