From: Martin Willi Date: Thu, 27 Jun 2013 15:25:21 +0000 (+0200) Subject: stream: add support for TCP streams X-Git-Tag: 5.1.0rc1~10^2~44 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db1c8aa460ce4b6cc053857aa765322f2233b8ee;p=thirdparty%2Fstrongswan.git stream: add support for TCP streams --- diff --git a/src/libstrongswan/networking/streams/stream.c b/src/libstrongswan/networking/streams/stream.c index 3c782cce08..bc6bbc210f 100644 --- a/src/libstrongswan/networking/streams/stream.c +++ b/src/libstrongswan/networking/streams/stream.c @@ -16,8 +16,7 @@ #include #include #include -#include -#include +#include typedef struct private_stream_t private_stream_t; @@ -315,3 +314,81 @@ stream_t *stream_create_unix(char *uri) } return stream_create_from_fd(fd); } + +/** + * See header. + */ +int stream_parse_uri_tcp(char *uri, struct sockaddr *addr) +{ + char *pos, buf[128]; + host_t *host; + u_long port; + int len; + + if (!strpfx(uri, "tcp://")) + { + return -1; + } + uri += strlen("tcp://"); + pos = strrchr(uri, ':'); + if (!pos) + { + return -1; + } + if (*uri == '[' && pos > uri && *(pos - 1) == ']') + { + /* IPv6 URI */ + snprintf(buf, sizeof(buf), "%.*s", (int)(pos - uri - 2), uri + 1); + } + else + { + snprintf(buf, sizeof(buf), "%.*s", (int)(pos - uri), uri); + } + port = strtoul(pos + 1, &pos, 10); + if (port == ULONG_MAX || *pos || port > 65535) + { + return -1; + } + host = host_create_from_dns(buf, AF_UNSPEC, port); + if (!host) + { + return -1; + } + len = *host->get_sockaddr_len(host); + memcpy(addr, host->get_sockaddr(host), len); + host->destroy(host); + return len; +} + +/** + * See header + */ +stream_t *stream_create_tcp(char *uri) +{ + union { + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr sa; + } addr; + int fd, len; + + len = stream_parse_uri_tcp(uri, &addr.sa); + if (len == -1) + { + DBG1(DBG_NET, "invalid stream URI: '%s'", uri); + return NULL; + } + fd = socket(addr.sa.sa_family, SOCK_STREAM, 0); + if (fd < 0) + { + DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno)); + return NULL; + } + if (connect(fd, &addr.sa, len)) + { + DBG1(DBG_NET, "connecting to '%s' failed: %s", uri, strerror(errno)); + close(fd); + return NULL; + } + return stream_create_from_fd(fd); +} diff --git a/src/libstrongswan/networking/streams/stream.h b/src/libstrongswan/networking/streams/stream.h index 842ad8e673..87685f8889 100644 --- a/src/libstrongswan/networking/streams/stream.h +++ b/src/libstrongswan/networking/streams/stream.h @@ -26,6 +26,7 @@ typedef struct stream_t stream_t; #include #include +#include /** * Constructor function prototype for stream_t. @@ -145,6 +146,32 @@ stream_t *stream_create_unix(char *uri); */ int stream_parse_uri_unix(char *uri, struct sockaddr_un *addr); +/** + * Create a stream for TCP sockets. + * + * TCP URIs start with tcp://, followed by a hostname (FQDN or IP), followed + * by a colon separated port. A full TCP uri looks something like: + * + * tcp://srv.example.com:5555 + * tcp://0.0.0.0:1234 + * tcp://[fec2::1]:7654 + * + * There is no default port, so a colon after tcp:// is mandatory. + * + * @param uri TCP socket specific URI, must start with "tcp://" + * @return stream instance, NULL on failure + */ +stream_t *stream_create_tcp(char *uri); + +/** + * Helper function to parse a tcp:// URI to a sockaddr + * + * @param uri URI + * @param addr sockaddr, large enough for URI + * @return length of sockaddr, -1 on error + */ +int stream_parse_uri_tcp(char *uri, struct sockaddr *addr); + /** * Create a stream from a file descriptor. * diff --git a/src/libstrongswan/networking/streams/stream_manager.c b/src/libstrongswan/networking/streams/stream_manager.c index dbd221e2ad..0141e1d8da 100644 --- a/src/libstrongswan/networking/streams/stream_manager.c +++ b/src/libstrongswan/networking/streams/stream_manager.c @@ -248,6 +248,7 @@ METHOD(stream_manager_t, destroy, void, private_stream_manager_t *this) { remove_stream(this, stream_create_unix); + remove_stream(this, stream_create_tcp); remove_service(this, stream_service_create_unix); this->streams->destroy(this->streams); @@ -282,6 +283,7 @@ stream_manager_t *stream_manager_create() ); add_stream(this, "unix://", stream_create_unix); + add_stream(this, "tcp://", stream_create_tcp); add_service(this, "unix://", stream_service_create_unix); return &this->public;