Exemplo n.º 1
0
/* retrieves ip address and port from a sockaddr structure */
static bool getaddressinfo(struct sockaddr* sa, char* addr,
                           long* port)
{
    unsigned short us_port;
    struct sockaddr_in* si = NULL;
#ifdef ENABLE_IPV6
    struct sockaddr_in6* si6 = NULL;
#endif

    switch (sa->sa_family) {
    case AF_INET:
        si = (struct sockaddr_in*) sa;
        if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
                          addr, MAX_IPADR_LEN) == NULL)
            return FALSE;
        us_port = ntohs(si->sin_port);
        *port = us_port;
        break;
#ifdef ENABLE_IPV6
    case AF_INET6:
        si6 = (struct sockaddr_in6*)sa;
        if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
                          addr, MAX_IPADR_LEN) == NULL)
            return FALSE;
        us_port = ntohs(si6->sin6_port);
        *port = us_port;
        break;
#endif
    default:
        addr[0] = '\0';
        *port = 0;
    }
    return TRUE;
}
Exemplo n.º 2
0
/*
 * Curl_printable_address() returns a printable version of the 1st address
 * given in the 'ai' argument. The result will be stored in the buf that is
 * bufsize bytes big.
 *
 * If the conversion fails, it returns NULL.
 */
const char *
Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
{
  const struct sockaddr_in *sa4;
  const struct in_addr *ipaddr4;
#ifdef ENABLE_IPV6
  const struct sockaddr_in6 *sa6;
  const struct in6_addr *ipaddr6;
#endif

  switch (ai->ai_family) {
    case AF_INET:
      sa4 = (const void *)ai->ai_addr;
      ipaddr4 = &sa4->sin_addr;
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
                            bufsize);
#ifdef ENABLE_IPV6
    case AF_INET6:
      sa6 = (const void *)ai->ai_addr;
      ipaddr6 = &sa6->sin6_addr;
      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
                            bufsize);
#endif
    default:
      break;
  }
  return NULL;
}
Exemplo n.º 3
0
/* retrieves ip address and port from a sockaddr structure */
static bool getaddressinfo(struct sockaddr* sa, char* addr,
                           long* port)
{
  unsigned short us_port;
  struct sockaddr_in* si = NULL;
#ifdef ENABLE_IPV6
  struct sockaddr_in6* si6 = NULL;
#endif
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
  struct sockaddr_un* su = NULL;
#endif

  switch (sa->sa_family) {
    case AF_INET:
      si = (struct sockaddr_in*) sa;
      if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
                        addr, MAX_IPADR_LEN)) {
        us_port = ntohs(si->sin_port);
        *port = us_port;
        return TRUE;
      }
      break;
#ifdef ENABLE_IPV6
    case AF_INET6:
      si6 = (struct sockaddr_in6*)sa;
      if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
                        addr, MAX_IPADR_LEN)) {
        us_port = ntohs(si6->sin6_port);
        *port = us_port;
        return TRUE;
      }
      break;
#endif
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
    case AF_UNIX:
      su = (struct sockaddr_un*)sa;
      snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
      *port = 0;
      return TRUE;
