initial support for IPv6 (more testing needed)
authorMartin Willi <martin@strongswan.org>
Wed, 30 Aug 2006 17:12:56 +0000 (17:12 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 30 Aug 2006 17:12:56 +0000 (17:12 -0000)
  socket works (without v6 filter)
  traffic selector handle IPv4/v4 cleanly
    improvements in traffic selector code
  kernel interface accepts v6 traffic selectors and hosts
  host_t class has full IPv6 support

16 files changed:
src/charon/config/traffic_selector.c
src/charon/daemon.c
src/charon/encoding/message.c
src/charon/encoding/payloads/traffic_selector_substructure.c
src/charon/network/socket.c
src/charon/network/socket.h
src/charon/queues/jobs/incoming_packet_job.c
src/charon/queues/send_queue.c
src/charon/sa/ike_sa.c
src/charon/sa/transactions/ike_sa_init.c
src/charon/threads/kernel_interface.c
src/charon/threads/sender.c
src/charon/threads/stroke_interface.c
src/libstrongswan/utils/host.c
src/libstrongswan/utils/host.h
src/starter/starterstroke.c

index 3d53d90..24cf7ea 100644 (file)
@@ -53,17 +53,27 @@ struct private_traffic_selector_t {
        u_int8_t protocol;
        
        /** 
-        * begin of address range, host order
+        * begin of address range, network order
         */
        union {
-               u_int32_t from_addr_ipv4;
+               /** dummy char for common address manipulation */
+               char from[0];
+               /** IPv4 address */
+               u_int32_t from4[1];
+               /** IPv6 address */
+               u_int32_t from6[4];
        };
        
        /**
-        * end of address range, host order
+        * end of address range, network order
         */
        union {
-               u_int32_t to_addr_ipv4;
+               /** dummy char for common address manipulation */
+               char to[0];
+               /** IPv4 address */
+               u_int32_t to4[1];
+               /** IPv6 address */
+               u_int32_t to6[4];
        };
        
        /**
@@ -83,6 +93,60 @@ struct private_traffic_selector_t {
 };
 
 /**
+ * calculate to "to"-address for the "from" address and a subnet size
+ */
+static void calc_range(private_traffic_selector_t *this, u_int8_t netbits)
+{
+       int byte;
+       size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+       
+       /* go through the from address, starting at the tail. While we
+        * have not processed the bits belonging to the host, set them to 1 on
+        * the to address. If we reach the bits for the net, copy them from "from". */
+       for (byte = size - 1; byte >=0; byte--)
+       {
+               u_char mask = 0x00;
+               int shift;
+               
+               shift = (byte+1) * 8 - netbits;
+               if (shift > 0)
+               {
+                       mask = 1 << shift;
+                       if (mask != 0xFF)
+                       {
+                               mask--;
+                       }
+               }
+               this->to[byte] = this->from[byte] | mask;
+       }
+}
+
+/**
+ * calculate to subnet size from "to"- and "from"-address
+ */
+static u_int8_t calc_netbits(private_traffic_selector_t *this)
+{
+       int byte, bit;
+       size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+       
+       /* go trough all bits of the addresses, begging in the front. 
+        * As longer as they equal, the subnet gets larger */
+       for (byte = 0; byte < size; byte++)
+       {
+               for (bit = 7; bit >= 0; bit--)
+               {
+                       if ((1<<bit & this->from[byte]) != (1<<bit & this->to[byte]))
+                       {
+                               return ((7 - bit) + (byte * 8));
+                       }
+               }
+       }
+       /* single host, netmask is 32/128 */
+       return (size * 8);
+}
+
+
+/**
  * internal generic constructor
  */
 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port);
@@ -105,23 +169,13 @@ static void update_string(private_traffic_selector_t *this)
        
        if (this->type == TS_IPV4_ADDR_RANGE)
        {
-               u_int32_t from_no, to_no, bit;
-               u_int8_t mask = 32;
+               u_int8_t mask;
                
                /* build address string */
-               from_no = htonl(this->from_addr_ipv4);
-               to_no = htonl(this->to_addr_ipv4);
-               inet_ntop(AF_INET, &from_no, addr_str, sizeof(addr_str));
+               inet_ntop(AF_INET, &this->from4, addr_str, sizeof(addr_str));
                
                /* build network mask string */
-               for (bit = 0; bit < 32; bit++)
-               {
-                       if ((1<<bit & from_no) != (1<<bit & to_no))
-                       {
-                               mask = bit;
-                               break;
-                       }
-               }
+               mask = calc_netbits(this);
                if (mask != 32)
                {
                        snprintf(mask_str, sizeof(mask_str), "/%d", mask);
@@ -129,8 +183,17 @@ static void update_string(private_traffic_selector_t *this)
        }
        else
        {
-               /* TODO: be a little bit more verbose ;-) */
-               snprintf(addr_str, sizeof(addr_str), "(IPv6 address range)");
+               u_int8_t mask;
+               
+               /* build address string */
+               inet_ntop(AF_INET6, &this->from6, addr_str, sizeof(addr_str));
+               
+               /* build network mask string */
+               mask = calc_netbits(this);
+               if (mask != 128)
+               {
+                       snprintf(mask_str, sizeof(mask_str), "/%d", mask);
+               }
        }
        
        /* build protocol string */
@@ -208,22 +271,15 @@ static char *get_string(private_traffic_selector_t *this)
  */
 static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other)
 {
-       if ((this->type == TS_IPV4_ADDR_RANGE) && (other->type == TS_IPV4_ADDR_RANGE) &&
-               (this->protocol == other->protocol || this->protocol == 0 || other->protocol == 0))
+       if (this->type == other->type && (this->protocol == other->protocol ||
+                                                               this->protocol == 0 || other->protocol == 0))
        {
-               u_int32_t from_addr, to_addr;
                u_int16_t from_port, to_port;
+               u_char *from, *to;
                u_int8_t protocol;
+               size_t size;
                private_traffic_selector_t *new_ts;
                
-               /* calculate the maximum address range allowed for both */
-               from_addr = max(this->from_addr_ipv4, other->from_addr_ipv4);
-               to_addr = min(this->to_addr_ipv4, other->to_addr_ipv4);
-               if (from_addr > to_addr)
-               {
-                       return NULL;
-               }
-               
                /* calculate the maximum port range allowed for both */
                from_port = max(this->from_port, other->from_port);
                to_port = min(this->to_port, other->to_port);
@@ -231,18 +287,53 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_
                {
                        return NULL;
                }
-               
                /* select protocol, which is not zero */
                protocol = max(this->protocol, other->protocol);
                
-               /* got a match, return it */
-               new_ts = traffic_selector_create(protocol, this->type, from_port, to_port); 
-               new_ts->from_addr_ipv4 = from_addr;
-               new_ts->to_addr_ipv4 = to_addr;
-               new_ts->type = TS_IPV4_ADDR_RANGE;
+               switch (this->type)
+               {
+                       case TS_IPV4_ADDR_RANGE:
+                               size = sizeof(this->from4);
+                               break;
+                       case TS_IPV6_ADDR_RANGE:
+                               size = sizeof(this->from6);
+                               break;
+                       default:
+                               return NULL;
+               }
+               
+               /* get higher from-address */
+               if (memcmp(this->from, other->from, size) > 0)
+               {
+                       from = this->from;
+               }
+               else
+               {
+                       from = other->from;
+               }
+               /* get lower to-address */
+               if (memcmp(this->to, other->to, size) > 0)
+               {
+                       to = other->to;
+               }
+               else
+               {
+                       to = this->to;
+               }
+               /* if "from" > "to", we don't have a match */
+               if (memcmp(from, to, size) > 0)
+               {
+                       return NULL;
+               }
+               
+               /* we have a match in protocol, port, and address: return it... */
+               new_ts = traffic_selector_create(protocol, this->type, from_port, to_port);
+               new_ts->type = this->type;
+               memcpy(new_ts->from, from, size);
+               memcpy(new_ts->to, to, size);
                update_string(new_ts);
                
-               return &(new_ts->public);
+               return &new_ts->public;
        }
        return NULL;
 }
@@ -256,16 +347,28 @@ static bool equals(private_traffic_selector_t *this, private_traffic_selector_t
        {
                return FALSE;
        }
-       if (this->type == TS_IPV4_ADDR_RANGE)
+       if (!(this->from_port == other->from_port &&
+                 this->to_port == other->to_port &&
+                 this->protocol == other->protocol))
        {
-               if (this->from_addr_ipv4 == other->from_addr_ipv4 &&
-                       this->to_addr_ipv4 == other->to_addr_ipv4 &&
-                       this->from_port == other->from_port &&
-                       this->to_port == other->to_port &&
-                       this->protocol == other->protocol)
-               {
-                       return TRUE;
-               }
+               return FALSE;
+       }
+       switch (this->type)
+       {
+               case TS_IPV4_ADDR_RANGE:
+                       if (memeq(this->from4, other->from4, sizeof(this->from4)))
+                       {
+                               return TRUE;
+                       }
+                       break;
+               case TS_IPV6_ADDR_RANGE:
+                       if (memeq(this->from6, other->from6, sizeof(this->from6)))
+                       {
+                               return TRUE;
+                       }
+                       break;
+               default:
+                       break;
        }
        return FALSE;
 }
@@ -275,26 +378,26 @@ static bool equals(private_traffic_selector_t *this, private_traffic_selector_t
  */
 static chunk_t get_from_address(private_traffic_selector_t *this)
 {
-       chunk_t from_addr = CHUNK_INITIALIZER;
+       chunk_t from = CHUNK_INITIALIZER;
        
        switch (this->type)
        {
                case TS_IPV4_ADDR_RANGE:
                {
-                       u_int32_t network;
-                       from_addr.len = sizeof(network);
-                       from_addr.ptr = malloc(from_addr.len);
-                       /* chunk must contain network order, convert! */
-                       network = htonl(this->from_addr_ipv4);
-                       memcpy(from_addr.ptr, &network, from_addr.len);
-                       break;  
+                       from.len = sizeof(this->from4);
+                       from.ptr = malloc(from.len);
+                       memcpy(from.ptr, this->from4, from.len);
+                       break;
                }
                case TS_IPV6_ADDR_RANGE:
                {
+                       from.len = sizeof(this->from6);
+                       from.ptr = malloc(from.len);
+                       memcpy(from.ptr, this->from6, from.len);
                        break;
                }
        }
-       return from_addr;
+       return from;
 }
        
 /**
@@ -302,26 +405,26 @@ static chunk_t get_from_address(private_traffic_selector_t *this)
  */
 static chunk_t get_to_address(private_traffic_selector_t *this)
 {
-       chunk_t to_addr = CHUNK_INITIALIZER;
+       chunk_t to = CHUNK_INITIALIZER;
        
        switch (this->type)
        {
                case TS_IPV4_ADDR_RANGE:
                {
-                       u_int32_t network;
-                       to_addr.len = sizeof(network);
-                       to_addr.ptr = malloc(to_addr.len);
-                       /* chunk must contain network order, convert! */
-                       network = htonl(this->to_addr_ipv4);
-                       memcpy(to_addr.ptr, &network, to_addr.len);
-                       break;  
+                       to.len = sizeof(this->to4);
+                       to.ptr = malloc(to.len);
+                       memcpy(to.ptr, this->to4, to.len);
+                       break;
                }
                case TS_IPV6_ADDR_RANGE:
                {
+                       to.len = sizeof(this->to6);
+                       to.ptr = malloc(to.len);
+                       memcpy(to.ptr, this->to6, to.len);
                        break;
                }
        }
-       return to_addr;
+       return to;
 }
        
 /**
@@ -361,14 +464,23 @@ static u_int8_t get_protocol(private_traffic_selector_t *this)
  */
 static void update_address_range(private_traffic_selector_t *this, host_t *host)
 {
-       if (host->get_family(host) == AF_INET &&
-               this->type == TS_IPV4_ADDR_RANGE)
+       if (host->get_family(host) == AF_INET && this->type == TS_IPV4_ADDR_RANGE)
+       {
+               if (this->from4[0] == 0)
+               {
+                       chunk_t from = host->get_address(host);
+                       memcpy(this->from4, from.ptr, from.len);
+                       memcpy(this->to4, from.ptr, from.len);
+               }
+       }
+       if (host->get_family(host) == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE)
        {
-               if (this->from_addr_ipv4 == 0)
+               if (this->from6[0] == 0 && this->from6[1] == 0 &&
+                       this->from6[2] == 0 && this->from6[3] == 0)
                {
                        chunk_t from = host->get_address(host);
-                       this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr));
-                       this->to_addr_ipv4 = this->from_addr_ipv4;
+                       memcpy(this->from6, from.ptr, from.len);
+                       memcpy(this->to6, from.ptr, from.len);
                }
        }
        update_string(this);
@@ -387,16 +499,22 @@ static traffic_selector_t *clone_(private_traffic_selector_t *this)
        {
                case TS_IPV4_ADDR_RANGE:
                {
-                       clone->from_addr_ipv4 = this->from_addr_ipv4;
-                       clone->to_addr_ipv4 = this->to_addr_ipv4;
+                       memcpy(clone->from4, this->from4, sizeof(this->from4));
+                       memcpy(clone->to4, this->to4, sizeof(this->to4));
                        update_string(clone);
                        return &clone->public;
                }
                case TS_IPV6_ADDR_RANGE:
+               {
+                       memcpy(clone->from6, this->from6, sizeof(this->from6));
+                       memcpy(clone->to6, this->to6, sizeof(this->to6));
+                       update_string(clone);
+                       return &clone->public;
+               }
                default:
                {
-                       free(this);
-                       return NULL;    
+                       /* unreachable */
+                       return &clone->public;
                }
        }
 }
