Beispiel #1
0
bool Curl_if_is_interface_name(const char *interf)
{
  /* This is here just to support the old interfaces */
  char buf[256];

  return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) ==
          IF2IP_NOT_FOUND) ? FALSE : TRUE;
}
Beispiel #2
0
bool Curl_if_is_interface_name(const char *interf)
{
  /* This is here just to support the old interfaces */
  char buf[256];

  char *ip = Curl_if2ip(AF_INET, interf, buf, sizeof(buf));

  return (ip != NULL) ? TRUE : FALSE;
}
Beispiel #3
0
static CURLcode bindlocal(struct connectdata *conn,
                          curl_socket_t sockfd)
{
  struct SessionHandle *data = conn->data;
  struct sockaddr_in me;
  struct sockaddr *sock = NULL;  /* bind to this address */
  socklen_t socksize; /* size of the data sock points to */
  unsigned short port = data->set.localport; /* use this port number, 0 for
                                                "random" */
  /* how many port numbers to try to bind to, increasing one at a time */
  int portnum = data->set.localportrange;

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if (data->set.device && (strlen(data->set.device)<255) ) {
    struct Curl_dns_entry *h=NULL;
    char myhost[256] = "";
    in_addr_t in;
    int rc;
    bool was_iface = FALSE;

    /* First check if the given name is an IP address */
    in=inet_addr(data->set.device);

    if((in == CURL_INADDR_NONE) &&
       Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
      /*
       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
       */
      rc = Curl_resolv(conn, myhost, 0, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_wait_for_resolv(conn, &h);

      if(h) {
        was_iface = TRUE;
        Curl_resolv_unlock(data, h);
      }
    }

    if(!was_iface) {
      /*
       * This was not an interface, resolve the name as a host name
       * or IP number
       */
      rc = Curl_resolv(conn, data->set.device, 0, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_wait_for_resolv(conn, &h);

      if(h) {
        if(in == CURL_INADDR_NONE)
          /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
          Curl_inet_ntop(h->addr->ai_addr->sa_family,
                         &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr,
                         myhost, sizeof myhost);
        else
          /* we know data->set.device is shorter than the myhost array */
          strcpy(myhost, data->set.device);
        Curl_resolv_unlock(data, h);
      }
    }

    if(! *myhost) {
      /* need to fix this
         h=Curl_gethost(data,
         getmyhost(*myhost,sizeof(myhost)),
         hostent_buf,
         sizeof(hostent_buf));
      */
      failf(data, "Couldn't bind to '%s'", data->set.device);
      return CURLE_HTTP_PORT_FAILED;
    }

    infof(data, "Bind local address to %s\n", myhost);

#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.
     *
     */
    if (was_iface) {
      /* Only bind to the interface when specified as interface, not just as a
       * hostname or ip address.
       */
      if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                     data->set.device, strlen(data->set.device)+1) != 0) {
        /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
           sockfd, data->set.device, Curl_strerror(Curl_sockerrno())); */
        infof(data, "SO_BINDTODEVICE %s failed\n",
              data->set.device);
        /* This is typically "errno 1, error: Operation not permitted" if
           you're not running as root or another suitable privileged user */
      }
    }
#endif

    in=inet_addr(myhost);
    if (CURL_INADDR_NONE == in) {
      failf(data,"couldn't find my own IP address (%s)", myhost);
      return CURLE_HTTP_PORT_FAILED;
    } /* end of inet_addr */

    if ( h ) {
      Curl_addrinfo *addr = h->addr;
      sock = addr->ai_addr;
      socksize = addr->ai_addrlen;
    }
    else
      return CURLE_HTTP_PORT_FAILED;

  }
  else if(port) {
    /* if a local port number is requested but no local IP, extract the
       address from the socket */
    memset(&me, 0, sizeof(struct sockaddr));
    me.sin_family = AF_INET;
    me.sin_addr.s_addr = INADDR_ANY;

    sock = (struct sockaddr *)&me;
    socksize = sizeof(struct sockaddr);

  }
  else
    /* no local kind of binding was requested */
    return CURLE_OK;

  do {

    /* Set port number to bind to, 0 makes the system pick one */
    if(sock->sa_family == AF_INET)
      ((struct sockaddr_in *)sock)->sin_port = htons(port);
#ifdef ENABLE_IPV6
    else
      ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
#endif

    if( bind(sockfd, sock, socksize) >= 0) {
      /* we succeeded to bind */
      struct Curl_sockaddr_storage add;
      size_t size;

      size = sizeof(add);
      if(getsockname(sockfd, (struct sockaddr *) &add,
                     (socklen_t *)&size)<0) {
        failf(data, "getsockname() failed");
        return CURLE_HTTP_PORT_FAILED;
      }
      /* We re-use/clobber the port variable here below */
      if(((struct sockaddr *)&add)->sa_family == AF_INET)
        port = ntohs(((struct sockaddr_in *)&add)->sin_port);
#ifdef ENABLE_IPV6
      else
        port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
#endif
      infof(data, "Local port: %d\n", port);
      return CURLE_OK;
    }
    if(--portnum > 0) {
      infof(data, "Bind to local port %d failed, trying next\n", port);
      port++; /* try next port */
    }
    else
      break;
  } while(1);

  data->state.os_errno = Curl_sockerrno();
  failf(data, "bind failure: %s",
        Curl_strerror(conn, data->state.os_errno));
  return CURLE_HTTP_PORT_FAILED;

}
Beispiel #4
0
static CURLcode bindlocal(struct connectdata *conn,
                          curl_socket_t sockfd, int af)
{
    struct SessionHandle *data = conn->data;

    struct Curl_sockaddr_storage sa;
    struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
    curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
    struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
#ifdef ENABLE_IPV6
    struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif

    struct Curl_dns_entry *h=NULL;
    unsigned short port = data->set.localport; /* use this port number, 0 for
                                                "random" */
    /* how many port numbers to try to bind to, increasing one at a time */
    int portnum = data->set.localportrange;
    const char *dev = data->set.str[STRING_DEVICE];
    int error;
    char myhost[256] = "";
    int done = 0; /* -1 for error, 1 for address found */

    /*************************************************************
     * Select device to bind socket to
     *************************************************************/
    if ( !dev && !port )
        /* no local kind of binding was requested */
        return CURLE_OK;

    memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));

    if(dev && (strlen(dev)<255) ) {

        /* interface */
        if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
            /*
             * We now have the numerical IP address in the 'myhost' buffer
             */
            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
        }
        else {
            /*
             * This was not an interface, resolve the name as a host name
             * or IP number
             *
             * Temporarily force name resolution to use only the address type
             * of the connection. The resolve functions should really be changed
             * to take a type parameter instead.
             */
            long ipver = data->set.ip_version;
            int rc;

            if (af == AF_INET)
                data->set.ip_version = CURL_IPRESOLVE_V4;
#ifdef ENABLE_IPV6
            else if (af == AF_INET6)
                data->set.ip_version = CURL_IPRESOLVE_V6;
#endif

            rc = Curl_resolv(conn, dev, 0, &h);
            if(rc == CURLRESOLV_PENDING)
                (void)Curl_wait_for_resolv(conn, &h);
            data->set.ip_version = ipver;

            if(h) {
                /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
                Curl_printable_address(h->addr, myhost, sizeof(myhost));
                infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
                      dev, af, myhost, h->addr->ai_family);
                Curl_resolv_unlock(data, h);
                done = 1;
            }
            else {
                /*
                 * provided dev was no interface (or interfaces are not supported
                 * e.g. solaris) no ip address and no domain we fail here
                 */
                done = -1;
            }
        }

        if(done > 0) {
#ifdef ENABLE_IPV6
            /* ipv6 address */
            if((af == AF_INET6) &&
                    (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
                si6->sin6_family = AF_INET6;
                si6->sin6_port = htons(port);
                sizeof_sa = sizeof(struct sockaddr_in6);
            }
            else
#endif
                /* ipv4 address */
                if((af == AF_INET) &&
                        (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
                    si4->sin_family = AF_INET;
                    si4->sin_port = htons(port);
                    sizeof_sa = sizeof(struct sockaddr_in);
                }
        }

        if(done < 1) {
            failf(data, "Couldn't bind to '%s'", dev);
            return CURLE_INTERFACE_FAILED;
        }
    }
    else {
        /* no device was given, prepare sa to match af's needs */
#ifdef ENABLE_IPV6
        if ( af == AF_INET6 ) {
            si6->sin6_family = AF_INET6;
            si6->sin6_port = htons(port);
            sizeof_sa = sizeof(struct sockaddr_in6);
        }
        else
#endif
            if ( af == AF_INET ) {
                si4->sin_family = AF_INET;
                si4->sin_port = htons(port);
                sizeof_sa = sizeof(struct sockaddr_in);
            }
    }

    for(;;) {
        if( bind(sockfd, sock, sizeof_sa) >= 0) {
            /* we succeeded to bind */
            struct Curl_sockaddr_storage add;
            curl_socklen_t size = sizeof(add);
            memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
            if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
                data->state.os_errno = error = SOCKERRNO;
                failf(data, "getsockname() failed with errno %d: %s",
                      error, Curl_strerror(conn, error));
                return CURLE_INTERFACE_FAILED;
            }
            infof(data, "Local port: %hu\n", port);
            conn->bits.bound = TRUE;
            return CURLE_OK;
        }

        if(--portnum > 0) {
            infof(data, "Bind to local port %hu failed, trying next\n", port);
            port++; /* try next port */
            /* We re-use/clobber the port variable here below */
            if(sock->sa_family == AF_INET)
                si4->sin_port = ntohs(port);
#ifdef ENABLE_IPV6
            else
                si6->sin6_port = ntohs(port);
#endif
        }
        else
            break;
    }

    data->state.os_errno = error = SOCKERRNO;
    failf(data, "bind failed with errno %d: %s",
          error, Curl_strerror(conn, error));

    return CURLE_INTERFACE_FAILED;
}
Beispiel #5
0
static CURLcode bindlocal(struct connectdata *conn,
                          curl_socket_t sockfd)
{
#ifdef HAVE_INET_NTOA
  bool bindworked = FALSE;
  struct SessionHandle *data = conn->data;

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if (strlen(data->set.device)<255) {
    struct Curl_dns_entry *h=NULL;
    size_t size;
    char myhost[256] = "";
    in_addr_t in;
    int rc;
    bool was_iface = FALSE;

    /* First check if the given name is an IP address */
    in=inet_addr(data->set.device);

    if((in == CURL_INADDR_NONE) &&
       Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
      /*
       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
       */
      rc = Curl_resolv(conn, myhost, 0, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_wait_for_resolv(conn, &h);

      if(h)
        was_iface = TRUE;
    }

    if(!was_iface) {
      /*
       * This was not an interface, resolve the name as a host name
       * or IP number
       */
      rc = Curl_resolv(conn, data->set.device, 0, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_wait_for_resolv(conn, &h);

      if(h)
        /* we know data->set.device is shorter than the myhost array */
        strcpy(myhost, data->set.device);
    }

    if(! *myhost) {
      /* need to fix this
         h=Curl_gethost(data,
         getmyhost(*myhost,sizeof(myhost)),
         hostent_buf,
         sizeof(hostent_buf));
      */
      failf(data, "Couldn't bind to '%s'", data->set.device);
      return CURLE_HTTP_PORT_FAILED;
    }

    infof(data, "We bind local end to %s\n", myhost);

#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.
     *
     */
    if (was_iface) {
      /* Only bind to the interface when specified as interface, not just as a
       * hostname or ip address.
       */
      if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                     data->set.device, strlen(data->set.device)+1) != 0) {
        /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
           sockfd, data->set.device, Curl_strerror(Curl_ourerrno())); */
        infof(data, "SO_BINDTODEVICE %s failed\n",
              data->set.device);
        /* This is typically "errno 1, error: Operation not permitted" if
           you're not running as root or another suitable privileged user */
      }
    }
#endif

    in=inet_addr(myhost);
    if (CURL_INADDR_NONE != in) {

      if ( h ) {
        Curl_addrinfo *addr = h->addr;

        Curl_resolv_unlock(data, h);
        /* we don't need it anymore after this function has returned */

        if( bind(sockfd, addr->ai_addr, (socklen_t)addr->ai_addrlen) >= 0) {
          /* we succeeded to bind */
#ifdef ENABLE_IPV6
          struct sockaddr_in6 add;
#else
          struct sockaddr_in add;
#endif

          bindworked = TRUE;

          size = sizeof(add);
          if(getsockname(sockfd, (struct sockaddr *) &add,
                         (socklen_t *)&size)<0) {
            failf(data, "getsockname() failed");
            return CURLE_HTTP_PORT_FAILED;
          }
        }

        if(!bindworked) {
          data->state.os_errno = Curl_ourerrno();
          failf(data, "bind failure: %s",
                Curl_strerror(conn, data->state.os_errno));
          return CURLE_HTTP_PORT_FAILED;
        }

      } /* end of if  h */
      else {
        failf(data,"could't find my own IP address (%s)", myhost);
        return CURLE_HTTP_PORT_FAILED;
      }
    } /* end of inet_addr */

    else {
      failf(data, "could't find my own IP address (%s)", myhost);
      return CURLE_HTTP_PORT_FAILED;
    }

    return CURLE_OK;

  } /* end of device selection support */