#endif
    default:
      break;
  }

  addr[0] = '\0';
  *port = 0;

  return FALSE;
}
Exemplo n.º 4
0
char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size)
{
  struct ifaddrs *iface, *head;
  char *ip=NULL;

  if (getifaddrs(&head) >= 0) {
    for (iface=head; iface != NULL; iface=iface->ifa_next) {
      if ((iface->ifa_addr != NULL) &&
          (iface->ifa_addr->sa_family == af) &&
          curl_strequal(iface->ifa_name, interface)) {
        void *addr;
        char scope[12]="";
#ifdef ENABLE_IPV6
        if (af == AF_INET6) {
          unsigned int scopeid = 0;
          addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
          /* Include the scope of this interface as part of the address */
          scopeid = ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
#endif
          if (scopeid)
            snprintf(scope, sizeof(scope), "%%%u", scopeid);
        }
        else
#endif
          addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
        ip = (char *) Curl_inet_ntop(af, addr, buf, buf_size);
        strlcat(buf, scope, buf_size);
        break;
      }
    }
    freeifaddrs(head);
  }
  return ip;
}
Exemplo n.º 5
0
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
                          const char *interf, char *buf, int buf_size)
{
  struct ifaddrs *iface, *head;
  if2ip_result_t res = IF2IP_NOT_FOUND;

#ifndef ENABLE_IPV6
  (void) remote_scope;
#endif

  if(getifaddrs(&head) >= 0) {
    for(iface=head; iface != NULL; iface=iface->ifa_next) {
      if(iface->ifa_addr != NULL) {
        if(iface->ifa_addr->sa_family == af) {
          if(curl_strequal(iface->ifa_name, interf)) {
            void *addr;
            char *ip;
            char scope[12]="";
            char ipstr[64];
#ifdef ENABLE_IPV6
            if(af == AF_INET6) {
              unsigned int scopeid = 0;
              addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
              /* Include the scope of this interface as part of the address */
              scopeid =
                ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
#endif
              if(scopeid != remote_scope) {
                /* We are interested only in interface addresses whose
                   scope ID matches the remote address we want to
                   connect to: global (0) for global, link-local for
                   link-local, etc... */
                if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED;
                continue;
              }
              if(scopeid)
                snprintf(scope, sizeof(scope), "%%%u", scopeid);
            }
            else
#endif
              addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
            res = IF2IP_FOUND;
            ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
            snprintf(buf, buf_size, "%s%s", ip, scope);
            break;
          }
        }
        else if((res == IF2IP_NOT_FOUND) &&
                curl_strequal(iface->ifa_name, interf)) {
          res = IF2IP_AF_NOT_SUPPORTED;
        }
      }
    }
    freeifaddrs(head);
  }
  return res;
}
Exemplo n.º 6
0
/*
 * Curl_printable_address() returns a printable version of the 1st address
 * given in the 'ip' argument. The result will be stored in the buf that is
 * bufsize bytes big.
 *
 * If the conversion fails, it returns NULL.
 */
const char *Curl_printable_address( const Curl_addrinfo *ip,
									char *buf, size_t bufsize ) {
	const void *ip4 = &( (const struct sockaddr_in*)ip->ai_addr )->sin_addr;
	int af = ip->ai_family;
#ifdef CURLRES_IPV6
	const void *ip6 = &( (const struct sockaddr_in6*)ip->ai_addr )->sin6_addr;
#else
	const void *ip6 = NULL;
#endif

	return Curl_inet_ntop( af, af == AF_INET ? ip4 : ip6, buf, bufsize );
}
Exemplo n.º 7
0
char *Curl_if2ip(const char *interface, char *buf, int buf_size)
{
  int dummy;
  char *ip=NULL;

  if(!interface)
    return NULL;

  dummy = socket(AF_INET, SOCK_STREAM, 0);
  if (SYS_ERROR == dummy) {
    return NULL;
  }
  else {
    struct ifreq req;
    size_t len = strlen(interface);
    memset(&req, 0, sizeof(req));
    if(len >= sizeof(req.ifr_name)) {
      sclose(dummy);
      return NULL; /* this can't be a fine interface name */
    }
    memcpy(req.ifr_name, interface, len+1);
    req.ifr_addr.sa_family = AF_INET;
#ifdef IOCTL_3_ARGS
    if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req)) {
#else
    if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req, sizeof(req))) {
#endif
      sclose(dummy);
      return NULL;
    }
    else {
      struct in_addr in;

      struct sockaddr_in *s = (struct sockaddr_in *)&req.ifr_dstaddr;
      memcpy(&in, &s->sin_addr, sizeof(in));
      ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
    }
    sclose(dummy);
  }
  return ip;
}

