diff options
| author | Luca Boccassi <luca.boccassi@gmail.com> | 2017-10-26 19:42:55 +0100 | 
|---|---|---|
| committer | Daniel Stenberg <daniel@haxx.se> | 2017-11-09 13:20:11 +0100 | 
| commit | 32828cc4fb241aca01913424aa1781af0acd6aee (patch) | |
| tree | d65b8b229fdb2e7a8148f6265a7c1451004c085a | |
| parent | b78dce252681a96d5f7123bfcd2f5d843e7c175c (diff) | |
--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
| -rw-r--r-- | docs/cmdline-opts/interface.d | 4 | ||||
| -rwxr-xr-x | 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;        }      }  | 
