]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-pfkey: Install ICMP[v6] type/code as expected by the Linux kernel
authorTobias Brunner <tobias@strongswan.org>
Tue, 15 Oct 2013 12:26:51 +0000 (14:26 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 17 Oct 2013 14:57:39 +0000 (16:57 +0200)
src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c

index feff3a7531eb4f8e7f6f97702161736327a740a4..98a6f81d5e1fbd3f1988a0db169ed46468380bbd 100644 (file)
@@ -870,6 +870,28 @@ static int lookup_algorithm(transform_type_t type, int ikev2)
        return alg;
 }
 
+/**
+ * Helper to set a port in a sockaddr_t, the port has to be in host order
+ */
+static void set_port(sockaddr_t *addr, u_int16_t port)
+{
+       switch (addr->sa_family)
+       {
+               case AF_INET:
+               {
+                       struct sockaddr_in *sin = (struct sockaddr_in*)addr;
+                       sin->sin_port = htons(port);
+                       break;
+               }
+               case AF_INET6:
+               {
+                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
+                       sin6->sin6_port = htons(port);
+                       break;
+               }
+       }
+}
+
 /**
  * Copy a host_t as sockaddr_t to the given memory location.
  * @return             the number of bytes copied
@@ -878,37 +900,38 @@ static size_t hostcpy(void *dest, host_t *host, bool include_port)
 {
        sockaddr_t *addr = host->get_sockaddr(host), *dest_addr = dest;
        socklen_t *len = host->get_sockaddr_len(host);
-       u_int16_t port = htons(host->get_port(host));
 
        memcpy(dest, addr, *len);
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
        dest_addr->sa_len = *len;
 #endif
-       switch (dest_addr->sa_family)
+       if (!include_port)
        {
-               case AF_INET:
-               {
-                       struct sockaddr_in *sin = dest;
-                       sin->sin_port = include_port ? port : 0;
-                       break;
-               }
-               case AF_INET6:
-               {
-                       struct sockaddr_in6 *sin6 = dest;
-                       sin6->sin6_port = include_port ? port : 0;
-                       break;
-               }
+               set_port(dest_addr, 0);
        }
        return *len;
 }
 
 /**
- * add a host behind an sadb_address extension
+ * Copy a host_t as sockaddr_t to the given memory location and map the port to
+ * ICMP/ICMPv6 message type/code as the Linux kernel expects it, that is, the
+ * type in the source and the code in the destination address.
+ * @return             the number of bytes copied
  */
-static void host2ext(host_t *host, struct sadb_address *ext, bool include_port)
+static size_t hostcpy_icmp(void *dest, host_t *host, u_int16_t type)
 {
-       size_t len = hostcpy(ext + 1, host, include_port);
-       ext->sadb_address_len = PFKEY_LEN(sizeof(*ext) + len);
+       size_t len;
+
+       len = hostcpy(dest, host, TRUE);
+       if (type == SADB_EXT_ADDRESS_SRC)
+       {
+               set_port(dest, traffic_selector_icmp_type(host->get_port(host)));
+       }
+       else
+       {
+               set_port(dest, traffic_selector_icmp_code(host->get_port(host)));
+       }
+       return len;
 }
 
 /**
@@ -918,10 +941,20 @@ static void add_addr_ext(struct sadb_msg *msg, host_t *host, u_int16_t type,
                                                 u_int8_t proto, u_int8_t prefixlen, bool include_port)
 {
        struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg);
+       size_t len;
+
        addr->sadb_address_exttype = type;
        addr->sadb_address_proto = proto;
        addr->sadb_address_prefixlen = prefixlen;
-       host2ext(host, addr, include_port);
+       if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)
+       {
+               len = hostcpy_icmp(addr + 1, host, type);
+       }
+       else
+       {
+               len = hostcpy(addr + 1, host, include_port);
+       }
+       addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len);
        PFKEY_EXT_ADD(msg, addr);
 }