@@ -413,7 +531,7 @@ static void destroy(private_traffic_selector_t *this)
 /*
  * see header
  */
-traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_addr, u_int16_t from_port, chunk_t to_addr, u_int16_t to_port)
+traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from, u_int16_t from_port, chunk_t to, u_int16_t to_port)
 {
        private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
        
@@ -421,17 +539,26 @@ traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_typ
        {
                case TS_IPV4_ADDR_RANGE:
                {
-                       if (from_addr.len != 4 || to_addr.len != 4)
+                       if (from.len != 4 || to.len != 4)
                        {
                                free(this);
                                return NULL;
                        }
-                       /* chunk contains network order, convert! */
-                       this->from_addr_ipv4 = ntohl(*((u_int32_t*)from_addr.ptr));
-                       this->to_addr_ipv4 = ntohl(*((u_int32_t*)to_addr.ptr));
+                       memcpy(this->from4, from.ptr, from.len);
+                       memcpy(this->to4, to.ptr, to.len);
                        break;
                }
                case TS_IPV6_ADDR_RANGE:
+               {
+                       if (from.len != 16 || to.len != 16)
+                       {
+                               free(this);
+                               return NULL;
+                       }
+                       memcpy(this->from6, from.ptr, from.len);
+                       memcpy(this->to6, to.ptr, to.len);
+                       break;
+               }
                default:
                {
                        free(this);
@@ -459,23 +586,44 @@ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t ne
                        
                        this->type = TS_IPV4_ADDR_RANGE;
                        from = net->get_address(net);
-                       this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr));
-                       if (this->from_addr_ipv4 == 0)
+                       memcpy(this->from4, from.ptr, from.len);
+                       if (this->from4[0] == 0)
                        {
                                /* use /0 for 0.0.0.0 */
-                               this->to_addr_ipv4 = ~0;
+                               this->to4[0] = ~0;
                        }
                        else
                        {
-                               this->to_addr_ipv4 = this->from_addr_ipv4 | ((1 << (32 - netbits)) - 1);
+                               calc_range(this, netbits);
                        }
-                       break;  
+                       break;
                }
                case AF_INET6:
+               {
+                       chunk_t from;
+                       
+                       this->type = TS_IPV6_ADDR_RANGE;
+                       from = net->get_address(net);
+                       memcpy(this->from6, from.ptr, from.len);
+                       if (this->from6[0] == 0 && this->from6[1] == 0 &&
+                               this->from6[2] == 0 && this->from6[3] == 0)
+                       {
+                               /* use /0 for ::0 */
+                               this->to6[0] = ~0;
+                               this->to6[1] = ~0;
+                               this->to6[2] = ~0;
+                               this->to6[3] = ~0;
+                       }
+                       else
+                       {
+                               calc_range(this, netbits);
+                       }
+                       break;
+               }
                default:
                {
                        free(this);
-                       return NULL;    
+                       return NULL;
                }
        }
        if (port)
@@ -505,25 +653,31 @@ traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_ty
        {
                case TS_IPV4_ADDR_RANGE:
                {
-                       if (inet_aton(from_addr, (struct in_addr*)&(this->from_addr_ipv4)) == 0)
+                       if (inet_pton(AF_INET, from_addr, (struct in_addr*)this->from4) < 0)
                        {
                                free(this);
                                return NULL;
                        }
-                       if (inet_aton(to_addr, (struct in_addr*)&(this->to_addr_ipv4)) == 0)
+                       if (inet_pton(AF_INET, to_addr, (struct in_addr*)this->to4) < 0)
                        {
                                free(this);
                                return NULL;
                        }
-                       /* convert to host order, inet_aton has network order */
-                       this->from_addr_ipv4 = ntohl(this->from_addr_ipv4);
-                       this->to_addr_ipv4 = ntohl(this->to_addr_ipv4);
                        break;  
                }
                case TS_IPV6_ADDR_RANGE:
                {
-                       free(this);
-                       return NULL;    
+                       if (inet_pton(AF_INET6, from_addr, (struct in6_addr*)this->from6) < 0)
+                       {
+                               free(this);
+                               return NULL;
+                       }
+                       if (inet_pton(AF_INET6, to_addr, (struct in6_addr*)this->to6) < 0)
+                       {
+                               free(this);
+                               return NULL;
+                       }
+                       break;
                }
        }
        
index a5ac5c6..68846fc 100644 (file)
@@ -250,7 +250,10 @@ void signal_handler(int signal)
        strings = backtrace_symbols(array, size);
        logger = logger_manager->get_logger(logger_manager, DAEMON);
 
-       logger->log(logger, ERROR, "Thread %u received SIGSEGV. Dumping %d frames from stack:", pthread_self(), size);
+       logger->log(logger, ERROR, 
+                               "Thread %u received %s. Dumping %d frames from stack:",
+                               signal == SIGSEGV ? "SIGSEGV" : "SIGILL",
+                               pthread_self(), size);
 
        for (i = 0; i < size; i++)
        {
@@ -312,6 +315,10 @@ private_daemon_t *daemon_create(void)
        {
                this->logger->log(this->logger, ERROR, "signal handler setup for SIGSEGV failed");
        }
+       if (sigaction(SIGILL, &action, NULL) == -1)
+       {
+               this->logger->log(this->logger, ERROR, "signal handler setup for SIGILL failed");
+       }
        return this;
 }
 
@@ -405,7 +412,6 @@ int main(int argc, char *argv[])
                fprintf(pid_file, "%d\n", getpid());
                fclose(pid_file);
        }
-       
        /* log socket info */
        list = charon->socket->create_local_address_list(charon->socket);
        private_charon->logger->log(private_charon->logger, CONTROL,
@@ -416,7 +422,6 @@ int main(int argc, char *argv[])
                private_charon->logger->log(private_charon->logger, CONTROL,
                                                                        "  %s", host->get_string(host));
                host->destroy(host);
-               
        }
        list->destroy(list);
        
