diff options
author | Martin Willi <martin@strongswan.org> | 2006-08-30 17:12:56 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2006-08-30 17:12:56 +0000 |
commit | 48d9883a3ea3a7a04314940d94ade7d1d148553e (patch) | |
tree | 48f44c81574b673b80e890fd7fb4a5e916e6a25a | |
parent | 51d4876814f94a48c4a14182cb3bd0eea848b2f4 (diff) | |
download | strongswan-48d9883a3ea3a7a04314940d94ade7d1d148553e.tar.bz2 strongswan-48d9883a3ea3a7a04314940d94ade7d1d148553e.tar.xz |
initial support for IPv6 (more testing needed)
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
-rw-r--r-- | src/charon/config/traffic_selector.c | 336 | ||||
-rw-r--r-- | src/charon/daemon.c | 11 | ||||
-rw-r--r-- | src/charon/encoding/message.c | 3 | ||||
-rw-r--r-- | src/charon/encoding/payloads/traffic_selector_substructure.c | 9 | ||||
-rw-r--r-- | src/charon/network/socket.c | 591 | ||||
-rw-r--r-- | src/charon/network/socket.h | 2 | ||||
-rw-r--r-- | src/charon/queues/jobs/incoming_packet_job.c | 4 | ||||
-rw-r--r-- | src/charon/queues/send_queue.c | 2 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 6 | ||||
-rw-r--r-- | src/charon/sa/transactions/ike_sa_init.c | 2 | ||||
-rw-r--r-- | src/charon/threads/kernel_interface.c | 48 | ||||
-rw-r--r-- | src/charon/threads/sender.c | 3 | ||||
-rwxr-xr-x | src/charon/threads/stroke_interface.c | 59 | ||||
-rw-r--r-- | src/libstrongswan/utils/host.c | 312 | ||||
-rw-r--r-- | src/libstrongswan/utils/host.h | 22 | ||||
-rw-r--r-- | src/starter/starterstroke.c | 38 |
16 files changed, 1074 insertions, 374 deletions
diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c index 3d53d9072..24cf7eaad 100644 --- a/src/charon/config/traffic_selector.c +++ b/src/charon/config/traffic_selector.c @@ -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; } } diff --git a/src/charon/daemon.c b/src/charon/daemon.c index a5ac5c63e..68846fc2e 100644 --- a/src/charon/daemon.c +++ b/src/charon/daemon.c @@ -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); diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c index 29a210352..b4bede333 100644 --- a/src/charon/encoding/message.c +++ b/src/charon/encoding/message.c @@ -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; } diff --git a/src/charon/encoding/payloads/traffic_selector_substructure.c b/src/charon/encoding/payloads/traffic_selector_substructure.c index 2ac746403..6ca600e63 100644 --- a/src/charon/encoding/payloads/traffic_selector_substructure.c +++ b/src/charon/encoding/payloads/traffic_selector_substructure.c @@ -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 */ diff --git a/src/charon/network/socket.c b/src/charon/network/socket.c index aca48ec5e..e208624b5 100644 --- a/src/charon/network/socket.c +++ b/src/charon/network/socket.c @@ -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> @@ -46,13 +47,15 @@ /* 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 a 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; } diff --git a/src/charon/network/socket.h b/src/charon/network/socket.h index 9d74651da..212a55cde 100644 --- a/src/charon/network/socket.h +++ b/src/charon/network/socket.h @@ -57,8 +57,6 @@ typedef struct socket_t socket_t; * @b Constructors: * - socket_create() * - * @todo add IPv6 support - * * @ingroup network */ struct socket_t { diff --git a/src/charon/queues/jobs/incoming_packet_job.c b/src/charon/queues/jobs/incoming_packet_job.c index 549d062dd..81e0366c8 100644 --- a/src/charon/queues/jobs/incoming_packet_job.c +++ b/src/charon/queues/jobs/incoming_packet_job.c @@ -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)); diff --git a/src/charon/queues/send_queue.c b/src/charon/queues/send_queue.c index a24308b69..985cf77b7 100644 --- a/src/charon/queues/send_queue.c +++ b/src/charon/queues/send_queue.c @@ -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)); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 135734784..fe8e05207 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -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; diff --git a/src/charon/sa/transactions/ike_sa_init.c b/src/charon/sa/transactions/ike_sa_init.c index c5e50a843..5da0a144c 100644 --- a/src/charon/sa/transactions/ike_sa_init.c +++ b/src/charon/sa/transactions/ike_sa_init.c @@ -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); diff --git a/src/charon/threads/kernel_interface.c b/src/charon/threads/kernel_interface.c index 9ca821fa2..b09070390 100644 --- a/src/charon/threads/kernel_interface.c +++ b/src/charon/threads/kernel_interface.c @@ -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); diff --git a/src/charon/threads/sender.c b/src/charon/threads/sender.c index a705950a1..9f16a1d2c 100644 --- a/src/charon/threads/sender.c +++ b/src/charon/threads/sender.c @@ -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); } diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index c3837744c..b095b605c 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -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; } diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c index 763358e5c..d0f4f96b0 100644 --- a/src/libstrongswan/utils/host.c +++ b/src/libstrongswan/utils/host.c @@ -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; } - diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h index 54f3b55bb..32abe56a3 100644 --- a/src/libstrongswan/utils/host.h +++ b/src/libstrongswan/utils/host.h @@ -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 diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 68a25df90..0c05ebaf3 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -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; |