Beispiel #1
0
END_TEST

START_TEST (inet_connect_test) {
  int sockfd = -1, port = INPORT_ANY, res;
  conn_t *conn;
  pr_netaddr_t *addr;

  res = pr_inet_connect(NULL, NULL, NULL, port);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE);
  fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno));

  res = pr_inet_connect(p, conn, NULL, 80);
  fail_unless(res < 0, "Failed to handle null connection");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
  fail_unless(addr != NULL, "Failed to resolve '127.0.0.1': %s",
    strerror(errno));

  res = pr_inet_connect(p, conn, addr, 80);
  fail_unless(res < 0, "Connected to 127.0.0.1#80 unexpectedly");

  pr_inet_close(p, conn);
}
Beispiel #2
0
int proxy_inet_connect(pool *p, conn_t *conn, const pr_netaddr_t *addr,
    int port) {
  int instrm_type = -1, outstrm_type = -1, res, xerrno;
  pr_netio_t *in_netio = NULL, *out_netio = NULL;

  if (conn != NULL) {
    if (conn->instrm != NULL) {
      instrm_type = conn->instrm->strm_type;

      in_netio = proxy_netio_unset(instrm_type, "inet_connect");
    }

    if (conn->outstrm != NULL) {
      outstrm_type = conn->outstrm->strm_type;

      if (outstrm_type != instrm_type) {
        out_netio = proxy_netio_unset(outstrm_type, "inet_connect");
      }
    }
  }

  res = pr_inet_connect(p, conn, addr, port);
  xerrno = errno;

  if (in_netio != NULL) {
    proxy_netio_set(instrm_type, in_netio);
  }

  if (out_netio != NULL) {
    proxy_netio_set(outstrm_type, out_netio);
  }

  errno = xerrno;
  return res;
}
Beispiel #3
0
END_TEST