index 29a2103..b4bede3 100644 (file)
@@ -1062,8 +1062,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig
                        if (status != SUCCESS)
                        {
                                this->logger->log(this->logger, ERROR, 
-                                                                 "encrypted payload could not be decrypted and parsed: %s", 
-                                                                 mapping_find(status_m, status));
+                                                                 "encrypted payload could not be decrypted and parsed");
                                iterator->destroy(iterator);
                                return PARSE_ERROR;
                        }
index 2ac7464..6ca600e 100644 (file)
@@ -149,6 +149,15 @@ static status_t verify(private_traffic_selector_substructure_t *this)
                        break;
                }
                case TS_IPV6_ADDR_RANGE:
+               {
+                       if ((this->starting_address.len != 16) ||
+                               (this->ending_address.len != 16))
+                       {
+                               /* ipv6 address must be 16 bytes long */
+                               return FAILED;
+                       }
+                       break;
+               }
                default:
                {
                        /* not supported ts type */
index aca48ec..e208624 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/udp.h>
 #include <linux/ipsec.h>
 #include <linux/filter.h>
 
 /* constants for packet handling */
 #define IP_LEN sizeof(struct iphdr)
+#define IP6_LEN sizeof(struct ip6_hdr)
 #define UDP_LEN sizeof(struct udphdr)
 #define MARKER_LEN sizeof(u_int32_t)
+
 /* offsets for packet handling */
-#define IP 0
-#define UDP IP + IP_LEN
-#define IKE UDP + UDP_LEN
+#define IP_PROTO_OFFSET 9
+#define IP6_PROTO_OFFSET 6
+#define IKE_VERSION_OFFSET 17
+#define IKE_LENGTH_OFFSET 24
 
 /* from linux/in.h */
 #ifndef IP_IPSEC_POLICY
@@ -90,19 +93,34 @@ struct private_socket_t{
         int natt_port;
         
         /**
-         * raw socket (receiver)
+         * raw receiver socket for IPv4
+         */
+        int recv4;
+        
+        /**
+         * raw receiver socket for IPv6
          */
-        int raw_fd;
+        int recv6;
 
         /**
-         * send socket on regular port
+         * send socket on regular port for IPv4
          */
-        int send_fd;
+        int send4;
 
         /**
-         * send socket on nat-t port
+         * send socket on regular port for IPv6
          */
-        int natt_fd;
+        int send6;
+
+        /**
+         * send socket on nat-t port for IPv4
+         */
+        int send4_natt;
+
+        /**
+         * send socket on nat-t port for IPv6
+         */
+        int send6_natt;
         
         /** 
          * logger for this socket
@@ -120,54 +138,180 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
        packet_t *pkt;
        struct iphdr *ip;
        struct udphdr *udp;
-       host_t *source, *dest;
+       host_t *source = NULL, *dest = NULL;
        int bytes_read = 0;
        int data_offset, oldstate;
+       fd_set rfds;
+
+       FD_ZERO(&rfds);
+       FD_SET(this->recv4, &rfds);
+       FD_SET(this->recv6, &rfds);
+       
+       this->logger->log(this->logger, CONTROL|LEVEL1,
+                                         "waiting for data on raw sockets");
        
-       this->logger->log(this->logger, CONTROL|LEVEL1, "receive from raw socket");
-       /* allow cancellation while blocking on recv() */
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-       bytes_read = recv(this->raw_fd, buffer, MAX_PACKET, 0);
-       pthread_setcancelstate(oldstate, NULL);
-
-       if (bytes_read < 0)
+       if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0)
        {
-               this->logger->log(this->logger, ERROR, "error reading from socket: %s", strerror(errno));
+               pthread_setcancelstate(oldstate, NULL);
                return FAILED;
        }
-
-       /* read source/dest from raw IP/UDP header */
-       ip = (struct iphdr*) buffer;
-       udp = (struct udphdr*) (buffer + IP_LEN);
+       pthread_setcancelstate(oldstate, NULL);
        
-       source = host_create_from_hdr(ip->saddr, udp->source);
-       dest = host_create_from_hdr(ip->daddr, udp->dest);
-
-       pkt = packet_create();
-       pkt->set_source(pkt, source);
-       pkt->set_destination(pkt, dest);
-
-       this->logger->log(this->logger, CONTROL|LEVEL1, "received packet: from %s:%d to %s:%d",
-                                         source->get_string(source), source->get_port(source),
-                                         dest->get_string(dest), dest->get_port(dest));
-
-       data_offset = IP_LEN + UDP_LEN;
-
-       /* remove non esp marker */     
-       if (dest->get_port(dest) == this->natt_port)
+       if (FD_ISSET(this->recv4, &rfds))
        {
-               data_offset += MARKER_LEN;
+               /* IPv4 raw sockets return the IP header. We read src/dest
+                * information directly from the raw header */
+               struct sockaddr_in src, dst;
+               bytes_read = recv(this->recv4, buffer, MAX_PACKET, 0);
+               if (bytes_read < 0)
+               {
+                       this->logger->log(this->logger, ERROR,
+                                                         "error reading from IPv4 socket: %s", 
+                                                         strerror(errno));
+                       return FAILED;
+               }
+               this->logger->log_bytes(this->logger, RAW,
+                                                               "received IPv4 packet", buffer, bytes_read);
+               
+               /* read source/dest from raw IP/UDP header */
+               if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
+               {
+                       this->logger->log(this->logger, ERROR,
+                                                         "received IPv4 packet too short");
+                       return FAILED;
+               }
+               ip = (struct iphdr*) buffer;
+               udp = (struct udphdr*) (buffer + IP_LEN);
+               src.sin_family = AF_INET;
+               src.sin_addr.s_addr = ip->saddr;
+               src.sin_port = udp->source;
+               dst.sin_family = AF_INET;
+               dst.sin_addr.s_addr = ip->daddr;
+               dst.sin_port = udp->dest;
+               source = host_create_from_sockaddr((sockaddr_t*)&src);
+               dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+               
+               pkt = packet_create();
+               pkt->set_source(pkt, source);
+               pkt->set_destination(pkt, dest);
+               this->logger->log(this->logger, CONTROL|LEVEL1, 
+                                                 "received packet: from %s[%d] to %s[%d]",
+                                                 source->get_string(source), source->get_port(source),
+                                                 dest->get_string(dest), dest->get_port(dest));
+               data_offset = IP_LEN + UDP_LEN;
+               /* remove non esp marker */     
+               if (dest->get_port(dest) == this->natt_port)
+               {
+                       data_offset += MARKER_LEN;
+               }
+               /* fill in packet */
+               data.len = bytes_read - data_offset;
+               data.ptr = malloc(data.len);
+               memcpy(data.ptr, buffer + data_offset, data.len);
+               pkt->set_data(pkt, data);
+       }
+       else if (FD_ISSET(this->recv6, &rfds))
+       {
+               /* IPv6 raw sockets return the no IP header. We must query
+                * src/dest via socket options/ancillary data */
+               struct msghdr msg;
+               struct cmsghdr *cmsgptr;
+               struct sockaddr_in6 src, dst;
+               struct iovec iov;
+               char ancillary[64];
+               
+               msg.msg_name = &src;
+               msg.msg_namelen = sizeof(src);
+               iov.iov_base = buffer;
+               iov.iov_len = sizeof(buffer);
+               msg.msg_iov = &iov;
+               msg.msg_iovlen = 1;
+               msg.msg_control = ancillary;
+               msg.msg_controllen = sizeof(ancillary);
+               msg.msg_flags = 0;
+               
+               bytes_read = recvmsg(this->recv6, &msg, 0);
+               if (bytes_read < 0)
+               {
+                       this->logger->log(this->logger, ERROR, 
+                                                         "error reading from IPv6 socket: %s", 
+                                                         strerror(errno));
+                       return FAILED;
+               }
+               this->logger->log_bytes(this->logger, RAW,
+                                                               "received IPv6 packet", buffer, bytes_read);
+               
+               if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN)
+               {
+                       this->logger->log(this->logger, ERROR,
+                                                         "received IPv6 packet too short");
+                       return FAILED;
+               }
+               
+               /* read ancillary data to get destination address */
+               for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+                        cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
+               {
+                       if (cmsgptr->cmsg_len == 0) 
+                       {
+                               this->logger->log(this->logger, ERROR, 
+                                                                 "error reading IPv6 ancillary data: %s", 
+                                                                 strerror(errno));
+                               return FAILED;
+                       }       
+                       if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
+                               cmsgptr->cmsg_type == IPV6_PKTINFO)
+                       {
+                               struct in6_pktinfo *pktinfo;
+                               pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr);
+                               
+                               memset(&dst, 0, sizeof(dst));
+                               memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
+                               dst.sin6_family = AF_INET6;
+                               udp = (struct udphdr*) (buffer);
+                               dst.sin6_port = udp->dest;
+                               src.sin6_port = udp->source;
+                               dest = host_create_from_sockaddr((sockaddr_t*)&dst);
+                       }
+               }
+               /* ancillary data missing? */
+               if (dest == NULL)
+               {
+                       this->logger->log(this->logger, ERROR, 
+                                                         "error reading IPv6 packet header");
+                       return FAILED;
+               }
+               
+               source = host_create_from_sockaddr((sockaddr_t*)&src);
+               
+               pkt = packet_create();
+               pkt->set_source(pkt, source);
+               pkt->set_destination(pkt, dest);
+               this->logger->log(this->logger, CONTROL|LEVEL1, 
+                                                 "received packet: from %s[%d] to %s[%d]",
+                                                 source->get_string(source), source->get_port(source),
+                                                 dest->get_string(dest), dest->get_port(dest));
+               data_offset = UDP_LEN;
+               /* remove non esp marker */     
+               if (dest->get_port(dest) == this->natt_port)
+               {
+                       data_offset += MARKER_LEN;
+               }
+               /* fill in packet */
+               data.len = bytes_read - data_offset;
+               data.ptr = malloc(data.len);
+               memcpy(data.ptr, buffer + data_offset, data.len);
+               pkt->set_data(pkt, data);
+       }
+       else
+       {
+               /* oops, shouldn't happen */
+               return FAILED;
        }
        
