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
This commit is contained in:
Martin Willi
2006-08-30 17:12:56 +00:00
parent 51d4876814
commit 48d9883a3e
16 changed files with 1075 additions and 375 deletions
+240 -86
View File
@@ -53,17 +53,27 @@ struct private_traffic_selector_t {
u_int8_t protocol; u_int8_t protocol;
/** /**
* begin of address range, host order * begin of address range, network order
*/ */
union { 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 { 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];
}; };
/** /**
@@ -82,6 +92,60 @@ struct private_traffic_selector_t {
char *string; char *string;
}; };
/**
* 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 * internal generic constructor
*/ */
@@ -105,23 +169,13 @@ static void update_string(private_traffic_selector_t *this)
if (this->type == TS_IPV4_ADDR_RANGE) if (this->type == TS_IPV4_ADDR_RANGE)
{ {
u_int32_t from_no, to_no, bit; u_int8_t mask;
u_int8_t mask = 32;
/* build address string */ /* build address string */
from_no = htonl(this->from_addr_ipv4); inet_ntop(AF_INET, &this->from4, addr_str, sizeof(addr_str));
to_no = htonl(this->to_addr_ipv4);
inet_ntop(AF_INET, &from_no, addr_str, sizeof(addr_str));
/* build network mask string */ /* build network mask string */
for (bit = 0; bit < 32; bit++) mask = calc_netbits(this);
{
if ((1<<bit & from_no) != (1<<bit & to_no))
{
mask = bit;
break;
}
}
if (mask != 32) if (mask != 32)
{ {
snprintf(mask_str, sizeof(mask_str), "/%d", mask); snprintf(mask_str, sizeof(mask_str), "/%d", mask);
@@ -129,8 +183,17 @@ static void update_string(private_traffic_selector_t *this)
} }
else else
{ {
/* TODO: be a little bit more verbose ;-) */ u_int8_t mask;
snprintf(addr_str, sizeof(addr_str), "(IPv6 address range)");
/* 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 */ /* 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) 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) && if (this->type == other->type && (this->protocol == other->protocol ||
(this->protocol == other->protocol || this->protocol == 0 || other->protocol == 0)) this->protocol == 0 || other->protocol == 0))
{ {
u_int32_t from_addr, to_addr;
u_int16_t from_port, to_port; u_int16_t from_port, to_port;
u_char *from, *to;
u_int8_t protocol; u_int8_t protocol;
size_t size;
private_traffic_selector_t *new_ts; 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 */ /* calculate the maximum port range allowed for both */
from_port = max(this->from_port, other->from_port); from_port = max(this->from_port, other->from_port);
to_port = min(this->to_port, other->to_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; return NULL;
} }
/* select protocol, which is not zero */ /* select protocol, which is not zero */
protocol = max(this->protocol, other->protocol); protocol = max(this->protocol, other->protocol);
/* got a match, return it */ 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 = traffic_selector_create(protocol, this->type, from_port, to_port);
new_ts->from_addr_ipv4 = from_addr; new_ts->type = this->type;
new_ts->to_addr_ipv4 = to_addr; memcpy(new_ts->from, from, size);
new_ts->type = TS_IPV4_ADDR_RANGE; memcpy(new_ts->to, to, size);
update_string(new_ts); update_string(new_ts);
return &(new_ts->public); return &new_ts->public;
} }
return NULL; return NULL;
} }
@@ -256,16 +347,28 @@ static bool equals(private_traffic_selector_t *this, private_traffic_selector_t
{ {
return FALSE; 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 && return FALSE;
this->to_addr_ipv4 == other->to_addr_ipv4 && }
this->from_port == other->from_port && switch (this->type)
this->to_port == other->to_port && {
this->protocol == other->protocol) case TS_IPV4_ADDR_RANGE:
{ if (memeq(this->from4, other->from4, sizeof(this->from4)))
return TRUE; {
} return TRUE;
}
break;
case TS_IPV6_ADDR_RANGE:
if (memeq(this->from6, other->from6, sizeof(this->from6)))
{
return TRUE;
}
break;
default:
break;
} }
return FALSE; 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) 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) switch (this->type)
{ {
case TS_IPV4_ADDR_RANGE: case TS_IPV4_ADDR_RANGE:
{ {
u_int32_t network; from.len = sizeof(this->from4);
from_addr.len = sizeof(network); from.ptr = malloc(from.len);
from_addr.ptr = malloc(from_addr.len); memcpy(from.ptr, this->from4, from.len);
/* chunk must contain network order, convert! */
network = htonl(this->from_addr_ipv4);
memcpy(from_addr.ptr, &network, from_addr.len);
break; break;
} }
case TS_IPV6_ADDR_RANGE: case TS_IPV6_ADDR_RANGE:
{ {
from.len = sizeof(this->from6);
from.ptr = malloc(from.len);
memcpy(from.ptr, this->from6, from.len);
break; 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) 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) switch (this->type)
{ {
case TS_IPV4_ADDR_RANGE: case TS_IPV4_ADDR_RANGE:
{ {
u_int32_t network; to.len = sizeof(this->to4);
to_addr.len = sizeof(network); to.ptr = malloc(to.len);
to_addr.ptr = malloc(to_addr.len); memcpy(to.ptr, this->to4, to.len);
/* chunk must contain network order, convert! */
network = htonl(this->to_addr_ipv4);
memcpy(to_addr.ptr, &network, to_addr.len);
break; break;
} }
case TS_IPV6_ADDR_RANGE: case TS_IPV6_ADDR_RANGE:
{ {
to.len = sizeof(this->to6);
to.ptr = malloc(to.len);
memcpy(to.ptr, this->to6, to.len);
break; 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) static void update_address_range(private_traffic_selector_t *this, host_t *host)
{ {
if (host->get_family(host) == AF_INET && if (host->get_family(host) == AF_INET && this->type == TS_IPV4_ADDR_RANGE)
this->type == TS_IPV4_ADDR_RANGE)
{ {
if (this->from_addr_ipv4 == 0) if (this->from4[0] == 0)
{ {
chunk_t from = host->get_address(host); chunk_t from = host->get_address(host);
this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr)); memcpy(this->from4, from.ptr, from.len);
this->to_addr_ipv4 = this->from_addr_ipv4; memcpy(this->to4, from.ptr, from.len);
}
}
if (host->get_family(host) == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE)
{
if (this->from6[0] == 0 && this->from6[1] == 0 &&
this->from6[2] == 0 && this->from6[3] == 0)
{
chunk_t from = host->get_address(host);
memcpy(this->from6, from.ptr, from.len);
memcpy(this->to6, from.ptr, from.len);
} }
} }
update_string(this); update_string(this);
@@ -387,16 +499,22 @@ static traffic_selector_t *clone_(private_traffic_selector_t *this)
{ {
case TS_IPV4_ADDR_RANGE: case TS_IPV4_ADDR_RANGE:
{ {
clone->from_addr_ipv4 = this->from_addr_ipv4; memcpy(clone->from4, this->from4, sizeof(this->from4));
clone->to_addr_ipv4 = this->to_addr_ipv4; memcpy(clone->to4, this->to4, sizeof(this->to4));
update_string(clone); update_string(clone);
return &clone->public; return &clone->public;
} }
case TS_IPV6_ADDR_RANGE: 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: default:
{ {
free(this); /* unreachable */
return NULL; return &clone->public;
} }
} }
} }
@@ -413,7 +531,7 @@ static void destroy(private_traffic_selector_t *this)
/* /*
* see header * 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); 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: case TS_IPV4_ADDR_RANGE:
{ {
if (from_addr.len != 4 || to_addr.len != 4) if (from.len != 4 || to.len != 4)
{ {
free(this); free(this);
return NULL; return NULL;
} }
/* chunk contains network order, convert! */ memcpy(this->from4, from.ptr, from.len);
this->from_addr_ipv4 = ntohl(*((u_int32_t*)from_addr.ptr)); memcpy(this->to4, to.ptr, to.len);
this->to_addr_ipv4 = ntohl(*((u_int32_t*)to_addr.ptr));
break; break;
} }
case TS_IPV6_ADDR_RANGE: 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: default:
{ {
free(this); free(this);
@@ -459,19 +586,40 @@ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t ne
this->type = TS_IPV4_ADDR_RANGE; this->type = TS_IPV4_ADDR_RANGE;
from = net->get_address(net); from = net->get_address(net);
this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr)); memcpy(this->from4, from.ptr, from.len);
if (this->from_addr_ipv4 == 0) if (this->from4[0] == 0)
{ {
/* use /0 for 0.0.0.0 */ /* use /0 for 0.0.0.0 */
this->to_addr_ipv4 = ~0; this->to4[0] = ~0;
} }
else else
{ {
this->to_addr_ipv4 = this->from_addr_ipv4 | ((1 << (32 - netbits)) - 1); calc_range(this, netbits);
} }
break; break;
} }
case AF_INET6: 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: default:
{ {
free(this); free(this);
@@ -505,25 +653,31 @@ traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_ty
{ {
case TS_IPV4_ADDR_RANGE: 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); free(this);
return NULL; 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); free(this);
return NULL; 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; break;
} }
case TS_IPV6_ADDR_RANGE: case TS_IPV6_ADDR_RANGE:
{ {
free(this); if (inet_pton(AF_INET6, from_addr, (struct in6_addr*)this->from6) < 0)
return NULL; {
free(this);
return NULL;
}
if (inet_pton(AF_INET6, to_addr, (struct in6_addr*)this->to6) < 0)
{
free(this);
return NULL;
}
break;
} }
} }
+8 -3
View File
@@ -250,7 +250,10 @@ void signal_handler(int signal)
strings = backtrace_symbols(array, size); strings = backtrace_symbols(array, size);
logger = logger_manager->get_logger(logger_manager, DAEMON); 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++) 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"); 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; return this;
} }
@@ -405,7 +412,6 @@ int main(int argc, char *argv[])
fprintf(pid_file, "%d\n", getpid()); fprintf(pid_file, "%d\n", getpid());
fclose(pid_file); fclose(pid_file);
} }
/* log socket info */ /* log socket info */
list = charon->socket->create_local_address_list(charon->socket); list = charon->socket->create_local_address_list(charon->socket);
private_charon->logger->log(private_charon->logger, CONTROL, 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, private_charon->logger->log(private_charon->logger, CONTROL,
" %s", host->get_string(host)); " %s", host->get_string(host));
host->destroy(host); host->destroy(host);
} }
list->destroy(list); list->destroy(list);
+1 -2
View File
@@ -1062,8 +1062,7 @@ static status_t decrypt_payloads(private_message_t *this,crypter_t *crypter, sig
if (status != SUCCESS) if (status != SUCCESS)
{ {
this->logger->log(this->logger, ERROR, this->logger->log(this->logger, ERROR,
"encrypted payload could not be decrypted and parsed: %s", "encrypted payload could not be decrypted and parsed");
mapping_find(status_m, status));
iterator->destroy(iterator); iterator->destroy(iterator);
return PARSE_ERROR; return PARSE_ERROR;
} }
@@ -149,6 +149,15 @@ static status_t verify(private_traffic_selector_substructure_t *this)
break; break;
} }
case TS_IPV6_ADDR_RANGE: 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: default:
{ {
/* not supported ts type */ /* not supported ts type */
+448 -135
View File
@@ -33,6 +33,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/udp.h> #include <netinet/udp.h>
#include <linux/ipsec.h> #include <linux/ipsec.h>
#include <linux/filter.h> #include <linux/filter.h>
@@ -46,13 +47,15 @@
/* constants for packet handling */ /* constants for packet handling */
#define IP_LEN sizeof(struct iphdr) #define IP_LEN sizeof(struct iphdr)
#define IP6_LEN sizeof(struct ip6_hdr)
#define UDP_LEN sizeof(struct udphdr) #define UDP_LEN sizeof(struct udphdr)
#define MARKER_LEN sizeof(u_int32_t) #define MARKER_LEN sizeof(u_int32_t)
/* offsets for packet handling */ /* offsets for packet handling */
#define IP 0 #define IP_PROTO_OFFSET 9
#define UDP IP + IP_LEN #define IP6_PROTO_OFFSET 6
#define IKE UDP + UDP_LEN #define IKE_VERSION_OFFSET 17
#define IKE_LENGTH_OFFSET 24
/* from linux/in.h */ /* from linux/in.h */
#ifndef IP_IPSEC_POLICY #ifndef IP_IPSEC_POLICY
@@ -90,19 +93,34 @@ struct private_socket_t{
int natt_port; int natt_port;
/** /**
* raw socket (receiver) * raw receiver socket for IPv4
*/ */
int raw_fd; int recv4;
/** /**
* send socket on regular port * raw receiver socket for IPv6
*/ */
int send_fd; int recv6;
/** /**
* send socket on nat-t port * send socket on regular port for IPv4
*/ */
int natt_fd; int send4;
/**
* send socket on regular port for IPv6
*/
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 * logger for this socket
@@ -120,54 +138,180 @@ static status_t receiver(private_socket_t *this, packet_t **packet)
packet_t *pkt; packet_t *pkt;
struct iphdr *ip; struct iphdr *ip;
struct udphdr *udp; struct udphdr *udp;
host_t *source, *dest; host_t *source = NULL, *dest = NULL;
int bytes_read = 0; int bytes_read = 0;
int data_offset, oldstate; 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); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
bytes_read = recv(this->raw_fd, buffer, MAX_PACKET, 0); if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0)
{
pthread_setcancelstate(oldstate, NULL);
return FAILED;
}
pthread_setcancelstate(oldstate, NULL); pthread_setcancelstate(oldstate, NULL);
if (bytes_read < 0) if (FD_ISSET(this->recv4, &rfds))
{ {
this->logger->log(this->logger, ERROR, "error reading from socket: %s", strerror(errno)); /* 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; return FAILED;
} }
/* read source/dest from raw IP/UDP header */
ip = (struct iphdr*) buffer;
udp = (struct udphdr*) (buffer + IP_LEN);
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)
{
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);
/* return packet */ /* return packet */
*packet = pkt; *packet = pkt;
return SUCCESS; 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) status_t sender(private_socket_t *this, packet_t *packet)
{ {
int sport, fd; int sport, skt, family;
ssize_t bytes_sent; ssize_t bytes_sent;
chunk_t data, marked; chunk_t data, marked;
host_t *src, *dst; host_t *src, *dst;
@@ -185,50 +329,68 @@ status_t sender(private_socket_t *this, packet_t *packet)
dst = packet->get_destination(packet); dst = packet->get_destination(packet);
data = packet->get_data(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), src->get_string(src), src->get_port(src),
dst->get_string(dst), dst->get_port(dst)); dst->get_string(dst), dst->get_port(dst));
/* send data */ /* send data */
sport = src->get_port(src); sport = src->get_port(src);
family = dst->get_family(dst);
if (sport == this->port) 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) 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 */ /* NAT keepalives without marker */
if (data.len != 1 || data.ptr[0] != 0xFF) if (data.len != 1 || data.ptr[0] != 0xFF)
{ {
/* add non esp marker to packet */ /* add non esp marker to packet */
if (data.len > MAX_PACKET - MARKER_LEN) 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; return FAILED;
} }
marked = chunk_alloc(data.len + MARKER_LEN); marked = chunk_alloc(data.len + MARKER_LEN);
memset(marked.ptr, 0, MARKER_LEN); memset(marked.ptr, 0, MARKER_LEN);
memcpy(marked.ptr + MARKER_LEN, data.ptr, data.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; data = marked;
} }
} }
else 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; 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))); dst->get_sockaddr(dst), *(dst->get_sockaddr_len(dst)));
if (bytes_sent != data.len) 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 FAILED;
} }
return SUCCESS; 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); host = host_create_from_sockaddr(cur->ifa_addr);
if (host) 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); 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; 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; struct sadb_x_policy policy;
int fd; int skt;
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); memset(&addr, 0, sizeof(addr));
if (fd < 0) /* precalculate constants depending on address family */
switch (family)
{ {
this->logger->log(this->logger, ERROR, "could not open IPv4 send socket!"); case AF_INET:
return FAILED; {
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!"); this->logger->log(this->logger, ERROR, "could not open send socket: %s",
close(fd); strerror(errno));
return FAILED; 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 */ /* 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_dir = IPSEC_DIR_OUTBOUND;
policy.sadb_x_policy_reserved = 0; policy.sadb_x_policy_reserved = 0;
policy.sadb_x_policy_id = 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!"); this->logger->log(this->logger, ERROR,
close(fd); "unable to set IPSEC_POLICY on send socket: %s",
return FAILED; strerror(errno));
close(skt);
return 0;
} }
/* We don't receive packets on the send socket, but we need a INBOUND policy. /* We don't receive packets on the send socket, but we need a INBOUND policy.
* Otherwise, UDP decapsulation does not work!!! */ * Otherwise, UDP decapsulation does not work!!! */
policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; 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!"); this->logger->log(this->logger, ERROR,
close(fd); "unable to set IPSEC_POLICY on send socket: %s",
return FAILED; strerror(errno));
close(skt);
return 0;
} }
/* bind the send socket */ /* bind the send socket */
addr.sin_family = AF_INET; if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0)
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{ {
this->logger->log(this->logger, ERROR, "unable to bind send socket: %s!", strerror(errno)); this->logger->log(this->logger, ERROR, "unable to bind send socket: %s",
return FAILED; strerror(errno));
close(skt);
return 0;
} }
*send_fd = fd; /* enable UDP decapsulation globally */
return SUCCESS; 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; 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 /* This filter code filters out all non-IKEv2 traffic on
* a SOCK_RAW IP_PROTP_UDP socket. Handling of other * 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[] = struct sock_filter ikev2_filter_code[] =
{ {
/* Protocol must be UDP */ /* 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), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_UDP, 0, 15),
/* Destination Port must be either port or natt_port */ /* 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->port, 1, 0),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->natt_port, 5, 12), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, this->natt_port, 5, 12),
/* port */ /* port */
/* IKE version must be 2.0 */ /* 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), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x20, 0, 10),
/* packet length is length in IKEv2 header + ip header + udp header */ /* packet length is length in IKEv2 header + ip header + udp header */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, IKE + 24), 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_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN),
BPF_STMT(BPF_RET+BPF_A, 0), BPF_STMT(BPF_RET+BPF_A, 0),
/* natt_port */ /* natt_port */
/* nat-t: check for marker */ /* 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), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5),
/* nat-t: IKE version must be 2.0 */ /* 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), 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 */ /* 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_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_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN + MARKER_LEN),
BPF_STMT(BPF_RET+BPF_A, 0), BPF_STMT(BPF_RET+BPF_A, 0),
/* packet doesn't match, ignore */ /* packet doesn't match, ignore */
BPF_STMT(BPF_RET+BPF_K, 0), BPF_STMT(BPF_RET+BPF_K, 0),
@@ -446,19 +679,36 @@ static status_t initialize(private_socket_t *this)
ikev2_filter_code ikev2_filter_code
}; };
/* set up raw socket */ /* set up a raw socket */
this->raw_fd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP); skt = socket(family, SOCK_RAW, IPPROTO_UDP);
if (this->raw_fd < 0) if (skt < 0)
{ {
this->logger->log(this->logger, ERROR, "unable to create raw socket!"); this->logger->log(this->logger, ERROR,
return FAILED; "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!"); if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER,
close(this->raw_fd); &ikev2_filter, sizeof(ikev2_filter)) < 0)
return FAILED; {
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 */ /* 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_dir = IPSEC_DIR_INBOUND;
policy.sadb_x_policy_reserved = 0; policy.sadb_x_policy_reserved = 0;
policy.sadb_x_policy_id = 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 (setsockopt(skt, ip_proto, ipsec_policy, &policy, sizeof(policy)) < 0)
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)
{ {
this->logger->log(this->logger, ERROR, this->logger->log(this->logger, ERROR,
"unable to set UDP_ENCAP on NAT-T socket: %s; NAT-T may fail", "unable to set IPSEC_POLICY on raw socket: %s",
strerror(errno)); 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) static void destroy(private_socket_t *this)
{ {
close(this->natt_fd); if (this->recv4)
close(this->send_fd); {
close(this->raw_fd); 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); free(this);
} }
@@ -528,11 +781,71 @@ socket_t *socket_create(u_int16_t port, u_int16_t natt_port)
this->port = port; this->port = port;
this->natt_port = natt_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); this->logger->log(this->logger, ERROR,
charon->kill(charon, "could not init socket!"); "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; return (socket_t*)this;
-2
View File
@@ -57,8 +57,6 @@ typedef struct socket_t socket_t;
* @b Constructors: * @b Constructors:
* - socket_create() * - socket_create()
* *
* @todo add IPv6 support
*
* @ingroup network * @ingroup network
*/ */
struct socket_t { struct socket_t {
+2 -2
View File
@@ -83,6 +83,7 @@ static void send_notify_response(private_incoming_packet_job_t *this,
response->set_request(response, FALSE); response->set_request(response, FALSE);
response->set_message_id(response, 0); response->set_message_id(response, 0);
response->set_ike_sa_id(response, ike_sa_id); 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); notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
response->add_payload(response, (payload_t *)notify); response->add_payload(response, (payload_t *)notify);
/* generation may fail, as most messages need a crypter/signer. /* 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)); mapping_find(notify_type_m, type));
charon->send_queue->add(charon->send_queue, packet); charon->send_queue->add(charon->send_queue, packet);
response->destroy(response); response->destroy(response);
ike_sa_id->destroy(ike_sa_id);
return; 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)); message = message_create_from_packet(this->packet->clone(this->packet));
src = message->get_source(message); src = message->get_source(message);
dst = message->get_destination(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), src->get_string(src), src->get_port(src),
dst->get_string(dst), dst->get_port(dst)); dst->get_string(dst), dst->get_port(dst));
+1 -1
View File
@@ -111,7 +111,7 @@ static void add(private_send_queue_t *this, packet_t *packet)
src = packet->get_source(packet); src = packet->get_source(packet);
dst = packet->get_destination(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), src->get_string(src), src->get_port(src),
dst->get_string(dst), dst->get_port(dst)); dst->get_string(dst), dst->get_port(dst));
+3 -3
View File
@@ -1784,13 +1784,13 @@ static status_t delete_(private_ike_sa_t *this)
case IKE_ESTABLISHED: case IKE_ESTABLISHED:
{ {
delete_ike_sa_t *delete_ike_sa; delete_ike_sa_t *delete_ike_sa;
delete_ike_sa = delete_ike_sa_create(&this->public);
if (this->transaction_out) if (this->transaction_out)
{ {
/* already a transaction in progress. As this may hang /* already a transaction in progress. As this may hang
* around a while, we don't inform the other peer. */ * around a while, we don't inform the other peer. */
return DESTROY_ME; return DESTROY_ME;
} }
delete_ike_sa = delete_ike_sa_create(&this->public);
return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE); return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
} }
case IKE_CREATED: 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->ike_sa_id = ike_sa_id->clone(ike_sa_id);
this->name = strdup("(uninitialized)"); this->name = strdup("(uninitialized)");
this->child_sas = linked_list_create(); this->child_sas = linked_list_create();
this->my_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(AF_INET, "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->my_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
this->other_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER); this->other_id = identification_create_from_encoding(ID_ANY, CHUNK_INITIALIZER);
this->crypter_in = NULL; this->crypter_in = NULL;
+2
View 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); list = charon->socket->create_local_address_list(charon->socket);
while (list->remove_first(list, (void**)&host) == SUCCESS) 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); notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
host->destroy(host); host->destroy(host);
request->add_payload(request, (payload_t*)notify); request->add_payload(request, (payload_t*)notify);
+22 -26
View 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 /* 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 * be anything else but a subnet. We use from_addr as subnet
* and try to calculate a usable subnet mask. * 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); from = ts->get_from_address(ts);
memcpy(net, chunk.ptr, chunk.len); 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; if ((1<<bit & from.ptr[byte]) != (1<<bit & to.ptr[byte]))
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) != (1<<bit & to)) *mask = ((7 - bit) + (byte * 8));
{ found = TRUE;
*mask = bit; break;
return;
}
} }
*mask = 32;
return;
} }
case TS_IPV6_ADDR_RANGE: if (found)
default:
{ {
/* TODO: IPV6 support */ break;
*mask = 0;
return;
} }
} }
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->id.proto = (protocol == PROTO_AH) ? KERNEL_AH : KERNEL_ESP;
tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
tmpl->mode = TRUE; tmpl->mode = TRUE;
tmpl->family = src->get_family(src);
host2xfrm(src, &tmpl->saddr); host2xfrm(src, &tmpl->saddr);
host2xfrm(dst, &tmpl->id.daddr); host2xfrm(dst, &tmpl->id.daddr);
+1 -2
View File
@@ -76,8 +76,7 @@ static void send_packets(private_sender_t * this)
status = charon->socket->send(charon->socket, current_packet); status = charon->socket->send(charon->socket, current_packet);
if (status != SUCCESS) if (status != SUCCESS)
{ {
this->logger->log(this->logger, ERROR, "Sending failed, socket returned %s", this->logger->log(this->logger, ERROR, "Sending packet failed");
mapping_find(status_m, status));
} }
current_packet->destroy(current_packet); current_packet->destroy(current_packet);
} }
+40 -17
View File
@@ -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.ike);
pop_string(msg, &msg->add_conn.algorithms.esp); 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? 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) 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; return;
} }
other_host = msg->add_conn.other.address ? 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) 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); my_host->destroy(my_host);
return; return;
} }
@@ -210,7 +227,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg)
stroke_end_t tmp_end; stroke_end_t tmp_end;
host_t *tmp_host; 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; tmp_host = my_host;
my_host = other_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)) 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; goto destroy_hosts;
} }
my_id = identification_create_from_string(msg->add_conn.me.id ? 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) 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; goto destroy_hosts;
} }
other_id = identification_create_from_string(msg->add_conn.other.id ? 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) 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); my_id->destroy(my_id);
goto destroy_hosts; goto destroy_hosts;
} }
my_subnet = host_create(AF_INET, msg->add_conn.me.subnet ? my_subnet = host_create_from_string(msg->add_conn.me.subnet ?
msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT); msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT);
if (my_subnet == NULL) 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; goto destroy_ids;
} }
other_subnet = host_create(AF_INET, msg->add_conn.other.subnet ? other_subnet = host_create_from_string(msg->add_conn.other.subnet ?
msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT); msg->add_conn.other.subnet : msg->add_conn.other.address, IKE_PORT);
if (other_subnet == NULL) 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); my_subnet->destroy(my_subnet);
goto destroy_ids; goto destroy_ids;
} }
+228 -68
View File
@@ -38,11 +38,6 @@ struct private_host_t {
*/ */
host_t public; host_t public;
/**
* Address family to use, such as AF_INET or AF_INET6
*/
int family;
/** /**
* string representation of host * string representation of host
*/ */
@@ -52,8 +47,14 @@ struct private_host_t {
* low-lewel structure, wich stores the address * low-lewel structure, wich stores the address
*/ */
union { union {
/** generic type */
struct sockaddr address; struct sockaddr address;
/** maximux sockaddr size */
struct sockaddr_storage address_max;
/** IPv4 address */
struct sockaddr_in address4; struct sockaddr_in address4;
/** IPv6 address */
struct sockaddr_in6 address6;
}; };
/** /**
* length of address structure * 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) 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}; u_int8_t default_route[4];
memset(default_route, 0, sizeof(default_route));
return !memcmp(default_route, &(this->address4.sin_addr.s_addr), 4); 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: default:
{ {
/* empty chunk is returned */
return FALSE; return FALSE;
} }
} }
@@ -104,25 +112,51 @@ static bool is_anyaddr(private_host_t *this)
*/ */
static char *get_string(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))
{
this->string = strdup("%any");
return;
}
switch (this->address.sa_family)
{ {
case AF_INET: case AF_INET:
case AF_INET6:
{ {
char *string; char buffer[INET6_ADDRSTRLEN];
/* we need to clone it, since inet_ntoa overwrites void *address;
* internal buffer on subsequent calls
*/ if (this->address.sa_family == AF_INET)
if (this->string == NULL)
{ {
string = is_anyaddr(this)? "%any" : inet_ntoa(this->address4.sin_addr); address = &this->address4.sin_addr;
this->string = malloc(strlen(string)+1);
strcpy(this->string, string);
} }
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: 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; 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.ptr = (char*)&(this->address4.sin_addr.s_addr);
address.len = 4; address.len = 4;
return address;
}
case AF_INET6:
{
address.ptr = (char*)&(this->address6.sin6_addr.s6_addr);
address.len = 16;
return address;
} }
default: default:
{ {
/* empty chunk is returned */ /* return empty chunk */
return address; return address;
} }
} }
@@ -155,7 +195,7 @@ static chunk_t get_address(private_host_t *this)
*/ */
static int get_family(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) 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); return ntohs(this->address4.sin_port);
} }
case AF_INET6:
{
return ntohs(this->address6.sin6_port);
}
default: default:
{ {
return 0; 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) static void set_port(private_host_t *this, u_int16_t port)
{ {
switch (this->family) switch (this->address.sa_family)
{ {
case AF_INET: case AF_INET:
{ {
this->address4.sin_port = htons(port); this->address4.sin_port = htons(port);
break;
}
case AF_INET6:
{
this->address6.sin6_port = htons(port);
break;
} }
default: 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); private_host_t *new = malloc_thing(private_host_t);
memcpy(new, this, sizeof(private_host_t)); memcpy(new, this, sizeof(private_host_t));
if (this->string) if (this->string)
{ {
new->string = malloc(strlen(this->string)+1); new->string = strdup(this->string);
strcpy(new->string, this->string);
} }
return new; 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) 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: case AF_INET:
{ {
if ((this->address4.sin_family == other->address4.sin_family) && if (memeq(&this->address4.sin_addr, &other->address4.sin_addr,
(this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr)) sizeof(this->address4.sin_addr)))
{
return TRUE;
}
break;
}
case AF_INET6:
{
if (memeq(&this->address6.sin6_addr, &other->address6.sin6_addr,
sizeof(this->address6.sin6_addr)))
{ {
return TRUE; return TRUE;
} }
} }
default:
break;
} }
return FALSE; return FALSE;
} }
@@ -234,16 +303,16 @@ static bool ip_equals(private_host_t *this, private_host_t *other)
/** /**
* Implements host_t.get_differences * 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; 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; 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; ret |= HOST_DIFF_PORT;
} }
@@ -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) 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: case AF_INET:
{ {
if ((this->address4.sin_family == other->address4.sin_family) && if (this->address4.sin_port == other->address4.sin_port)
(this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr) &&
(this->address4.sin_port == other->address4.sin_port))
{ {
return TRUE; return TRUE;
} }
break;
} }
case AF_INET6:
{
if (this->address6.sin6_port == other->address6.sin6_port)
{
return TRUE;
}
break;
}
default:
break;
} }
return FALSE; 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_address = (chunk_t (*) (host_t *)) get_address;
this->public.get_port = (u_int16_t (*) (host_t *))get_port; 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.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.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals;
this->public.equals = (bool (*) (host_t *,host_t *)) equals; this->public.equals = (bool (*) (host_t *,host_t *)) equals;
this->public.is_anyaddr = (bool (*) (host_t *)) is_anyaddr; 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(); private_host_t *this = host_create_empty();
this->family = family; this->address.sa_family = family;
switch (family) switch (family)
{ {
/* IPv4 */
case AF_INET: case AF_INET:
{ {
this->address4.sin_family = AF_INET; if (inet_pton(family, address, &this->address4.sin_addr) <=0)
this->address4.sin_addr.s_addr = inet_addr(address); {
break;
}
this->address4.sin_port = htons(port); this->address4.sin_port = htons(port);
this->socklen = sizeof(struct sockaddr_in); 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: default:
{ {
free(this); break;
return NULL;
} }
} }
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(); private_host_t *this = host_create_empty();
this->family = AF_INET; this->address.sa_family = AF_INET;
this->address4.sin_family = AF_INET;
this->address4.sin_addr.s_addr = address; this->address4.sin_addr.s_addr = address;
this->address4.sin_port = port; this->address4.sin_port = port;
this->socklen = sizeof(struct sockaddr_in); 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(); private_host_t *this = host_create_empty();
this->family = family; this->address.sa_family = family;
switch (family) switch (family)
{ {
/* IPv4 */
case AF_INET: case AF_INET:
{ {
if (address.len != 4) 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->address4.sin_port = htons(port);
this->socklen = sizeof(struct sockaddr_in); this->socklen = sizeof(struct sockaddr_in);
set_string(this);
return &(this->public); 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); free(this);
return NULL; 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) host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
{ {
chunk_t address; private_host_t *this = host_create_empty();
switch (sockaddr->sa_family) switch (sockaddr->sa_family)
{ {
/* IPv4 */
case AF_INET: 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; memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6));
address.ptr = (void*)&(sin->sin_addr.s_addr); this->socklen = sizeof(struct sockaddr_in6);
address.len = 4; set_string(this);
return host_create_from_chunk(AF_INET, address, ntohs(sin->sin_port)); return &this->public;
} }
default: default:
return NULL; break;
} }
free(this);
return NULL;
} }
+14 -6
View File
@@ -192,19 +192,31 @@ struct host_t {
/** /**
* @brief Constructor to create a host_t object from an address string * @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 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 address string of an address, such as "152.96.193.130"
* @param port port number * @param port port number
* @return * @return
* - host_t object * - host_t object
* - NULL, if family not supported. * - NULL, if family not supported/invalid string.
* *
* @ingroup network * @ingroup network
*/ */
host_t *host_create(int family, char *address, u_int16_t port); 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 * @brief Constructor to create a host_t object from raw header data
* *
@@ -222,8 +234,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 * @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 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 * @param address address as 4 byte chunk_t in networ order
* @param port port number * @param port port number
@@ -238,8 +248,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 * @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 * @param sockaddr sockaddr struct which contains family, address and port
* @return * @return
* - host_t object * - host_t object
+36 -2
View File
@@ -106,14 +106,48 @@ static char* connection_name(starter_conn_t *conn)
return conn->name; 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) 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->id = push_string(msg, conn_end->id);
msg_end->cert = push_string(msg, conn_end->cert); msg_end->cert = push_string(msg, conn_end->cert);
msg_end->ca = push_string(msg, conn_end->ca); msg_end->ca = push_string(msg, conn_end->ca);
msg_end->updown = push_string(msg, conn_end->updown); msg_end->updown = push_string(msg, conn_end->updown);
msg_end->address = push_string(msg, inet_ntoa(conn_end->addr.u.v4.sin_addr)); ip_address2string(&conn_end->addr, buffer, sizeof(buffer));
msg_end->subnet = push_string(msg, inet_ntoa(conn_end->subnet.addr.u.v4.sin_addr)); 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->subnet_mask = conn_end->subnet.maskbits;
msg_end->sendcert = conn_end->sendcert; msg_end->sendcert = conn_end->sendcert;
msg_end->protocol = conn_end->protocol; msg_end->protocol = conn_end->protocol;