START_TEST (inet_connect_ipv4_test) {
  int sockfd = -1, port = INPORT_ANY, res;
  conn_t *conn;
  const pr_netaddr_t *addr;

  res = pr_inet_connect(NULL, NULL, NULL, port);
  fail_unless(res < 0, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE);
  fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno));

  res = pr_inet_connect(p, conn, NULL, 80);
  fail_unless(res < 0, "Failed to handle null address");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
  fail_unless(addr != NULL, "Failed to resolve '127.0.0.1': %s",
    strerror(errno));

  res = pr_inet_connect(p, conn, addr, 80);
  fail_unless(res < 0, "Connected to 127.0.0.1#80 unexpectedly");
  fail_unless(errno == ECONNREFUSED, "Expected ECONNREFUSED (%d), got %s (%d)",
    ECONNREFUSED, strerror(errno), errno);

  /* Try connecting to Google's DNS server. */

  addr = pr_netaddr_get_addr(p, "8.8.8.8", NULL);
  fail_unless(addr != NULL, "Failed to resolve '8.8.8.8': %s",
    strerror(errno));

  res = pr_inet_connect(p, conn, addr, 53);
  if (res < 0) {
    /* Note: We get EINVAL here because the socket already tried (and failed)
     * to connect to a different address.  Interestingly, trying to connect(2)
     * using that same fd to a different address yields EINVAL.
     */
    fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
      strerror(errno), errno);
  }
  pr_inet_close(p, conn);

  conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE);
  fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno));

  res = pr_inet_connect(p, conn, addr, 53);
  fail_if(res < 0, "Failed to connect to 8.8.8.8#53: %s", strerror(errno));

  res = pr_inet_connect(p, conn, addr, 53);
  fail_unless(res < 0, "Failed to connect to 8.8.8.8#53: %s",
    strerror(errno));
  fail_unless(errno == EISCONN, "Expected EISCONN (%d), got %s (%d)",
    EISCONN, strerror(errno), errno);
  pr_inet_close(p, conn);
}
Beispiel #4
0
static int data_active_open(char *reason, off_t size) {
  conn_t *c;
  int rev;
  pr_netaddr_t *bind_addr;

  if (!reason && session.xfer.filename)
    reason = session.xfer.filename;

  if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(session.c->remote_addr)) {
    bind_addr = session.c->local_addr;

  } else {
    /* In this scenario, the server has an IPv6 socket, but the remote client
     * is an IPv4 (or IPv4-mapped IPv6) peer.
     */
    bind_addr = pr_netaddr_v6tov4(session.xfer.p, session.c->local_addr);
  }

  session.d = pr_inet_create_conn(session.pool, -1, bind_addr,
    session.c->local_port-1, TRUE);

  /* Set the "stalled" timer, if any, to prevent the connection
   * open from taking too long
   */
  if (timeout_stalled) {
    pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb,
      "TimeoutStalled");
  }

  rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS);

  /* Protocol and socket options should be set before handshaking. */

  if (session.xfer.direction == PR_NETIO_IO_RD) {
    pr_inet_set_socket_opts(session.d->pool, session.d,
      (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0);
    
  } else {
    pr_inet_set_socket_opts(session.d->pool, session.d,
      0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0));
  }

  /* Make sure that the necessary socket options are set on the socket prior
   * to the call to connect(2).
   */
  pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len, 0,
    IPTOS_THROUGHPUT, 1);
  pr_inet_generate_socket_event("core.data-connect", main_server,
    session.d->local_addr, session.d->listen_fd);

  if (pr_inet_connect(session.d->pool, session.d, &session.data_addr,
      session.data_port) == -1) {
    pr_response_add_err(R_425, _("Unable to build data connection: %s"),
      strerror(session.d->xerrno));
    destroy_pool(session.d->pool);
    session.d = NULL;
    return -1;
  }

  c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA,
    session.d->listen_fd, -1, -1, TRUE);

  pr_netaddr_set_reverse_dns(rev);

  if (c) {
    pr_log_debug(DEBUG4, "active data connection opened - local  : %s:%d",
      pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port);
    pr_log_debug(DEBUG4, "active data connection opened - remote : %s:%d",
      pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port);

    if (session.xfer.xfer_type != STOR_UNIQUE) {
      if (size)
        pr_response_send(R_150, _("Opening %s mode data connection for %s "
          "(%" PR_LU " bytes)"), MODE_STRING, reason, (pr_off_t) size);
      else
        pr_response_send(R_150, _("Opening %s mode data connection for %s"),
          MODE_STRING, reason);

    } else {

      /* Format of 150 responses for STOU is explicitly dictated by
       * RFC 1123:
       *
       *  4.1.2.9  STOU Command: RFC-959 Section 4.1.3
       *
       *    The STOU command stores into a uniquely named file.  When it
       *    receives an STOU command, a Server-FTP MUST return the
       *    actual file name in the "125 Transfer Starting" or the "150
       *    Opening Data Connection" message that precedes the transfer
       *    (the 250 reply code mentioned in RFC-959 is incorrect).  The
       *    exact format of these messages is hereby defined to be as
       *    follows:
       *
       *        125 FILE: pppp
       *        150 FILE: pppp
       *
       *    where pppp represents the unique pathname of the file that
       *    will be written.
       */
      pr_response_send(R_150, "FILE: %s", reason);
    }

    pr_inet_close(session.pool, session.d);
    pr_inet_set_nonblock(session.pool, session.d);
    session.d = c;
    return 0;
  }

  pr_response_add_err(R_425, _("Unable to build data connection: %s"),
    strerror(session.d->xerrno));
  destroy_pool(session.d->pool);
  session.d = NULL;
  return -1;
}
Beispiel #5
0
END_TEST