-       /* fill in packet */
-       data.len = bytes_read - data_offset;
-       data.ptr = malloc(data.len);
-       memcpy(data.ptr, buffer + data_offset, data.len);
-       pkt->set_data(pkt, data);
-
        /* return packet */
        *packet = pkt;
-
        return SUCCESS;
 }
 
@@ -176,7 +320,7 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
  */
 status_t sender(private_socket_t *this, packet_t *packet)
 {
-       int sport, fd;
+       int sport, skt, family;
        ssize_t bytes_sent;
        chunk_t data, marked;
        host_t *src, *dst;
@@ -185,50 +329,68 @@ status_t sender(private_socket_t *this, packet_t *packet)
        dst = packet->get_destination(packet);
        data = packet->get_data(packet);
 
-       this->logger->log(this->logger, CONTROL|LEVEL1, "sending packet: from %s:%d to %s:%d",
+       this->logger->log(this->logger, CONTROL|LEVEL1, "sending packet: from %s[%d] to %s[%d]",
                                          src->get_string(src), src->get_port(src),
                                          dst->get_string(dst), dst->get_port(dst));
        
        /* send data */
        sport = src->get_port(src);
+       family = dst->get_family(dst);
        if (sport == this->port)
        {
-               fd = this->send_fd;
+               if (family == AF_INET)
+               {
+                       skt = this->send4;
+               }
+               else
+               {
+                       skt = this->send6;
+               }
        }
        else if (sport == this->natt_port)
        {
-               fd = this->natt_fd;
+               if (family == AF_INET)
+               {
+                       skt = this->send4_natt;
+               }
+               else
+               {
+                       skt = this->send6_natt;
+               }
                /* NAT keepalives without marker */
                if (data.len != 1 || data.ptr[0] != 0xFF)
                {
                        /* add non esp marker to packet */
                        if (data.len > MAX_PACKET - MARKER_LEN)
                        {
-                               this->logger->log(this->logger, ERROR, "unable to send packet: it's too big");
+                               this->logger->log(this->logger, ERROR, 
+                                                                 "unable to send packet: it's too big");
                                return FAILED;
                        }
                        marked = chunk_alloc(data.len + MARKER_LEN);
                        memset(marked.ptr, 0, MARKER_LEN);
                        memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len);
-                       packet->set_data(packet, marked); /* let the packet do the clean up for us */
+                       /* let the packet do the clean up for us */
+                       packet->set_data(packet, marked);
                        data = marked;
                }
        }
        else
        {
-               this->logger->log(this->logger, ERROR, "unable to locate a send socket for port: %d", sport);
+               this->logger->log(this->logger, ERROR,
+                                                 "unable to locate a send socket for port %d", sport);
                return FAILED;
        }
        
-       bytes_sent = sendto(fd, data.ptr, data.len, 0,
+       bytes_sent = sendto(skt, data.ptr, data.len, 0,
                                                dst->get_sockaddr(dst), *(dst->get_sockaddr_len(dst)));
 
        if (bytes_sent != data.len)
        {
-               this->logger->log(this->logger, ERROR, "error writing to socket: %s", strerror(errno));
+               this->logger->log(this->logger, ERROR, 
+                                                 "error writing to socket: %s", strerror(errno));
                return FAILED;
        }
-       
        return SUCCESS;
 }
 
@@ -326,7 +488,9 @@ static linked_list_t* create_local_address_list(private_socket_t *this)
                host = host_create_from_sockaddr(cur->ifa_addr);
                if (host)
                {
-                       /* address supported, add to list */
+                       /* we use always the IKEv2 port. This is relevant for
+                        * natd payload hashing. */
+                       host->set_port(host, this->port);
                        result->insert_last(result, host);
                }
        }
@@ -335,27 +499,60 @@ static linked_list_t* create_local_address_list(private_socket_t *this)
 }
 
 /**
- * setup a send socket on a specified port
+ * open a socket to send packets
  */
-static status_t setup_send_socket(private_socket_t *this, u_int16_t port, int *send_fd) 
+static int open_send_socket(private_socket_t *this, int family, u_int16_t port)
 {
        int on = TRUE;
-       struct sockaddr_in addr;
+       int type = UDP_ENCAP_ESPINUDP;
+       struct sockaddr_storage addr;
+       u_int ip_proto, ipsec_policy;
        struct sadb_x_policy policy;
-       int fd;
+       int skt;
        
-       fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (fd < 0)
+       memset(&addr, 0, sizeof(addr));
+       /* precalculate constants depending on address family */
+       switch (family)
        {
-               this->logger->log(this->logger, ERROR, "could not open IPv4 send socket!");
-               return FAILED;
+               case AF_INET:
+               {
+                       struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+                       sin->sin_family = AF_INET;
+                       sin->sin_addr.s_addr = INADDR_ANY;
+                       sin->sin_port = htons(port);
+                       ip_proto = IPPROTO_IP;
+                       ipsec_policy = IP_IPSEC_POLICY;
+                       break;
+               }
+               case AF_INET6:
+               {
+                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+                       sin6->sin6_family = AF_INET6;
+                       memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
+                       sin6->sin6_port = htons(port);
+                       ip_proto = IPPROTO_IPV6;
+                       ipsec_policy = IPV6_IPSEC_POLICY;
+                       break;
+               }
+               default:
+                       return 0;
        }
        
-       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+       skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+       if (skt < 0)
        {
-               this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on send socket!");
-               close(fd);
-               return FAILED;
+               this->logger->log(this->logger, ERROR, "could not open send socket: %s",
+                                                 strerror(errno));
+               return 0;
+       }
+       
+       if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+       {
+               this->logger->log(this->logger, ERROR, 
+                                                 "unable to set SO_REUSEADDR on send socket: %s",
+                                                 strerror(errno));
+               close(skt);
+               return 0;
        }
        
        /* bypass outgoung IKE traffic on send socket */
@@ -365,44 +562,80 @@ static status_t setup_send_socket(private_socket_t *this, u_int16_t port, int *s
        policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
        policy.sadb_x_policy_reserved = 0;
        policy.sadb_x_policy_id = 0;
-       /* TODO: use IPPROTO_IPV6/IPV6_IPSEC_POLICY for IPv6 sockets */
-       if (setsockopt(fd, IPPROTO_IP, IP_IPSEC_POLICY, &policy, sizeof(policy)) < 0)
+       
+       if (setsockopt(skt, ip_proto, ipsec_policy, &policy, sizeof(policy)) < 0)
        {
-               this->logger->log(this->logger, ERROR, "unable to set IPSEC_POLICY on send socket!");
-               close(fd);
-               return FAILED;
+               this->logger->log(this->logger, ERROR, 
+                                                 "unable to set IPSEC_POLICY on send socket: %s",
+                                                 strerror(errno));
+               close(skt);
+               return 0;
        }
+       
        /* We don't receive packets on the send socket, but we need a INBOUND policy.
         * Otherwise, UDP decapsulation does not work!!! */
        policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
-       if (setsockopt(fd, IPPROTO_IP, IP_IPSEC_POLICY, &policy, sizeof(policy)) < 0)
+       if (setsockopt(skt, ip_proto, ipsec_policy, &policy, sizeof(policy)) < 0)
        {
-               this->logger->log(this->logger, ERROR, "unable to set IPSEC_POLICY on send socket!");
-               close(fd);
-               return FAILED;
+               this->logger->log(this->logger, ERROR,
+                                                 "unable to set IPSEC_POLICY on send socket: %s",
+                                                 strerror(errno));
+               close(skt);
+               return 0;
        }
        
        /* bind the send socket */
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = INADDR_ANY;
-       addr.sin_port = htons(port);
-       if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
+       if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0)
        {
-               this->logger->log(this->logger, ERROR, "unable to bind send socket: %s!", strerror(errno));
-               return FAILED;
+               this->logger->log(this->logger, ERROR, "unable to bind send socket: %s",
+                                                 strerror(errno));
+               close(skt);
+               return 0;
        }
-
-       *send_fd = fd;
-       return SUCCESS;
+       
+       /* enable UDP decapsulation globally */
+       if (setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
+       {
+               this->logger->log(this->logger, ERROR,
+                                                 "unable to set UDP_ENCAP: %s; NAT-T may fail",
+                                                 strerror(errno));
+       }
+       
+       return skt;
 }
 
 /**
- * Initialize all sub sockets
+ * open a socket to receive packets
  */
-static status_t initialize(private_socket_t *this)
+static int open_recv_socket(private_socket_t *this, int family)
 {
+       int skt;
+       int on = TRUE;
+       u_int proto_offset, ip_len, ip_proto, ipsec_policy, ip_pktinfo, udp_header, ike_header;
        struct sadb_x_policy policy;
-       int type = UDP_ENCAP_ESPINUDP;
+       
+       /* precalculate constants depending on address family */
+       switch (family)
+       {
+               case AF_INET:
+                       proto_offset = IP_PROTO_OFFSET;
+                       ip_len = IP_LEN;
+                       ip_proto = IPPROTO_IP;
+                       ip_pktinfo = IP_PKTINFO;
+                       ipsec_policy = IP_IPSEC_POLICY;
+                       break;
+               case AF_INET6:
+                       proto_offset = IP6_PROTO_OFFSET;
+                       ip_len = IP6_LEN;
+                       ip_proto = IPPROTO_IPV6;
+                       ip_pktinfo = IPV6_PKTINFO;
+                       ipsec_policy = IPV6_IPSEC_POLICY;
+                       break;
+               default:
+                       return 0;
+       }
+       udp_header = ip_len;
+       ike_header = ip_len + UDP_LEN;
        
        /* This filter code filters out all non-IKEv2 traffic on
         * a SOCK_RAW IP_PROTP_UDP socket. Handling of other
@@ -411,30 +644,30 @@ static status_t initialize(private_socket_t *this)
        struct sock_filter ikev2_filter_code[] =
        {
                /* Protocol must be UDP */
-               BPF_STMT(BPF_LD+BPF_B+BPF_ABS, IP + 9),
+               BPF_STMT(BPF_LD+BPF_B+BPF_ABS, proto_offset),
                BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_UDP, 0, 15),
                /* Destination Port must be either port or natt_port */
-               BPF_STMT(BPF_LD+BPF_H+BPF_ABS, UDP + 2),
+               BPF_STMT(BPF_LD+BPF_H+BPF_ABS, udp_header + 2),
                BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->port, 1, 0),
                BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->natt_port, 5, 12),
                /* port */
                        /* IKE version must be 2.0 */