/* -- end of if2ip() -- */
#else
char *Curl_if2ip(const char *interf, char *buf, int buf_size)
{
    (void) interf;
    (void) buf;
    (void) buf_size;
    return NULL;
}
Exemplo n.º 8
0
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
                          unsigned int remote_scope_id, const char *interf,
                          char *buf, int buf_size)
{
  struct ifreq req;
  struct in_addr in;
  struct sockaddr_in *s;
  curl_socket_t dummy;
  size_t len;

  (void)remote_scope;
  (void)remote_scope_id;

  if(!interf || (af != AF_INET))
    return IF2IP_NOT_FOUND;

  len = strlen(interf);
  if(len >= sizeof(req.ifr_name))
    return IF2IP_NOT_FOUND;

  dummy = socket(AF_INET, SOCK_STREAM, 0);
  if(CURL_SOCKET_BAD == dummy)
    return IF2IP_NOT_FOUND;

  memset(&req, 0, sizeof(req));
  memcpy(req.ifr_name, interf, len+1);
  req.ifr_addr.sa_family = AF_INET;

  if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
    sclose(dummy);
    /* With SIOCGIFADDR, we cannot tell the difference between an interface
       that does not exist and an interface that has no address of the
       correct family. Assume the interface does not exist */
    return IF2IP_NOT_FOUND;
  }

  s = (struct sockaddr_in *)&req.ifr_addr;
  memcpy(&in, &s->sin_addr, sizeof(in));
  Curl_inet_ntop(s->sin_family, &in, buf, buf_size);

  sclose(dummy);
  return IF2IP_FOUND;
}
Exemplo n.º 9
0
char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size)
{
  struct ifreq req;
  struct in_addr in;
  struct sockaddr_in *s;
  curl_socket_t dummy;
  size_t len;
  char *ip;

  if(!interface || (af != AF_INET))
    return NULL;

  len = strlen(interface);
  if(len >= sizeof(req.ifr_name))
    return NULL;

  dummy = socket(AF_INET, SOCK_STREAM, 0);
  if(CURL_SOCKET_BAD == dummy)
    return NULL;

  memset(&req, 0, sizeof(req));
  memcpy(req.ifr_name, interface, len+1);
  req.ifr_addr.sa_family = AF_INET;

  if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
    sclose(dummy);
    return NULL;
  }

  s = (struct sockaddr_in *)&req.ifr_addr;
  memcpy(&in, &s->sin_addr, sizeof(in));
  ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size);

  sclose(dummy);
  return ip;
}
Exemplo n.º 10
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;

}
Exemplo n.º 11
0
/* singleipconnect() connects to the given IP only, and it may return without
   having connected if used from the multi interface. */
static curl_socket_t
singleipconnect(struct connectdata *conn,
                const Curl_addrinfo *ai,
                long timeout_ms,
                bool *connected)
{
    struct Curl_sockaddr_ex addr;
    char addr_buf[128];
    int rc;
    int error;
    bool isconnected;
    struct SessionHandle *data = conn->data;
    curl_socket_t sockfd;
    CURLcode res;
    const void *iptoprint;
    struct sockaddr_in * const sa4 = (void *)&addr.sa_addr;
#ifdef ENABLE_IPV6
    struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
#endif

    /*
     * The Curl_sockaddr_ex structure is basically libcurl's external API
     * curl_sockaddr structure with enough space available to directly hold
     * any protocol-specific address structures. The variable declared here
     * will be used to pass / receive data to/from the fopensocket callback
     * if this has been set, before that, it is initialized from parameters.
     */

    addr.family = ai->ai_family;
    addr.socktype = conn->socktype;
    addr.protocol = ai->ai_protocol;
    addr.addrlen = ai->ai_addrlen;

    if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
        addr.addrlen = sizeof(struct Curl_sockaddr_storage);
    memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);

    *connected = FALSE; /* default is not connected */

    if(data->set.fopensocket)
        /*
         * If the opensocket callback is set, all the destination address
         * information is passed to the callback. Depending on this information the
         * callback may opt to abort the connection, this is indicated returning
         * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
         * the callback returns a valid socket the destination address information
         * might have been changed and this 'new' address will actually be used
         * here to connect.
         */
        sockfd = data->set.fopensocket(data->set.opensocket_client,
                                       CURLSOCKTYPE_IPCXN,
                                       (struct curl_sockaddr *)&addr);
    else
        /* opensocket callback not set, so simply create the socket now */
        sockfd = socket(addr.family, addr.socktype, addr.protocol);

    if(sockfd == CURL_SOCKET_BAD)
        /* no socket, no connection */
        return CURL_SOCKET_BAD;