#else
  (void)conn;
  (void)sockfd;
#endif /* end of HAVE_INET_NTOA */

  return CURLE_HTTP_PORT_FAILED;
}
Beispiel #6
0
static CURLcode bindlocal(struct connectdata *conn,
                          curl_socket_t sockfd, int af)
{
  struct SessionHandle *data = conn->data;
  struct sockaddr_in me;
#ifdef ENABLE_IPV6
  struct sockaddr_in6 me6;
#endif
  struct sockaddr *sock = NULL;  /* bind to this address */
  socklen_t socksize = 0; /* size of the data sock points to */
  struct Curl_dns_entry *h=NULL;
  unsigned short port = data->set.localport; /* use this port number, 0 for
                                                "random" */
  /* how many port numbers to try to bind to, increasing one at a time */
  int portnum = data->set.localportrange;
  const char *dev = data->set.str[STRING_DEVICE];
  int error;

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if(dev && (strlen(dev)<255) ) {
    char myhost[256] = "";
    int rc;
    bool was_iface = FALSE;

    if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
      /*
       * We now have the numerical IP address in the 'myhost' buffer
       */
      rc = Curl_resolv(conn, myhost, 0, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_wait_for_resolv(conn, &h);

      if(h) {
        was_iface = TRUE;
      }
    }

    if(!was_iface) {
      /*
       * This was not an interface, resolve the name as a host name
       * or IP number
       */

      /*
       * Temporarily force name resolution to use only the address type
       * of the connection. The resolve functions should really be changed
       * to take a type parameter instead.
       */
      long ipver = data->set.ip_version;
      if (af == AF_INET)
        data->set.ip_version = CURL_IPRESOLVE_V4;
#ifdef ENABLE_IPV6
      else if (af == AF_INET6)
        data->set.ip_version = CURL_IPRESOLVE_V6;
#endif

      rc = Curl_resolv(conn, dev, 0, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_wait_for_resolv(conn, &h);
      data->set.ip_version = ipver;

      if(h) {
        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
        Curl_printable_address(h->addr, myhost, sizeof myhost);
      }
    }

    if(!*myhost || !h) {
      /* need to fix this
         h=Curl_gethost(data,
         getmyhost(*myhost,sizeof(myhost)),
         hostent_buf,
         sizeof(hostent_buf));
      */
      failf(data, "Couldn't bind to '%s'", dev);
      if(h)
        Curl_resolv_unlock(data, h);
      return CURLE_INTERFACE_FAILED;
    }

    infof(data, "Bind local address to %s\n", myhost);

    sock = h->addr->ai_addr;
    socksize = h->addr->ai_addrlen;

#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.
     *
     */
    if(was_iface) {
      /* 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, 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
  }
  else if(port) {
    /* if a local port number is requested but no local IP, extract the
       address from the socket */
    if(af == AF_INET) {
      memset(&me, 0, sizeof(me));
      me.sin_family = AF_INET;
      me.sin_addr.s_addr = INADDR_ANY;

      sock = (struct sockaddr *)&me;
      socksize = sizeof(me);

    }
#ifdef ENABLE_IPV6
    else { /* AF_INET6 */
      memset(&me6, 0, sizeof(me6));
      me6.sin6_family = AF_INET6;
      /* in6addr_any isn't always available and since me6 has just been
         cleared, it's not strictly necessary to use it here */
      /*me6.sin6_addr = in6addr_any;*/

      sock = (struct sockaddr *)&me6;
      socksize = sizeof(me6);
    }
#endif
  }
  else
    /* no local kind of binding was requested */
    return CURLE_OK;

  do {

    /* Set port number to bind to, 0 makes the system pick one */
    if(sock->sa_family == AF_INET)
      me.sin_port = htons(port);
#ifdef ENABLE_IPV6
    else
      me6.sin6_port = htons(port);
#endif

    if( bind(sockfd, sock, socksize) >= 0) {
      /* we succeeded to bind */
      struct Curl_sockaddr_storage add;
      socklen_t size = sizeof(add);
      memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
      if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
        data->state.os_errno = error = SOCKERRNO;
        failf(data, "getsockname() failed with errno %d: %s",
              error, Curl_strerror(conn, error));
        if(h)
          Curl_resolv_unlock(data, h);
        return CURLE_INTERFACE_FAILED;
      }
      /* We re-use/clobber the port variable here below */
      if(((struct sockaddr *)&add)->sa_family == AF_INET)
        port = ntohs(((struct sockaddr_in *)&add)->sin_port);
#ifdef ENABLE_IPV6
      else
        port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
#endif
      infof(data, "Local port: %d\n", port);
      conn->bits.bound = TRUE;
      if(h)
        Curl_resolv_unlock(data, h);
      return CURLE_OK;
    }
    if(--portnum > 0) {
      infof(data, "Bind to local port %d failed, trying next\n", port);
      port++; /* try next port */
    }
    else
      break;
  } while(1);

  data->state.os_errno = error = SOCKERRNO;
  failf(data, "bind failed with errno %d: %s",
        error, Curl_strerror(conn, error));
  if(h)
    Curl_resolv_unlock(data, h);

  return CURLE_INTERFACE_FAILED;
}
Beispiel #7
0
static CURLcode bindlocal(struct connectdata *conn,
                          curl_socket_t sockfd)
{
#ifdef HAVE_INET_NTOA
  bool bindworked = FALSE;
  struct SessionHandle *data = conn->data;

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if (strlen(data->set.device)<255) {
    struct Curl_dns_entry *h=NULL;
    size_t size;
    char myhost[256] = "";
    in_addr_t in;
    int rc;
    bool was_iface = FALSE;

    /* First check if the given name is an IP address */
    in=inet_addr(data->set.device);
      
    if((in == CURL_INADDR_NONE) &&
       Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
      /*
       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
       */
      rc = Curl_resolv(conn, myhost, 0, &h);
      if(rc == 1)
        (void)Curl_wait_for_resolv(conn, &h);

      if(h)
        was_iface = TRUE;
    }

    if(!was_iface) {
      /*
       * This was not an interface, resolve the name as a host name
       * or IP number
       */
      rc = Curl_resolv(conn, data->set.device, 0, &h);
      if(rc == 1)
        (void)Curl_wait_for_resolv(conn, &h);

      if(h)
        /* we know data->set.device is shorter than the myhost array */
        strcpy(myhost, data->set.device);
    }

    if(! *myhost) {
      /* need to fix this
         h=Curl_gethost(data,
         getmyhost(*myhost,sizeof(myhost)),
         hostent_buf,
         sizeof(hostent_buf));
      */
      failf(data, "Couldn't bind to '%s'", data->set.device);
      return CURLE_HTTP_PORT_FAILED;
    }

    infof(data, "We bind local end to %s\n", myhost);

#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.
     *
     */
    if (was_iface) {
      /* Only bind to the interface when specified as interface, not just as a
       * hostname or ip address.
       */
      if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                     data->set.device, strlen(data->set.device)+1) != 0) {
        /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
           sockfd, data->set.device, strerror(errno)); */
        infof(data, "SO_BINDTODEVICE %s failed\n",
              data->set.device);
        /* This is typiclally "errno 1, error: Operation not permitted" if
           you're not running as root or another suitable privileged user */
      }
    }
