From 32828cc4fb241aca01913424aa1781af0acd6aee Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Thu, 26 Oct 2017 19:42:55 +0100 Subject: --interface: add support for Linux VRF The --interface command (CURLOPT_INTERFACE option) already uses SO_BINDTODEVICE on Linux, but it tries to parse it as an interface or IP address first, which fails in case the user passes a VRF. Try to use the socket option immediately and parse it as a fallback instead. Update the documentation to mention this feature, and that it requires the binary to be ran by root or with CAP_NET_RAW capabilities for this to work. Closes #2024 --- docs/cmdline-opts/interface.d | 4 ++++ lib/connect.c | 52 +++++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/docs/cmdline-opts/interface.d b/docs/cmdline-opts/interface.d index da84cd2b6..bd0817618 100644 --- a/docs/cmdline-opts/interface.d +++ b/docs/cmdline-opts/interface.d @@ -10,3 +10,7 @@ name, IP address or host name. An example could look like: curl --interface eth0:1 https://www.example.com/ If this option is used several times, the last one will be used. + +On Linux it can be used to specify a VRF, but the binary needs to either +have CAP_NET_RAW or to be ran as root. More information about Linux VRF: +https://www.kernel.org/doc/Documentation/networking/vrf.txt diff --git a/lib/connect.c b/lib/connect.c index 28c6e9ed2..d47c1b996 100755 --- a/lib/connect.c +++ b/lib/connect.c @@ -285,6 +285,34 @@ static CURLcode bindlocal(struct connectdata *conn, /* interface */ if(!is_host) { +#ifdef SO_BINDTODEVICE + /* I am not sure any other OSs than Linux that provide this feature, + * and at the least I cannot test. --Ben + * + * This feature allows one to tightly bind the local socket to a + * particular interface. This will force even requests to other + * local interfaces to go out the external interface. + * + * + * Only bind to the interface when specified as interface, not just + * as a hostname or ip address. + * + * interface might be a VRF, eg: vrf-blue, which means it cannot be + * converted to an IP address and would fail Curl_if2ip. Simply try + * to use it straight away. + */ + if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, + dev, (curl_socklen_t)strlen(dev) + 1) == 0) { + /* This is typically "errno 1, error: Operation not permitted" if + * you're not running as root or another suitable privileged + * user. + * If it succeeds it means the parameter was a valid interface and + * not an IP address. Return immediately. + */ + return CURLE_OK; + } +#endif + switch(Curl_if2ip(af, scope, conn->scope_id, dev, myhost, sizeof(myhost))) { case IF2IP_NOT_FOUND: @@ -305,30 +333,6 @@ static CURLcode bindlocal(struct connectdata *conn, infof(data, "Local Interface %s is ip %s using address family %i\n", dev, myhost, af); done = 1; - -#ifdef SO_BINDTODEVICE - /* I am not sure any other OSs than Linux that provide this feature, - * and at the least I cannot test. --Ben - * - * This feature allows one to tightly bind the local socket to a - * particular interface. This will force even requests to other - * local interfaces to go out the external interface. - * - * - * Only bind to the interface when specified as interface, not just - * as a hostname or ip address. - */ - if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, - dev, (curl_socklen_t)strlen(dev) + 1) != 0) { - error = SOCKERRNO; - infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;" - " will do regular bind\n", - dev, error, Curl_strerror(conn, error)); - /* This is typically "errno 1, error: Operation not permitted" if - you're not running as root or another suitable privileged - user */ - } -#endif break; } } -- cgit v1.2.1