From 6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 Mon Sep 17 00:00:00 2001 From: Yves-Alexis Perez Date: Sun, 25 Aug 2013 15:37:26 +0200 Subject: Imported Upstream version 5.1.0 --- .../plugins/socket_default/socket_default_socket.c | 159 ++++++++++++++------- 1 file changed, 110 insertions(+), 49 deletions(-) (limited to 'src/libcharon/plugins/socket_default/socket_default_socket.c') diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index c0b744a68..4139afe5a 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2012 Tobias Brunner + * Copyright (C) 2006-2013 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -162,23 +162,26 @@ METHOD(socket_t, receiver, status_t, FD_ZERO(&rfds); - if (this->ipv4) + if (this->ipv4 != -1) { FD_SET(this->ipv4, &rfds); + max_fd = max(max_fd, this->ipv4); } - if (this->ipv4_natt) + if (this->ipv4_natt != -1) { FD_SET(this->ipv4_natt, &rfds); + max_fd = max(max_fd, this->ipv4_natt); } - if (this->ipv6) + if (this->ipv6 != -1) { FD_SET(this->ipv6, &rfds); + max_fd = max(max_fd, this->ipv6); } - if (this->ipv6_natt) + if (this->ipv6_natt != -1) { FD_SET(this->ipv6_natt, &rfds); + max_fd = max(max_fd, this->ipv6_natt); } - max_fd = max(max(this->ipv4, this->ipv4_natt), max(this->ipv6, this->ipv6_natt)); DBG2(DBG_NET, "waiting for data on sockets"); oldstate = thread_cancelability(TRUE); @@ -189,22 +192,22 @@ METHOD(socket_t, receiver, status_t, } thread_cancelability(oldstate); - if (FD_ISSET(this->ipv4, &rfds)) + if (this->ipv4 != -1 && FD_ISSET(this->ipv4, &rfds)) { port = this->port; selected = this->ipv4; } - if (FD_ISSET(this->ipv4_natt, &rfds)) + if (this->ipv4_natt != -1 && FD_ISSET(this->ipv4_natt, &rfds)) { port = this->natt; selected = this->ipv4_natt; } - if (FD_ISSET(this->ipv6, &rfds)) + if (this->ipv6 != -1 && FD_ISSET(this->ipv6, &rfds)) { port = this->port; selected = this->ipv6; } - if (FD_ISSET(this->ipv6_natt, &rfds)) + if (this->ipv6_natt != -1 && FD_ISSET(this->ipv6_natt, &rfds)) { port = this->natt; selected = this->ipv6_natt; @@ -326,7 +329,7 @@ METHOD(socket_t, receiver, status_t, METHOD(socket_t, sender, status_t, private_socket_default_socket_t *this, packet_t *packet) { - int sport, skt, family; + int sport, skt = -1, family; ssize_t bytes_sent; chunk_t data; host_t *src, *dst; @@ -376,9 +379,10 @@ METHOD(socket_t, sender, status_t, return FAILED; } } - else + if (skt == -1) { - DBG1(DBG_NET, "unable to locate a send socket for port %d", sport); + DBG1(DBG_NET, "no socket found to send IPv%d packet from port %d", + family == AF_INET ? 4 : 6, sport); return FAILED; } @@ -497,6 +501,22 @@ METHOD(socket_t, get_port, u_int16_t, return nat_t ? this->natt : this->port; } +METHOD(socket_t, supported_families, socket_family_t, + private_socket_default_socket_t *this) +{ + socket_family_t families = SOCKET_FAMILY_NONE; + + if (this->ipv4 != -1 || this->ipv4_natt != -1) + { + families |= SOCKET_FAMILY_IPV4; + } + if (this->ipv6 != -1 || this->ipv6_natt != -1) + { + families |= SOCKET_FAMILY_IPV6; + } + return families; +} + /** * open a socket to send and receive packets */ @@ -537,20 +557,20 @@ static int open_socket(private_socket_default_socket_t *this, pktinfo = IPV6_RECVPKTINFO; break; default: - return 0; + return -1; } skt = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (skt < 0) { DBG1(DBG_NET, "could not open socket: %s", strerror(errno)); - return 0; + return -1; } if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) { DBG1(DBG_NET, "unable to set SO_REUSEADDR on socket: %s", strerror(errno)); close(skt); - return 0; + return -1; } /* bind the socket */ @@ -558,7 +578,7 @@ static int open_socket(private_socket_default_socket_t *this, { DBG1(DBG_NET, "unable to bind socket: %s", strerror(errno)); close(skt); - return 0; + return -1; } /* retrieve randomly allocated port if needed */ @@ -568,7 +588,7 @@ static int open_socket(private_socket_default_socket_t *this, { DBG1(DBG_NET, "unable to determine port: %s", strerror(errno)); close(skt); - return 0; + return -1; } switch (family) { @@ -588,7 +608,7 @@ static int open_socket(private_socket_default_socket_t *this, { DBG1(DBG_NET, "unable to set IP_PKTINFO on socket: %s", strerror(errno)); close(skt); - return 0; + return -1; } } @@ -610,22 +630,69 @@ static int open_socket(private_socket_default_socket_t *this, return skt; } +/** + * Check if we should use the given family + */ +static bool use_family(int family) +{ + switch (family) + { + case AF_INET: + return lib->settings->get_bool(lib->settings, + "%s.plugins.socket-default.use_ipv4", TRUE, charon->name); + case AF_INET6: + return lib->settings->get_bool(lib->settings, + "%s.plugins.socket-default.use_ipv6", TRUE, charon->name); + default: + return FALSE; + } +} + +/** + * Open a socket pair (normal and NAT traversal) for a given address family + */ +static void open_socketpair(private_socket_default_socket_t *this, int family, + int *skt, int *skt_natt, char *label) +{ + if (!use_family(family)) + { + *skt = -1; + *skt_natt = -1; + return; + } + + *skt = open_socket(this, family, &this->port); + if (*skt == -1) + { + *skt_natt = -1; + DBG1(DBG_NET, "could not open %s socket, %s disabled", label, label); + } + else + { + *skt_natt = open_socket(this, family, &this->natt); + if (*skt_natt == -1) + { + DBG1(DBG_NET, "could not open %s NAT-T socket", label); + } + } +} + METHOD(socket_t, destroy, void, private_socket_default_socket_t *this) { - if (this->ipv4) + if (this->ipv4 != -1) { close(this->ipv4); } - if (this->ipv4_natt) + if (this->ipv4_natt != -1) { close(this->ipv4_natt); } - if (this->ipv6) + if (this->ipv6 != -1) { close(this->ipv6); } - if (this->ipv6_natt) + if (this->ipv6_natt != -1) { close(this->ipv6_natt); } @@ -645,6 +712,7 @@ socket_default_socket_t *socket_default_socket_create() .send = _sender, .receive = _receiver, .get_port = _get_port, + .supported_families = _supported_families, .destroy = _destroy, }, }, @@ -666,37 +734,30 @@ socket_default_socket_t *socket_default_socket_create() this->natt = 0; } - /* we allocate IPv6 sockets first as that will reserve randomly allocated - * ports also for IPv4 */ - this->ipv6 = open_socket(this, AF_INET6, &this->port); - if (this->ipv6 == 0) - { - DBG1(DBG_NET, "could not open IPv6 socket, IPv6 disabled"); - } - else - { - this->ipv6_natt = open_socket(this, AF_INET6, &this->natt); - if (this->ipv6_natt == 0) - { - DBG1(DBG_NET, "could not open IPv6 NAT-T socket"); - } - } - - this->ipv4 = open_socket(this, AF_INET, &this->port); - if (this->ipv4 == 0) - { - DBG1(DBG_NET, "could not open IPv4 socket, IPv4 disabled"); - } - else + if ((this->port && this->port < 1024) || (this->natt && this->natt < 1024)) { - this->ipv4_natt = open_socket(this, AF_INET, &this->natt); - if (this->ipv4_natt == 0) + if (!lib->caps->check(lib->caps, CAP_NET_BIND_SERVICE)) { - DBG1(DBG_NET, "could not open IPv4 NAT-T socket"); + /* required to bind ports < 1024 */ + DBG1(DBG_NET, "socket-default plugin requires CAP_NET_BIND_SERVICE " + "capability"); + destroy(this); + return NULL; } } - if (!this->ipv4 && !this->ipv6) + /* we allocate IPv6 sockets first as that will reserve randomly allocated + * ports also for IPv4. On OS X, we have to do it the other way round + * for the same effect. */ +#ifdef __APPLE__ + open_socketpair(this, AF_INET, &this->ipv4, &this->ipv4_natt, "IPv4"); + open_socketpair(this, AF_INET6, &this->ipv6, &this->ipv6_natt, "IPv6"); +#else /* !__APPLE__ */ + open_socketpair(this, AF_INET6, &this->ipv6, &this->ipv6_natt, "IPv6"); + open_socketpair(this, AF_INET, &this->ipv4, &this->ipv4_natt, "IPv4"); +#endif /* __APPLE__ */ + + if (this->ipv4 == -1 && this->ipv6 == -1) { DBG1(DBG_NET, "could not create any sockets"); destroy(this); -- cgit v1.2.3