-                       BPF_STMT(BPF_LD+BPF_B+BPF_ABS, IKE + 17),
+                       BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET),
                        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10),
                        /* packet length is length in IKEv2 header + ip header + udp header */
-                       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, IKE + 24),
-                       BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, IP_LEN + UDP_LEN),
+                       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + IKE_LENGTH_OFFSET),
+                       BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN),
                        BPF_STMT(BPF_RET+BPF_A, 0),
                /* natt_port */
                        /* nat-t: check for marker */
-                       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, IKE),
+                       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header),
                        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5),
                        /* nat-t: IKE version must be 2.0 */
-                       BPF_STMT(BPF_LD+BPF_B+BPF_ABS, IKE + MARKER_LEN + 17),
+                       BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + MARKER_LEN + IKE_VERSION_OFFSET),
                        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 3),
                        /* nat-t: packet length is length in IKEv2 header + ip header + udp header + non esp marker */
-                       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, IKE + MARKER_LEN + 24),
-                       BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, IP_LEN + UDP_LEN + MARKER_LEN),
+                       BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + MARKER_LEN + IKE_LENGTH_OFFSET),
+                       BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN + MARKER_LEN),
                        BPF_STMT(BPF_RET+BPF_A, 0),
                /* packet doesn't match, ignore */
                BPF_STMT(BPF_RET+BPF_K, 0),
@@ -445,20 +678,37 @@ static status_t initialize(private_socket_t *this)
                sizeof(ikev2_filter_code) / sizeof(struct sock_filter),
                ikev2_filter_code
        };
-
-       /* set up raw socket */
-       this->raw_fd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
-       if (this->raw_fd < 0)
+       
+       /* set up raw socket */
+       skt = socket(family, SOCK_RAW, IPPROTO_UDP);
+       if (skt < 0)
        {
-               this->logger->log(this->logger, ERROR, "unable to create raw socket!");
-               return FAILED;
+               this->logger->log(this->logger, ERROR,
+                                                 "unable to create raw socket: %s",
+                                                 strerror(errno));
+               return 0;
        }
        
-       if (setsockopt(this->raw_fd, SOL_SOCKET, SO_ATTACH_FILTER, &ikev2_filter, sizeof(ikev2_filter)) < 0)
+       if (family == AF_INET)
        {
-               this->logger->log(this->logger, ERROR, "unable to attach IKEv2 filter to raw socket!");
-               close(this->raw_fd);
-               return FAILED;
+               if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER,
+                                       &ikev2_filter, sizeof(ikev2_filter)) < 0)
+               {
+                       this->logger->log(this->logger, ERROR, 
+                                                       "unable to attach IKEv2 filter to raw socket: %s",
+                                                       strerror(errno));
+                       close(skt);
+                       return 0;
+               }
+       }
+       
+       else if (setsockopt(skt, ip_proto, ip_pktinfo, &on, sizeof(on)) < 0)
+       {
+               this->logger->log(this->logger, ERROR, 
+                                                 "unable to set IPV6_PKTINFO on raw socket: %s",
+                                                 strerror(errno));
+               close(skt);
+               return 0;
        }
        
        /* bypass incomining IKE traffic on this socket */
@@ -468,35 +718,17 @@ static status_t initialize(private_socket_t *this)
        policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
        policy.sadb_x_policy_reserved = 0;
        policy.sadb_x_policy_id = 0;
-       /* TODO: use IPPROTO_IPV6/IPV6_IPSEC_POLICY for IPv6 sockets */
-       if (setsockopt(this->raw_fd, IPPROTO_IP, IP_IPSEC_POLICY, &policy, sizeof(policy)) < 0)
-       {
-               this->logger->log(this->logger, ERROR, "unable to set IPSEC_POLICY on raw socket!");
-               close(this->raw_fd);
-               return FAILED;
-       }
-       
-       /* setup the send sockets */
-       if (setup_send_socket(this, this->port, &this->send_fd) != SUCCESS)
-       {
-               this->logger->log(this->logger, ERROR, "unable to setup send socket on port %d!", this->port);
-               return FAILED;
-       }
-       if (setup_send_socket(this, this->natt_port, &this->natt_fd) != SUCCESS)
-       {
-               this->logger->log(this->logger, ERROR, "unable to setup send socket on port %d!", this->natt_port);
-               return FAILED;
-       }
        