#endif

    in=inet_addr(myhost);
    if (CURL_INADDR_NONE != in) {

      if ( h ) {
        Curl_addrinfo *addr = h->addr;

        Curl_resolv_unlock(data, h);
        /* we don't need it anymore after this function has returned */

#ifdef ENABLE_IPV6
        if( bind(sockfd, addr->ai_addr, addr->ai_addrlen) >= 0) {
          /* we succeeded to bind */
          struct sockaddr_in6 add;

          bindworked = TRUE;
	
          size = sizeof(add);
          if(getsockname(sockfd, (struct sockaddr *) &add,
                         (socklen_t *)&size)<0) {
            failf(data, "getsockname() failed");
            return CURLE_HTTP_PORT_FAILED;
          }
        }
#else
        {
          struct sockaddr_in sa;

          memset((char *)&sa, 0, sizeof(sa));
          memcpy((char *)&sa.sin_addr, addr->h_addr, addr->h_length);
          sa.sin_family = AF_INET;
          sa.sin_addr.s_addr = in;
          sa.sin_port = 0; /* get any port */
	
          if( bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
            /* we succeeded to bind */
            struct sockaddr_in add;
	
            bindworked = TRUE;
            
            size = sizeof(add);
            if(getsockname(sockfd, (struct sockaddr *) &add,
                           (socklen_t *)&size)<0) {
              failf(data, "getsockname() failed");
              return CURLE_HTTP_PORT_FAILED;
            }
          }
        }
#endif
        if(!bindworked) {
          switch(errno) {
          case EBADF:
            failf(data, "Invalid descriptor: %d", errno);
            break;
          case EINVAL:
            failf(data, "Invalid request: %d", errno);
            break;
          case EACCES:
            failf(data, "Address is protected, user not superuser: %d", errno);
            break;
          case ENOTSOCK:
            failf(data,
                  "Argument is a descriptor for a file, not a socket: %d",
                  errno);
            break;
          case EFAULT:
            failf(data, "Inaccessable memory error: %d", errno);
            break;
          case ENAMETOOLONG:
            failf(data, "Address too long: %d", errno);
            break;
          case ENOMEM:
            failf(data, "Insufficient kernel memory was available: %d", errno);
            break;
          default:
            failf(data, "errno %d", errno);
            break;
          } /* end of switch(errno) */
	
          return CURLE_HTTP_PORT_FAILED;
        } /* end of else */
	
      } /* end of if  h */
      else {
	failf(data,"could't find my own IP address (%s)", myhost);
	return CURLE_HTTP_PORT_FAILED;
      }
    } /* end of inet_addr */

    else {
      failf(data, "could't find my own IP address (%s)", myhost);
      return CURLE_HTTP_PORT_FAILED;
    }

    return CURLE_OK;

  } /* end of device selection support */