START_TEST (inet_connect_ipv6_test) {
#ifdef PR_USE_IPV6
  int sockfd = -1, port = INPORT_ANY, res;
  conn_t *conn;
  const pr_netaddr_t *addr;
  unsigned char use_ipv6;

  use_ipv6 = pr_netaddr_use_ipv6();

  pr_netaddr_enable_ipv6();
  pr_inet_set_default_family(p, AF_INET6);

  conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE);
  fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno));

  addr = pr_netaddr_get_addr(p, "::1", NULL);
  fail_unless(addr != NULL, "Failed to resolve '::1': %s",
    strerror(errno));

  res = pr_inet_connect(p, conn, addr, 80);
  fail_unless(res < 0, "Connected to ::1#80 unexpectedly");
  fail_unless(errno == ECONNREFUSED || errno == ENETUNREACH,
    "Expected ECONNREFUSED (%d) or ENETUNREACH (%d), got %s (%d)",
    ECONNREFUSED, ENETUNREACH, strerror(errno), errno);

  /* Try connecting to Google's DNS server. */

  addr = pr_netaddr_get_addr(p, "2001:4860:4860::8888", NULL);
  fail_unless(addr != NULL, "Failed to resolve '2001:4860:4860::8888': %s",
    strerror(errno));

  res = pr_inet_connect(p, conn, addr, 53);
  if (res < 0) {
    /* Note: We get EINVAL here because the socket already tried (and failed)
     * to connect to a different address.  Interestingly, trying to connect(2)
     * using that same fd to a different address yields EINVAL.
     */
    fail_unless(errno == EINVAL || errno == ENETUNREACH,
      "Expected EINVAL (%d) or ENETUNREACH (%d), got %s (%d)",
      EINVAL, ENETUNREACH, strerror(errno), errno);
  }
  pr_inet_close(p, conn);

  conn = pr_inet_create_conn(p, sockfd, NULL, port, FALSE);
  fail_unless(conn != NULL, "Failed to create conn: %s", strerror(errno));

  res = pr_inet_connect(p, conn, addr, 53);
  if (res < 0) {
    /* This could be expected, e.g. if there's no route. */
    fail_unless(errno == EHOSTUNREACH || errno == ENETUNREACH,
      "Expected EHOSTUNREACH (%d) or ENETUNREACH (%d), got %s (%d)",
      EHOSTUNREACH, ENETUNREACH, strerror(errno), errno);
  }

  res = pr_inet_connect(p, conn, addr, 53);
  fail_unless(res < 0, "Failed to connect to 2001:4860:4860::8888#53: %s",
    strerror(errno));
  fail_unless(errno == EISCONN || errno == EHOSTUNREACH || errno == ENETUNREACH,
    "Expected EISCONN (%d) or EHOSTUNREACH (%d) or ENETUNREACH (%d), "
    "got %s (%d)", EISCONN, EHOSTUNREACH, ENETUNREACH, strerror(errno), errno);
  pr_inet_close(p, conn);

  pr_inet_set_default_family(p, AF_INET);

  if (use_ipv6 == FALSE) {
    pr_netaddr_disable_ipv6();
  }