-       /* enable UDP decapsulation globally */
-       if (setsockopt(this->natt_fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
+       if (setsockopt(skt, ip_proto, ipsec_policy, &policy, sizeof(policy)) < 0)
        {
-               this->logger->log(this->logger, ERROR,
-                                                 "unable to set UDP_ENCAP on NAT-T socket: %s; NAT-T may fail",
+               this->logger->log(this->logger, ERROR, 
+                                                 "unable to set IPSEC_POLICY on raw socket: %s",
                                                  strerror(errno));
+               close(skt);
+               return 0;
        }
        
-       return SUCCESS;
+       return skt;
 }
 
 /**
@@ -504,9 +736,30 @@ static status_t initialize(private_socket_t *this)
  */
 static void destroy(private_socket_t *this)
 {
-       close(this->natt_fd);
-       close(this->send_fd);
-       close(this->raw_fd);
+       if (this->recv4)
+       {
+               close(this->recv4);
+       }
+       if (this->recv6)
+       {
+               close(this->recv6);
+       }
+       if (this->send4)
+       {
+               close(this->send4);
+       }
+       if (this->send6)
+       {
+               close(this->send6);
+       }
+       if (this->send4_natt)
+       {
+               close(this->send4_natt);
+       }
+       if (this->send6_natt)
+       {
+               close(this->send6_natt);
+       }
        free(this);
 }
 
@@ -528,12 +781,72 @@ socket_t *socket_create(u_int16_t port, u_int16_t natt_port)
        
        this->port = port;
        this->natt_port = natt_port;
+       this->recv4 = 0;
+       this->recv6 = 0;
+       this->send4 = 0;
+       this->send6 = 0;
+       this->send4_natt = 0;
+       this->send6_natt = 0;
        
-       if (initialize(this) != SUCCESS)
+       this->recv4 = open_recv_socket(this, AF_INET);
+       if (this->recv4 == 0)
        {
-               free(this);
-               charon->kill(charon, "could not init socket!");
+               this->logger->log(this->logger, ERROR, 
+                                                 "could not open IPv4 receive socket, IPv4 disabled");
        }
-
+       else
+       {
+               this->send4 = open_send_socket(this, AF_INET, this->port);
+               if (this->send4 == 0)
+               {
+                       this->logger->log(this->logger, ERROR, 
+                                                         "could not open IPv4 send socket, IPv4 disabled");
+                       close(this->recv4);
+               }
+               else
+               {
+                       this->send4_natt = open_send_socket(this, AF_INET, this->natt_port);
+                       if (this->send4_natt == 0)
+                       {
+                               this->logger->log(this->logger, ERROR, 
+                                                                 "could not open IPv4 NAT-T send socket");
+                       }
+               }
+       }
+       
+       this->recv6 = open_recv_socket(this, AF_INET6);
+       if (this->recv6 == 0)
+       {
+               this->logger->log(this->logger, ERROR, 
+                                                 "could not open IPv6 receive socket, IPv6 disabled");
+       }
+       else
+       {
+               this->send6 = open_send_socket(this, AF_INET6, this->port);
+               if (this->send4 == 0)
+               {
+                       this->logger->log(this->logger, ERROR, 
+                                                         "could not open IPv6 send socket, IPv6 disabled");
+                       close(this->recv6);
+               }
+               else
+               {
+                       this->send6_natt = open_send_socket(this, AF_INET, this->natt_port);
+                       if (this->send6_natt == 0)
+                       {
+                               this->logger->log(this->logger, ERROR, 
+                                                                 "could not open IPv6 NAT-T send socket");
+                       }
+               }
+       }
+       
+       if (!(this->send4 || this->send6))
+       {
+               this->logger->log(this->logger, ERROR,
+                                                 "could not create any sockets");
+               destroy(this);
+               charon->kill(charon, "socket initialization failed");
+       }
+       
        return (socket_t*)this;
 }
index 9d74651..212a55c 100644 (file)
@@ -57,8 +57,6 @@ typedef struct socket_t socket_t;
  * @b Constructors:
  * - socket_create()
  * 
- * @todo add IPv6 support
- * 
  * @ingroup network
  */
 struct socket_t {
index 549d062..81e0366 100644 (file)
@@ -83,6 +83,7 @@ static void send_notify_response(private_incoming_packet_job_t *this,
        response->set_request(response, FALSE);
        response->set_message_id(response, 0);
        response->set_ike_sa_id(response, ike_sa_id);
+       ike_sa_id->destroy(ike_sa_id);
        notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
        response->add_payload(response, (payload_t *)notify);
        /* generation may fail, as most messages need a crypter/signer.
@@ -96,7 +97,6 @@ static void send_notify_response(private_incoming_packet_job_t *this,
                                          mapping_find(notify_type_m, type)); 
        charon->send_queue->add(charon->send_queue, packet);
        response->destroy(response);
-       ike_sa_id->destroy(ike_sa_id);
        return;
 }
 
@@ -114,7 +114,7 @@ static status_t execute(private_incoming_packet_job_t *this)
        message = message_create_from_packet(this->packet->clone(this->packet));
        src = message->get_source(message);
        dst = message->get_destination(message);
-       this->logger->log(this->logger, CONTROL, "received packet: from %s:%d to %s:%d",
+       this->logger->log(this->logger, CONTROL, "received packet: from %s[%d] to %s[%d]",
                                          src->get_string(src), src->get_port(src),
                                          dst->get_string(dst), dst->get_port(dst));
        
index a24308b..985cf77 100644 (file)
@@ -111,7 +111,7 @@ static void add(private_send_queue_t *this, packet_t *packet)
        
        src = packet->get_source(packet);
        dst = packet->get_destination(packet);
-       this->logger->log(this->logger, CONTROL, "sending packet: from %s:%d to %s:%d",
+       this->logger->log(this->logger, CONTROL, "sending packet: from %s[%d] to %s[%d]",
                                          src->get_string(src), src->get_port(src),
                                          dst->get_string(dst), dst->get_port(dst));
        
index 1357347..fe8e052 100644 (file)
@@ -1784,13 +1784,13 @@ static status_t delete_(private_ike_sa_t *this)
                case IKE_ESTABLISHED:
                {
                        delete_ike_sa_t *delete_ike_sa;
-                       delete_ike_sa = delete_ike_sa_create(&this->public);
                        if (this->transaction_out)
                        {
                                /* already a transaction in progress. As this may hang
                                * around a while, we don't inform the other peer. */
                                return DESTROY_ME;
                        }
+                       delete_ike_sa = delete_ike_sa_create(&this->public);
                        return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
                }
                case IKE_CREATED:
@@ -1956,8 +1956,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
        this->name = strdup("(uninitialized)");
        this->child_sas = linked_list_create();
-       this->my_host = host_create(AF_INET, "0.0.0.0", 0);
-       this->other_host = host_create(AF_INET, "0.0.0.0", 0);
+       this->my_host = host_create_from_string("0.0.0.0", 0);
+       this->other_host = host_create_from_string("0.0.0.0", 0);
        this->my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
        this->other_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
        this->crypter_in = NULL;
index c5e50a8..5da0a14 100644 (file)
@@ -375,6 +375,8 @@ static status_t get_request(private_ike_sa_init_t *this, message_t **result)
                list = charon->socket->create_local_address_list(charon->socket);
                while (list->remove_first(list, (void**)&host) == SUCCESS)
                {
+                       /* TODO: should we only include NAT payloads for addresses
+                        * of used address family? */
                        notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
                        host->destroy(host);
                        request->add_payload(request, (payload_t*)notify);
index 9ca821f..b090703 100644 (file)
@@ -889,42 +889,37 @@ static void ts2subnet(traffic_selector_t* ts,
        /* there is no way to do this cleanly, as the address range may
         * be anything else but a subnet. We use from_addr as subnet 
         * and try to calculate a usable subnet mask.
-        */
-       chunk_t chunk;
+       */
+       int byte, bit;
+       bool found = FALSE;
+       chunk_t from, to;
+       size_t size = (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) ? 4 : 16;
        
-       chunk = ts->get_from_address(ts);
-       memcpy(net, chunk.ptr, chunk.len);
+       from = ts->get_from_address(ts);
+       to = ts->get_to_address(ts);
        
-       switch (ts->get_type(ts))
+       *mask = (size * 8);
+       /* go trough all bits of the addresses, beginning in the front.
+        * As longer as they equal, the subnet gets larger */
+       for (byte = 0; byte < size; byte++)
        {
-               case TS_IPV4_ADDR_RANGE:
+               for (bit = 7; bit >= 0; bit--)
                {
-                       u_int32_t from, to, bit;
-                       
-                       from = *(u_int32_t*)chunk.ptr;
-                       chunk_free(&chunk);
-                       chunk = ts->get_to_address(ts);
-                       to = *(u_int32_t*)chunk.ptr;
-                       chunk_free(&chunk);
-                       for (bit = 0; bit < 32; bit++)
+                       if ((1<<bit & from.ptr[byte]) != (1<<bit & to.ptr[byte]))
                        {
-                               if ((1<<bit & from) != (1<<bit & to))
-                               {
-                                       *mask = bit;
-                                       return;
-                               }
+                               *mask = ((7 - bit) + (byte * 8));
+                               found = TRUE;
+                               break;
                        }
-                       *mask = 32;
-                       return;
                }
-               case TS_IPV6_ADDR_RANGE:
-               default:
+               if (found)
                {
-                       /* TODO: IPV6 support */
-                       *mask = 0;
-                       return;
+                       break;
                }
        }
+       memcpy(net, from.ptr, from.len);
+       chunk_free(&from);
+       chunk_free(&to);
 }
 
 /**
@@ -1075,6 +1070,7 @@ static status_t add_policy(private_kernel_interface_t *this,
        tmpl->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP;
        tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
        tmpl->mode = TRUE;
+       tmpl->family = src->get_family(src);
        
        host2xfrm(src, &tmpl->saddr);
        host2xfrm(dst, &tmpl->id.daddr);
index a705950..9f16a1d 100644 (file)
@@ -76,8 +76,7 @@ static void send_packets(private_sender_t * this)
                status = charon->socket->send(charon->socket, current_packet);
                if (status != SUCCESS)
                {
-                       this->logger->log(this->logger, ERROR, "Sending failed, socket returned %s", 
-                                                               mapping_find(status_m, status));
+                       this->logger->log(this->logger, ERROR, "Sending packet failed");
                }
                current_packet->destroy(current_packet);
        }
index c383774..b095b60 100755 (executable)
@@ -186,21 +186,38 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
        pop_string(msg, &msg->add_conn.algorithms.ike);
        pop_string(msg, &msg->add_conn.algorithms.esp);
        
-       this->logger->log(this->logger, CONTROL, "received stroke: add connection \"%s\"", msg->add_conn.name);
-                               
+       this->logger->log(this->logger, CONTROL, 
+                                         "received stroke: add connection \"%s\"", msg->add_conn.name);
+       
+       this->logger->log(this->logger, CONTROL|LEVEL2, "conn %s", msg->add_conn.name);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  right=%s", msg->add_conn.me.address);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  left=%s", msg->add_conn.other.address);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  rightsubnet=%s", msg->add_conn.me.subnet);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  leftsubnet=%s", msg->add_conn.other.subnet);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  rightid=%s", msg->add_conn.me.id);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  leftid=%s", msg->add_conn.other.id);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  rightcert=%s", msg->add_conn.me.cert);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  leftcert=%s", msg->add_conn.other.cert);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  rightca=%s", msg->add_conn.me.ca);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  leftca=%s", msg->add_conn.other.ca);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  ike=%s", msg->add_conn.algorithms.ike);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "  esp=%s", msg->add_conn.algorithms.esp);
+       
        my_host = msg->add_conn.me.address?
-                         host_create(AF_INET, msg->add_conn.me.address, IKE_PORT) : NULL;
+                         host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL;
        if (my_host == NULL)
        {
-               this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.me.address);
+               this->stroke_logger->log(this->stroke_logger, ERROR, 
+                                                                "invalid host: %s", msg->add_conn.me.address);
                return;
        }
 
        other_host = msg->add_conn.other.address ?
-                                host_create(AF_INET, msg->add_conn.other.address, IKE_PORT) : NULL;
+                       host_create_from_string(msg->add_conn.other.address, IKE_PORT) : NULL;
        if (other_host == NULL)
        {
-               this->stroke_logger->log(this->stroke_logger, ERROR, "invalid host: %s", msg->add_conn.other.address);
+               this->stroke_logger->log(this->stroke_logger, ERROR, 
+                                                                "invalid host: %s", msg->add_conn.other.address);
                my_host->destroy(my_host);
                return;
        }
@@ -210,7 +227,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
                stroke_end_t tmp_end;
                host_t *tmp_host;
 
-               this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, "left is other host, swapping ends");
+               this->stroke_logger->log(this->stroke_logger, CONTROL|LEVEL1, 
+                                                                "left is other host, swapping ends");
 
                tmp_host = my_host;
                my_host = other_host;
@@ -222,40 +240,45 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
        }
        else if (!charon->socket->is_local_address(charon->socket, my_host))
        {
-               this->stroke_logger->log(this->stroke_logger, ERROR, "left nor right host is our side, aborting");
+               this->stroke_logger->log(this->stroke_logger, ERROR, 
+                                                                "left nor right host is our side, aborting");
                goto destroy_hosts;
        }
 
        my_id = identification_create_from_string(msg->add_conn.me.id ?
-                                                                                         msg->add_conn.me.id : msg->add_conn.me.address);
+                                               msg->add_conn.me.id : msg->add_conn.me.address);
        if (my_id == NULL)
        {
-               this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.me.id);
+               this->stroke_logger->log(this->stroke_logger, ERROR, 
+                                                                "invalid id: %s", msg->add_conn.me.id);
                goto destroy_hosts;
        }
 
        other_id = identification_create_from_string(msg->add_conn.other.id ?
-                                                                                                msg->add_conn.other.id : msg->add_conn.other.address);
+                                               msg->add_conn.other.id : msg->add_conn.other.address);
        if (other_id == NULL)
        {
-               this->stroke_logger->log(this->stroke_logger, ERROR, "invalid id: %s", msg->add_conn.other.id);
+               this->stroke_logger->log(this->stroke_logger, ERROR, 
+                                                                "invalid id: %s", msg->add_conn.other.id);
                my_id->destroy(my_id);
                goto destroy_hosts;
        }
        
-       my_subnet = host_create(AF_INET, msg->add_conn.me.subnet ?
-                                                                        msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
+       my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
+                                       msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
        if (my_subnet == NULL)
        {
-               this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
+               this->stroke_logger->log(this->stroke_logger, ERROR, 
+                                                                "invalid subnet: %s", msg->add_conn.me.subnet);
                goto destroy_ids;
        }
        
-       other_subnet = host_create(AF_INET, msg->add_conn.other.subnet ?
-                                                                               msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
+       other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
+                                       msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
        if (other_subnet == NULL)
        {
-               this->stroke_logger->log(this->stroke_logger, ERROR, "invalid subnet: %s", msg->add_conn.me.subnet);
+               this->stroke_logger->log(this->stroke_logger, ERROR, 
+                                                                "invalid subnet: %s", msg->add_conn.me.subnet);
                my_subnet->destroy(my_subnet);
                goto destroy_ids;
        }
index 763358e..d0f4f96 100644 (file)
@@ -39,11 +39,6 @@ struct private_host_t {
        host_t public;
        
        /**
-        * Address family to use, such as AF_INET or AF_INET6
-        */
-       int family;
-       
-       /**
         * string representation of host
         */
        char *string;
@@ -52,8 +47,14 @@ struct private_host_t {
         * low-lewel structure, wich stores the address
         */
        union {
+               /** generic type */
                struct sockaddr address;
+               /** maximux sockaddr size */
+               struct sockaddr_storage address_max;
+               /** IPv4 address */
                struct sockaddr_in address4;
+               /** IPv6 address */
+               struct sockaddr_in6 address6;
        };
        /**
         * length of address structure
@@ -83,17 +84,24 @@ static socklen_t *get_sockaddr_len(private_host_t *this)
  */
 static bool is_anyaddr(private_host_t *this)
 {
-       switch (this->family) 
+       switch (this->address.sa_family) 
        {
-               case AF_INET: 
+               case AF_INET:
                {
-                       static u_int8_t default_route[4] = {0x00, 0x00, 0x00, 0x00};
-                       
-                       return !memcmp(default_route, &(this->address4.sin_addr.s_addr), 4);
+                       u_int8_t default_route[4];
+                       memset(default_route, 0, sizeof(default_route));
+                       return memeq(default_route, &(this->address4.sin_addr.s_addr),
+                                                sizeof(default_route));
+               }
+               case AF_INET6:
+               {
+                       u_int8_t default_route[16];
+                       memset(default_route, 0, sizeof(default_route));
+                       return memeq(default_route, &(this->address6.sin6_addr.s6_addr),
+                                                sizeof(default_route));
                }
                default:
                {
-                       /* empty chunk is returned */
                        return FALSE;
                }       
        }
@@ -104,25 +112,51 @@ static bool is_anyaddr(private_host_t *this)
  */
 static char *get_string(private_host_t *this)
 {
-       switch (this->family) 
+       return this->string;
+}
+
+/**
+ * Compute the string value
+ */
+static void set_string(private_host_t *this)
+{
+       if (is_anyaddr(this))
        {
-               case AF_INET: 
+               this->string = strdup("%any");
+               return;
+       }
+       
+       switch (this->address.sa_family) 
+       {
+               case AF_INET:
+               case AF_INET6:
                {
-                       char *string;
-                       /* we need to clone it, since inet_ntoa overwrites 
-                        * internal buffer on subsequent calls
-                        */
-                       if (this->string == NULL)
+                       char buffer[INET6_ADDRSTRLEN];
+                       void *address;
+                       
+                       if (this->address.sa_family == AF_INET)
                        {
-                               string = is_anyaddr(this)? "%any" : inet_ntoa(this->address4.sin_addr);
-                               this->string = malloc(strlen(string)+1);
-                               strcpy(this->string, string);
+                               address = &this->address4.sin_addr;
                        }
-                       return this->string;
+                       else
+                       {
+                               address = &this->address6.sin6_addr;
+                       }
+                       
+                       if (inet_ntop(this->address.sa_family, address,
+                                                 buffer, sizeof(buffer)) != NULL)
+                       {
+                               this->string = strdup(buffer);
+                       }
+                       else
+                       {
+                               this->string = strdup("(address conversion failed)");
+                       }
+                       return;
                }
                default:
                {
-                       return "(family not supported)";
+                       this->string = strdup("(family not supported)");
                }
        }
 }
@@ -134,17 +168,23 @@ static chunk_t get_address(private_host_t *this)
 {
        chunk_t address = CHUNK_INITIALIZER;
        
-       switch (this->family) 
+       switch (this->address.sa_family) 
        {
-               case AF_INET: 
+               case AF_INET:
                {
-                       /* allocate 4 bytes for IPv4 address*/
                        address.ptr = (char*)&(this->address4.sin_addr.s_addr);
                        address.len = 4;
+                       return address;
+               }
+               case AF_INET6:
+               {
+                       address.ptr = (char*)&(this->address6.sin6_addr.s6_addr);
+                       address.len = 16;
+                       return address;
                }
                default:
                {
-                       /* empty chunk is returned */
+                       /* return empty chunk */
                        return address;
                }
        }
@@ -155,7 +195,7 @@ static chunk_t get_address(private_host_t *this)
  */
 static int get_family(private_host_t *this)
 {
-       return this->family;    
+       return this->address.sa_family;
 }
 
 /**
@@ -163,12 +203,16 @@ static int get_family(private_host_t *this)
  */
 static u_int16_t get_port(private_host_t *this)
 {
-       switch (this->family) 
+       switch (this->address.sa_family) 
        {
-               case AF_INET: 
+               case AF_INET:
                {
                        return ntohs(this->address4.sin_port);
                }
+               case AF_INET6:
+               {
+                       return ntohs(this->address6.sin6_port);
+               }
                default:
                {
                        return 0;
@@ -181,15 +225,21 @@ static u_int16_t get_port(private_host_t *this)
  */
 static void set_port(private_host_t *this, u_int16_t port)
 {
-       switch (this->family)
+       switch (this->address.sa_family)
        {
                case AF_INET:
                {
                        this->address4.sin_port = htons(port);
+                       break;
+               }
+               case AF_INET6:
+               {
+                       this->address6.sin6_port = htons(port);
+                       break;
                }
                default:
                {
-                       /*TODO*/
+                       break;
                }
        }
 }
@@ -201,12 +251,10 @@ static private_host_t *clone(private_host_t *this)
 {
        private_host_t *new = malloc_thing(private_host_t);
        
-               
        memcpy(new, this, sizeof(private_host_t));
        if (this->string)
        {
-               new->string = malloc(strlen(this->string)+1);
-               strcpy(new->string, this->string);
+               new->string = strdup(this->string);
        }
        return new;
 }
@@ -216,17 +264,38 @@ static private_host_t *clone(private_host_t *this)
  */
 static bool ip_equals(private_host_t *this, private_host_t *other)
 {
-       switch (this->family)
+       if (this->address.sa_family != other->address.sa_family)
+       {
+               /* 0.0.0.0 and ::0 are equal */
+               if (is_anyaddr(this) && is_anyaddr(other))
+               {
+                       return TRUE;
+               }
+               
+               return FALSE;
+       }
+       
+       switch (this->address.sa_family)
        {
-               /* IPv4 */
                case AF_INET:
                {
-                       if ((this->address4.sin_family == other->address4.sin_family) &&
-                               (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr))
+                       if (memeq(&this->address4.sin_addr, &other->address4.sin_addr,
+                                         sizeof(this->address4.sin_addr)))
                        {
-                               return TRUE;    
+                               return TRUE;
                        }
+                       break;
                }
+               case AF_INET6:
+               {
+                       if (memeq(&this->address6.sin6_addr, &other->address6.sin6_addr,
+                                         sizeof(this->address6.sin6_addr)))
+                       {
+                               return TRUE;
+                       }
+               }
+               default:
+                       break;
        }
        return FALSE;
 }
@@ -234,20 +303,20 @@ static bool ip_equals(private_host_t *this, private_host_t *other)
 /**
  * Implements host_t.get_differences
  */
-static host_diff_t get_differences(private_host_t *this, private_host_t *other)
+static host_diff_t get_differences(host_t *this, host_t *other)
 {
        host_diff_t ret = HOST_DIFF_NONE;
        
-       if (!this->public.ip_equals(&this->public, &other->public))
+       if (!this->ip_equals(this, other))
        {
                ret |= HOST_DIFF_ADDR;
        }
 
-       if (this->public.get_port(&this->public) != other->public.get_port(&other->public))
+       if (this->get_port(this) != other->get_port(other))
        {
                ret |= HOST_DIFF_PORT;
        }
-
+       
        return ret;
 }
 
@@ -256,18 +325,31 @@ static host_diff_t get_differences(private_host_t *this, private_host_t *other)
  */
 static bool equals(private_host_t *this, private_host_t *other)
 {
-       switch (this->family)
+       if (!ip_equals(this, other))
+       {
+               return FAILED;
+       }
+       
+       switch (this->address.sa_family)
        {
-               /* IPv4 */
                case AF_INET:
                {
-                       if ((this->address4.sin_family == other->address4.sin_family) &&
-                               (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr) &&
-                               (this->address4.sin_port == other->address4.sin_port))
+                       if (this->address4.sin_port == other->address4.sin_port)
+                       {
+                               return TRUE;
+                       }
+                       break;
+               }
+               case AF_INET6:
+               {
+                       if (this->address6.sin6_port == other->address6.sin6_port)
                        {
-                               return TRUE;    
+                               return TRUE;
                        }
+                       break;
                }
+               default:
+                       break;
        }
        return FALSE;
 }
@@ -296,7 +378,7 @@ static private_host_t *host_create_empty(void)
        this->public.get_address = (chunk_t (*) (host_t *)) get_address;
        this->public.get_port = (u_int16_t (*) (host_t *))get_port;
        this->public.set_port = (void (*) (host_t *,u_int16_t))set_port;
-       this->public.get_differences = (host_diff_t (*) (host_t *,host_t *)) get_differences;
+       this->public.get_differences = get_differences;
        this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals;
        this->public.equals = (bool (*) (host_t *,host_t *)) equals;
        this->public.is_anyaddr = (bool (*) (host_t *)) is_anyaddr;
@@ -314,27 +396,88 @@ host_t *host_create(int family, char *address, u_int16_t port)
 {
        private_host_t *this = host_create_empty();
        
-       this->family = family;
+       this->address.sa_family = family;
 
        switch (family)
        {
-               /* IPv4 */
                case AF_INET:
                {
-                       this->address4.sin_family = AF_INET;
-                       this->address4.sin_addr.s_addr = inet_addr(address);
+                       if (inet_pton(family, address, &this->address4.sin_addr) <=0)
+                       {
+                               break;
+                       }
                        this->address4.sin_port = htons(port);
                        this->socklen = sizeof(struct sockaddr_in);
-                       return &(this->public);
+                       set_string(this);
+                       return &this->public;
+               }
+               case AF_INET6:
+               {
+                       if (inet_pton(family, address, &this->address6.sin6_addr) <=0)
+                       {
+                               break;
+                       }
+                       this->address6.sin6_port = htons(port);
+                       this->socklen = sizeof(struct sockaddr_in6);
+                       set_string(this);
+                       return &this->public;
                }
                default:
                {
-                       free(this);
-                       return NULL;
-
+                       break;
                }
        }
+       free(this);
+       return NULL;
+}
+
+/*
+ * Described in header.
+ */
+host_t *host_create_from_string(char *string, u_int16_t port)
+{
+       private_host_t *this = host_create_empty();
        
+       if (strchr(string, '.'))
+       {
+               this->address.sa_family = AF_INET;
+       }
+       else
+       {
+               this->address.sa_family = AF_INET6;
+       }
+
+       switch (this->address.sa_family)
+       {
+               case AF_INET:
+               {
+                       if (inet_pton(AF_INET, string, &this->address4.sin_addr) <=0)
+                       {
+                               break;
+                       }
+                       this->address4.sin_port = htons(port);
+                       this->socklen = sizeof(struct sockaddr_in);
+                       set_string(this);
+                       return &this->public;
+               }
+               case AF_INET6:
+               {
+                       if (inet_pton(AF_INET6, string, &this->address6.sin6_addr) <=0)
+                       {
+                               break;
+                       }
+                       this->address6.sin6_port = htons(port);
+                       this->socklen = sizeof(struct sockaddr_in6);
+                       set_string(this);
+                       return &this->public;
+               }
+               default:
+               {
+                       break;
+               }
+       }
+       free(this);
+       return NULL;
 }
 
 /*
@@ -344,13 +487,12 @@ host_t *host_create_from_hdr(u_long address, u_short port)
 {
        private_host_t *this = host_create_empty();
        
-       this->family = AF_INET;
-
-       this->address4.sin_family = AF_INET;
+       this->address.sa_family = AF_INET;
        this->address4.sin_addr.s_addr = address;
        this->address4.sin_port = port;
        this->socklen = sizeof(struct sockaddr_in);
-       return &(this->public);
+       set_string(this);
+       return &this->public;
 }
 
 /*
@@ -360,22 +502,35 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port)
 {
        private_host_t *this = host_create_empty();
        
-       this->family = family;
+       this->address.sa_family = family;
        switch (family)
        {
-               /* IPv4 */
                case AF_INET:
                {
                        if (address.len != 4)
                        {
-                               break;  
+                               break;
                        }
-                       this->address4.sin_family = AF_INET;
-                       memcpy(&(this->address4.sin_addr.s_addr),address.ptr,4);
+                       memcpy(&(this->address4.sin_addr.s_addr), address.ptr,4);
                        this->address4.sin_port = htons(port);
                        this->socklen = sizeof(struct sockaddr_in);
+                       set_string(this);
                        return &(this->public);
                }
+               case AF_INET6:
+               {
+                       if (address.len != 16)
+                       {
+                               break;
+                       }
+                       memcpy(&(this->address6.sin6_addr.s6_addr), address.ptr, 16);
+                       this->address6.sin6_port = htons(port);
+                       this->socklen = sizeof(struct sockaddr_in6);
+                       set_string(this);
+                       return &this->public;
+               }
+               default:
+                       break;
        }
        free(this);
        return NULL;
@@ -386,20 +541,25 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port)
  */
 host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
 {
-       chunk_t address;
+       private_host_t *this = host_create_empty();
        
        switch (sockaddr->sa_family)
        {
-               /* IPv4 */
                case AF_INET:
+                       memcpy(&this->address4, sockaddr, sizeof(struct sockaddr_in));
+                       this->socklen = sizeof(struct sockaddr_in);
+                       set_string(this);
+                       return &this->public;
+               case AF_INET6:
                {
-                       struct sockaddr_in *sin = (struct sockaddr_in *)sockaddr;
-                       address.ptr = (void*)&(sin->sin_addr.s_addr);
-                       address.len = 4;
-                       return host_create_from_chunk(AF_INET, address, ntohs(sin->sin_port));
+                       memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6));
+                       this->socklen = sizeof(struct sockaddr_in6);
+                       set_string(this);
+                       return &this->public;
                }
                default:
-                       return NULL;
+                       break;
        }
+       free(this);
+       return NULL;
 }
-
index 54f3b55..32abe56 100644 (file)
@@ -191,21 +191,33 @@ struct host_t {
 
 /**
  * @brief Constructor to create a host_t object from an address string
- * 
- * Currently supports only IPv4!
+ *
  *
  * @param family               Address family to use for this object, such as AF_INET or AF_INET6
  * @param address              string of an address, such as "152.96.193.130"
  * @param port                 port number
  * @return                             
  *                                             - host_t object 
- *                                             - NULL, if family not supported.
+ *                                             - NULL, if family not supported/invalid string.
  * 
  * @ingroup network
  */
 host_t *host_create(int family, char *address, u_int16_t port);
 
 /**
+ * @brief Same as host_create(), but guesses the family.
+ *
+ * @param string               string of an address, such as "152.96.193.130"
+ * @param port                 port number
+ * @return                             
+ *                                             - host_t object 
+ *                                             - NULL, if string not an address.
+ * 
+ * @ingroup network
+ */
+host_t *host_create_from_string(char *string, u_int16_t port);
+
+/**
  * @brief Constructor to create a host_t object from raw header data
  *
  * only IPv4 (create host_create_from_hdr6 for IPv6)!
@@ -221,8 +233,6 @@ host_t *host_create_from_hdr(u_long address, u_short port);
 
 /**
  * @brief Constructor to create a host_t object from an address chunk
- * 
- * Currently supports only IPv4!
  *
  * @param family               Address family to use for this object, such as AF_INET or AF_INET6
  * @param address              address as 4 byte chunk_t in networ order
@@ -237,8 +247,6 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port);
 
 /**
  * @brief Constructor to create a host_t object from a sockaddr struct
- * 
- * Currently supports only IPv4!
  *
  * @param sockaddr             sockaddr struct which contains family, address and port
  * @return                             
index 68a25df..0c05eba 100644 (file)
@@ -106,14 +106,48 @@ static char* connection_name(starter_conn_t *conn)
        return conn->name;
 }
 
+static void ip_address2string(ip_address *addr, char *buffer, size_t len)
+{
+       switch (((struct sockaddr*)addr)->sa_family)
+       {
+               case AF_INET:
+               {
+                       struct sockaddr_in* sin = (struct sockaddr_in*)addr;
+                       if (inet_ntop(AF_INET, &sin->sin_addr, buffer, len))
+                       {
+                               return;
+                       }
+                       break;
+               }
+               case AF_INET6:
+               {
+                       struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
+                       if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer, len))
+                       {
+                               return;
+                       }
+                       break;
+               }
+               default:
+                       break;
+       }
+       /* failed */
+       snprintf(buffer, len, "0.0.0.0");
+}
+
+
 static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, starter_end_t *conn_end)
 {
+       char buffer[INET6_ADDRSTRLEN];
+       
        msg_end->id = push_string(msg, conn_end->id);
        msg_end->cert = push_string(msg, conn_end->cert);
        msg_end->ca = push_string(msg, conn_end->ca);
        msg_end->updown = push_string(msg, conn_end->updown);
-       msg_end->address = push_string(msg, inet_ntoa(conn_end->addr.u.v4.sin_addr));
-       msg_end->subnet = push_string(msg, inet_ntoa(conn_end->subnet.addr.u.v4.sin_addr));
+       ip_address2string(&conn_end->addr, buffer, sizeof(buffer));
+       msg_end->address = push_string(msg, buffer);
+       ip_address2string(&conn_end->subnet.addr, buffer, sizeof(buffer));
+       msg_end->subnet = push_string(msg, buffer);
        msg_end->subnet_mask = conn_end->subnet.maskbits;
        msg_end->sendcert = conn_end->sendcert;
        msg_end->protocol = conn_end->protocol;