#endif /* end of HAVE_INET_NTOA */

  return CURLE_HTTP_PORT_FAILED;
}
Beispiel #8
0
static CURLcode bindlocal(struct connectdata *conn,
                          int sockfd)
{
#if !defined(WIN32)||defined(__CYGWIN32__)
  /* We don't generally like checking for OS-versions, we should make this
     HAVE_XXXX based, although at the moment I don't have a decent test for
     this! */

#ifdef HAVE_INET_NTOA

  struct SessionHandle *data = conn->data;

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if (strlen(data->set.device)<255) {
    struct sockaddr_in sa;
    struct Curl_dns_entry *h=NULL;
    size_t size;
    char myhost[256] = "";
    in_addr_t in;

    /* First check if the given name is an IP address */
    in=inet_addr(data->set.device);
      
    if((in == CURL_INADDR_NONE) &&
       Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
      /*
       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
       */
      h = Curl_resolv(data, myhost, 0);
    }
    else {
      if(strlen(data->set.device)>1) {
        /*
         * This was not an interface, resolve the name as a host name
         * or IP number
         */
        h = Curl_resolv(data, data->set.device, 0);
        if(h) {
          /* we know data->set.device is shorter than the myhost array */
          strcpy(myhost, data->set.device);
        }
      }
    }

    if(! *myhost) {
      /* need to fix this
         h=Curl_gethost(data,
         getmyhost(*myhost,sizeof(myhost)),
         hostent_buf,
         sizeof(hostent_buf));
      */
      return CURLE_HTTP_PORT_FAILED;
    }

    infof(data, "We bind local end to %s\n", myhost);

    in=inet_addr(myhost);
    if (CURL_INADDR_NONE != in) {

      if ( h ) {
        Curl_addrinfo *addr = h->addr;

        Curl_resolv_unlock(data, h);
        /* we don't need it anymore after this function has returned */

#ifdef ENABLE_IPV6
        (void)sa; /* prevent compiler warning */
        if( bind(sockfd, addr->ai_addr, addr->ai_addrlen) >= 0) {
          /* we succeeded to bind */
          struct sockaddr_in6 add;
	
          size = sizeof(add);
          if(getsockname(sockfd, (struct sockaddr *) &add,
                         (socklen_t *)&size)<0) {
            failf(data, "getsockname() failed");
            return CURLE_HTTP_PORT_FAILED;
          }
        }
#else
        memset((char *)&sa, 0, sizeof(sa));
        memcpy((char *)&sa.sin_addr, addr->h_addr, addr->h_length);
        sa.sin_family = AF_INET;
        sa.sin_addr.s_addr = in;
        sa.sin_port = 0; /* get any port */
	
        if( bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
          /* we succeeded to bind */
          struct sockaddr_in add;
	
          size = sizeof(add);
          if(getsockname(sockfd, (struct sockaddr *) &add,
                         (socklen_t *)&size)<0) {
            failf(data, "getsockname() failed");
            return CURLE_HTTP_PORT_FAILED;
          }
        }
#endif
        else {
          switch(errno) {
          case EBADF:
            failf(data, "Invalid descriptor: %d", errno);
            break;
          case EINVAL:
            failf(data, "Invalid request: %d", errno);
            break;
          case EACCES:
            failf(data, "Address is protected, user not superuser: %d", errno);
            break;
          case ENOTSOCK:
            failf(data,
                  "Argument is a descriptor for a file, not a socket: %d",
                  errno);
            break;
          case EFAULT:
            failf(data, "Inaccessable memory error: %d", errno);
            break;
          case ENAMETOOLONG:
            failf(data, "Address too long: %d", errno);
            break;
          case ENOMEM:
            failf(data, "Insufficient kernel memory was available: %d", errno);
            break;
          default:
            failf(data, "errno %d", errno);
            break;
          } /* end of switch(errno) */
	
          return CURLE_HTTP_PORT_FAILED;
        } /* end of else */
	
      } /* end of if  h */
      else {
	failf(data,"could't find my own IP address (%s)", myhost);
	return CURLE_HTTP_PORT_FAILED;
      }
    } /* end of inet_addr */

    else {
      failf(data, "could't find my own IP address (%s)", myhost);
      return CURLE_HTTP_PORT_FAILED;
    }

    return CURLE_OK;

  } /* end of device selection support */
#endif /* end of HAVE_INET_NTOA */
#endif /* end of not WIN32 */

  return CURLE_HTTP_PORT_FAILED;
}
Beispiel #9
0
static CURLcode bindlocal(struct connectdata *conn,
                          curl_socket_t sockfd, int af, unsigned int scope)
{
  struct Curl_easy *data = conn->data;

  struct Curl_sockaddr_storage sa;
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
#ifdef ENABLE_IPV6
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif

  struct Curl_dns_entry *h = NULL;
  unsigned short port = data->set.localport; /* use this port number, 0 for
                                                "random" */
  /* how many port numbers to try to bind to, increasing one at a time */
  int portnum = data->set.localportrange;
  const char *dev = data->set.str[STRING_DEVICE];
  int error;

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if(!dev && !port)
    /* no local kind of binding was requested */
    return CURLE_OK;

  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));

  if(dev && (strlen(dev)<255) ) {
    char myhost[256] = "";
    int done = 0; /* -1 for error, 1 for address found */
    bool is_interface = FALSE;
    bool is_host = FALSE;
    static const char *if_prefix = "if!";
    static const char *host_prefix = "host!";

    if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
      dev += strlen(if_prefix);
      is_interface = TRUE;
    }
    else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
      dev += strlen(host_prefix);
      is_host = TRUE;
    }

    /* 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:
          if(is_interface) {
            /* Do not fall back to treating it as a host name */
            failf(data, "Couldn't bind to interface '%s'", dev);
            return CURLE_INTERFACE_FAILED;
          }
          break;
        case IF2IP_AF_NOT_SUPPORTED:
          /* Signal the caller to try another address family if available */
          return CURLE_UNSUPPORTED_PROTOCOL;
        case IF2IP_FOUND:
          is_interface = TRUE;
          /*
           * We now have the numerical IP address in the 'myhost' buffer
           */
          infof(data, "Local Interface %s is ip %s using address family %i\n",
                dev, myhost, af);
          done = 1;
          break;
      }
    }
    if(!is_interface) {
      /*
       * This was not an interface, resolve the name as a host name
       * or IP number
       *
       * Temporarily force name resolution to use only the address type
       * of the connection. The resolve functions should really be changed
       * to take a type parameter instead.
       */
      long ipver = conn->ip_version;
      int rc;

      if(af == AF_INET)
        conn->ip_version = CURL_IPRESOLVE_V4;
#ifdef ENABLE_IPV6
      else if(af == AF_INET6)
        conn->ip_version = CURL_IPRESOLVE_V6;
#endif

      rc = Curl_resolv(conn, dev, 0, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_resolver_wait_resolv(conn, &h);
      conn->ip_version = ipver;

      if(h) {
        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
        Curl_printable_address(h->addr, myhost, sizeof(myhost));
        infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
              dev, af, myhost, h->addr->ai_family);
        Curl_resolv_unlock(data, h);
        done = 1;
      }
      else {
        /*
         * provided dev was no interface (or interfaces are not supported
         * e.g. solaris) no ip address and no domain we fail here
         */
        done = -1;
      }
    }

    if(done > 0) {
#ifdef ENABLE_IPV6
      /* IPv6 address */
      if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
        char *scope_ptr = strchr(myhost, '%');
        if(scope_ptr)
          *(scope_ptr++) = 0;
#endif
        if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
          si6->sin6_family = AF_INET6;
          si6->sin6_port = htons(port);
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
          if(scope_ptr)
            /* The "myhost" string either comes from Curl_if2ip or from
               Curl_printable_address. The latter returns only numeric scope
               IDs and the former returns none at all.  So the scope ID, if
               present, is known to be numeric */
            si6->sin6_scope_id = atoi(scope_ptr);
#endif
        }
        sizeof_sa = sizeof(struct sockaddr_in6);
      }
      else