#endif /* PR_USE_IPV6 */
}
Beispiel #6
0
static int data_active_open(char *reason, off_t size) {
  conn_t *c;
  int bind_port, rev;
  pr_netaddr_t *bind_addr;
  unsigned char *root_revoke = NULL;

  if (!reason && session.xfer.filename)
    reason = session.xfer.filename;

  if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(session.c->remote_addr)) {
    bind_addr = session.c->local_addr;

  } else {
    /* In this scenario, the server has an IPv6 socket, but the remote client
     * is an IPv4 (or IPv4-mapped IPv6) peer.
     */
    bind_addr = pr_netaddr_v6tov4(session.xfer.p, session.c->local_addr);
  }

  /* Default source port to which to bind for the active transfer, as
   * per RFC959.
   */
  bind_port = session.c->local_port-1;

  /* A RootRevoke value of 0 indicates 'false', 1 indicates 'true', and
   * 2 indicates 'NonCompliantActiveTransfer'.  We change the source port for
   * a RootRevoke value of 2.
   */
  root_revoke = get_param_ptr(TOPLEVEL_CONF, "RootRevoke", FALSE);
  if (root_revoke != NULL &&
      *root_revoke == 2) {
    bind_port = INPORT_ANY;
  }

  session.d = pr_inet_create_conn(session.pool, -1, bind_addr, bind_port, TRUE);

  /* Default remote address to which to connect for an active transfer,
   * if the client has not specified a different address via PORT/EPRT,
   * as per RFC 959.
   */
  if (pr_netaddr_get_family(&session.data_addr) == AF_UNSPEC) {
    pr_log_debug(DEBUG6, "Client has not sent previous PORT/EPRT command, "
      "defaulting to %s#%u for active transfer",
      pr_netaddr_get_ipstr(session.c->remote_addr), session.c->remote_port);

    pr_netaddr_set_family(&session.data_addr, pr_netaddr_get_family(session.c->remote_addr));
    pr_netaddr_set_sockaddr(&session.data_addr, pr_netaddr_get_sockaddr(session.c->remote_addr));
  }

  /* Set the "stalled" timer, if any, to prevent the connection
   * open from taking too long
   */
  if (timeout_stalled) {
    pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb,
      "TimeoutStalled");
  }

  rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS);

  /* Protocol and socket options should be set before handshaking. */

  if (session.xfer.direction == PR_NETIO_IO_RD) {
    pr_inet_set_socket_opts(session.d->pool, session.d,
      (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0,
      main_server->tcp_keepalive);
    
  } else {
    pr_inet_set_socket_opts(session.d->pool, session.d,
      0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0),
      main_server->tcp_keepalive);
  }

  /* Make sure that the necessary socket options are set on the socket prior
   * to the call to connect(2).
   */
  pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len, 0,
    IPTOS_THROUGHPUT, 1);
  pr_inet_generate_socket_event("core.data-connect", main_server,
    session.d->local_addr, session.d->listen_fd);

  if (pr_inet_connect(session.d->pool, session.d, &session.data_addr,
      session.data_port) == -1) {
    pr_log_debug(DEBUG6,
      "Error connecting to %s#%u for active data transfer: %s",
      pr_netaddr_get_ipstr(&session.data_addr), session.data_port,
      strerror(session.d->xerrno));
    pr_response_add_err(R_425, _("Unable to build data connection: %s"),
      strerror(session.d->xerrno));
    errno = session.d->xerrno;

    destroy_pool(session.d->pool);
    session.d = NULL;
    return -1;
  }

  c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA,
    session.d->listen_fd, -1, -1, TRUE);

  pr_netaddr_set_reverse_dns(rev);

  if (c) {
    pr_log_debug(DEBUG4, "active data connection opened - local  : %s:%d",
      pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port);
    pr_log_debug(DEBUG4, "active data connection opened - remote : %s:%d",
      pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port);

    if (session.xfer.xfer_type != STOR_UNIQUE) {
      if (size) {
        pr_response_send(R_150, _("Opening %s mode data connection for %s "
          "(%" PR_LU " bytes)"), MODE_STRING, reason, (pr_off_t) size);

      } else {
        pr_response_send(R_150, _("Opening %s mode data connection for %s"),
          MODE_STRING, reason);
      }

    } else {

      /* Format of 150 responses for STOU is explicitly dictated by
       * RFC 1123:
       *
       *  4.1.2.9  STOU Command: RFC-959 Section 4.1.3
       *
       *    The STOU command stores into a uniquely named file.  When it
       *    receives an STOU command, a Server-FTP MUST return the
       *    actual file name in the "125 Transfer Starting" or the "150
       *    Opening Data Connection" message that precedes the transfer
       *    (the 250 reply code mentioned in RFC-959 is incorrect).  The
       *    exact format of these messages is hereby defined to be as
       *    follows:
       *
       *        125 FILE: pppp
       *        150 FILE: pppp
       *
       *    where pppp represents the unique pathname of the file that
       *    will be written.
       */
      pr_response_send(R_150, "FILE: %s", reason);
    }

    pr_inet_close(session.pool, session.d);
    pr_inet_set_nonblock(session.pool, session.d);
    session.d = c;
    return 0;
  }

  pr_response_add_err(R_425, _("Unable to build data connection: %s"),
    strerror(session.d->xerrno));
  errno = session.d->xerrno;

  destroy_pool(session.d->pool);
  session.d = NULL;
  return -1;
}