summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/socket_default/socket_default_socket.c
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2013-08-25 15:37:27 +0200
committerYves-Alexis Perez <corsac@debian.org>2013-08-25 15:37:27 +0200
commitc7307e752d8f47c68f834e22ee2ce0a14a70e695 (patch)
treefbb442a20ab54aad511b46a070e65b8d09c22791 /src/libcharon/plugins/socket_default/socket_default_socket.c
parentf74c6d77c3efb529e7403eeef0613c061eb895b3 (diff)
parent6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 (diff)
downloadvyos-strongswan-c7307e752d8f47c68f834e22ee2ce0a14a70e695.tar.gz
vyos-strongswan-c7307e752d8f47c68f834e22ee2ce0a14a70e695.zip
Merge tag 'upstream/5.1.0'
Upstream version 5.1.0
Diffstat (limited to 'src/libcharon/plugins/socket_default/socket_default_socket.c')
-rw-r--r--src/libcharon/plugins/socket_default/socket_default_socket.c159
1 files changed, 110 insertions, 49 deletions
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);