#endif
      /* IPv4 address */
      if((af == AF_INET) &&
         (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
        si4->sin_family = AF_INET;
        si4->sin_port = htons(port);
        sizeof_sa = sizeof(struct sockaddr_in);
      }
    }

    if(done < 1) {
      /* errorbuf is set false so failf will overwrite any message already in
         the error buffer, so the user receives this error message instead of a
         generic resolve error. */
      data->state.errorbuf = FALSE;
      failf(data, "Couldn't bind to '%s'", dev);
      return CURLE_INTERFACE_FAILED;
    }
  }
  else {
    /* no device was given, prepare sa to match af's needs */
#ifdef ENABLE_IPV6
    if(af == AF_INET6) {
      si6->sin6_family = AF_INET6;
      si6->sin6_port = htons(port);
      sizeof_sa = sizeof(struct sockaddr_in6);
    }
    else
#endif
    if(af == AF_INET) {
      si4->sin_family = AF_INET;
      si4->sin_port = htons(port);
      sizeof_sa = sizeof(struct sockaddr_in);
    }
  }

  for(;;) {
    if(bind(sockfd, sock, sizeof_sa) >= 0) {
      /* we succeeded to bind */
      struct Curl_sockaddr_storage add;
      curl_socklen_t size = sizeof(add);
      memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
      if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
        data->state.os_errno = error = SOCKERRNO;
        failf(data, "getsockname() failed with errno %d: %s",
              error, Curl_strerror(conn, error));
        return CURLE_INTERFACE_FAILED;
      }
      infof(data, "Local port: %hu\n", port);
      conn->bits.bound = TRUE;
      return CURLE_OK;
    }

    if(--portnum > 0) {
      infof(data, "Bind to local port %hu failed, trying next\n", port);
      port++; /* try next port */
      /* We re-use/clobber the port variable here below */
      if(sock->sa_family == AF_INET)
        si4->sin_port = ntohs(port);
#ifdef ENABLE_IPV6
      else
        si6->sin6_port = ntohs(port);
#endif
    }
    else
      break;
  }

  data->state.os_errno = error = SOCKERRNO;
  failf(data, "bind failed with errno %d: %s",
        error, Curl_strerror(conn, error));

  return CURLE_INTERFACE_FAILED;
}