#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
    if (conn->scope && (addr.family == AF_INET6))
        sa6->sin6_scope_id = conn->scope;
#endif

    /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
       argument? */
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
    if(addr.family == AF_UNIX) {
        infof(data, "  Trying %s... ",
              ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
        snprintf(data->info.ip, MAX_IPADR_LEN, "%s",
                 ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
        strcpy(conn->ip_addr_str, data->info.ip);
    }
    else
#endif
    {
#ifdef ENABLE_IPV6
        if(addr.family == AF_INET6) {
            iptoprint = &sa6->sin6_addr;
            conn->bits.ipv6 = TRUE;
        }
        else
#endif
        {
            iptoprint = &sa4->sin_addr;
        }

        if(Curl_inet_ntop(addr.family, iptoprint, addr_buf,
                          sizeof(addr_buf)) != NULL) {
            infof(data, "  Trying %s... ", addr_buf);
            snprintf(data->info.ip, MAX_IPADR_LEN, "%s", addr_buf);
            strcpy(conn->ip_addr_str, data->info.ip);
        }
    }

    if(data->set.tcp_nodelay)
        tcpnodelay(conn, sockfd);

    nosigpipe(conn, sockfd);

    Curl_sndbufset(sockfd);

    if(data->set.fsockopt) {
        /* activate callback for setting socket options */
        error = data->set.fsockopt(data->set.sockopt_client,
                                   sockfd,
                                   CURLSOCKTYPE_IPCXN);
        if(error) {
            sclose(sockfd); /* close the socket and bail out */
            return CURL_SOCKET_BAD;
        }
    }

    /* possibly bind the local end to an IP, interface or port */
    res = bindlocal(conn, sockfd, addr.family);
    if(res) {
        sclose(sockfd); /* close socket and bail out */
        return CURL_SOCKET_BAD;
    }

    /* set socket non-blocking */
    curlx_nonblock(sockfd, TRUE);

    /* Connect TCP sockets, bind UDP */
    if(conn->socktype == SOCK_STREAM)
        rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
    else
        rc = 0;

    if(-1 == rc) {
        error = SOCKERRNO;

        switch (error) {
        case EINPROGRESS:
        case EWOULDBLOCK:
#if defined(EAGAIN)
#if (EAGAIN) != (EWOULDBLOCK)
        /* On some platforms EAGAIN and EWOULDBLOCK are the
         * same value, and on others they are different, hence
         * the odd #if
         */
        case EAGAIN:
#endif
#endif
            rc = waitconnect(conn, sockfd, timeout_ms);
            break;
        default:
            /* unknown error, fallthrough and try another address! */
            failf(data, "Failed to connect to %s: %s",
                  addr_buf, Curl_strerror(conn,error));
            data->state.os_errno = error;
            break;
        }
    }

    /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
       connect(). We can be sure of this since connect() cannot return 1. */
    if((WAITCONN_TIMEOUT == rc) &&
            (data->state.used_interface == Curl_if_multi)) {
        /* Timeout when running the multi interface */
        return sockfd;
    }

    isconnected = verifyconnect(sockfd, &error);

    if(!rc && isconnected) {
        /* we are connected, awesome! */
        *connected = TRUE; /* this is a true connect */
        infof(data, "connected\n");
        Curl_updateconninfo(conn, sockfd);
        return sockfd;
    }
    else if(WAITCONN_TIMEOUT == rc)
        infof(data, "Timeout\n");
    else {
        data->state.os_errno = error;
        infof(data, "%s\n", Curl_strerror(conn, error));
    }

    /* connect failed or timed out */
    sclose(sockfd);

    return CURL_SOCKET_BAD;
}
Exemplo n.º 12
0
static int
krb4_auth(void *app_data, struct connectdata *conn)
{
  int ret;
  char *p;
  unsigned char *ptr;
  size_t len;
  KTEXT_ST adat;
  MSG_DAT msg_data;
  int checksum;
  u_int32_t cs;
  struct krb4_data *d = app_data;
  char *host = conn->host.name;
  ssize_t nread;
  int l = sizeof(conn->local_addr);
  struct SessionHandle *data = conn->data;
  CURLcode result;

  if(getsockname(conn->sock[FIRSTSOCKET],
                 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
    perror("getsockname()");

  checksum = getpid();
  ret = mk_auth(d, &adat, "ftp", host, checksum);
  if(ret == KDC_PR_UNKNOWN)
    ret = mk_auth(d, &adat, "rcmd", host, checksum);
  if(ret) {
    infof(data, "%s\n", krb_get_err_text(ret));
    return AUTH_CONTINUE;
  }

#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
  if(krb_get_config_bool("nat_in_use")) {
    struct sockaddr_in *localaddr  = (struct sockaddr_in *)LOCAL_ADDR;
    struct in_addr natAddr;

    if(krb_get_our_ip_for_realm(krb_realmofhost(host),
                                 &natAddr) != KSUCCESS
        && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
      infof(data, "Can't get address for realm %s\n",
                 krb_realmofhost(host));
    else {
      if(natAddr.s_addr != localaddr->sin_addr.s_addr) {
        char addr_buf[128];
        if(Curl_inet_ntop(AF_INET, natAddr, addr_buf, sizeof(addr_buf)))
          infof(data, "Using NAT IP address (%s) for kerberos 4\n", addr_buf);
        localaddr->sin_addr = natAddr;
      }
    }
  }
#endif

  if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) {
    Curl_failf(data, "Out of memory base64-encoding");
    return AUTH_CONTINUE;
  }

  result = Curl_ftpsendf(conn, "ADAT %s", p);

  free(p);

  if(result)
    return -2;

  if(Curl_GetFTPResponse(&nread, conn, NULL))
    return -1;

  if(data->state.buffer[0] != '2'){
    Curl_failf(data, "Server didn't accept auth data");
    return AUTH_ERROR;
  }

  p = strstr(data->state.buffer, "ADAT=");
  if(!p) {
    Curl_failf(data, "Remote host didn't send adat reply");
    return AUTH_ERROR;
  }
  p += 5;
  len = Curl_base64_decode(p, &ptr);
  if(len > sizeof(adat.dat)-1) {
    free(ptr);
    len=0;
  }
  if(!len || !ptr) {
    Curl_failf(data, "Failed to decode base64 from server");
    return AUTH_ERROR;
  }
  memcpy((char *)adat.dat, ptr, len);
  free(ptr);
  adat.length = len;
  ret = krb_rd_safe(adat.dat, adat.length, &d->key,
                    (struct sockaddr_in *)hisctladdr,
                    (struct sockaddr_in *)myctladdr, &msg_data);
  if(ret) {
    Curl_failf(data, "Error reading reply from server: %s",
               krb_get_err_text(ret));
    return AUTH_ERROR;
  }
  krb_get_int(msg_data.app_data, &cs, 4, 0);
  if(cs - checksum != 1) {
    Curl_failf(data, "Bad checksum returned from server");
    return AUTH_ERROR;
  }
  return AUTH_OK;
}