コード例 #1
0
ファイル: netaddr.c プロジェクト: netdna/proftpd
END_TEST

START_TEST (netaddr_clear_test) {
  pr_netaddr_t *addr;

  mark_point();
  pr_netaddr_clear(NULL);

  addr = pr_netaddr_alloc(p);
  addr->na_family = 1;

  pr_netaddr_clear(addr);
  fail_unless(addr->na_family == 0, "Failed to clear addr");
}
コード例 #2
0
ファイル: netaddr.c プロジェクト: netdna/proftpd
END_TEST
#endif /* PR_USE_IPV6 */

START_TEST (netaddr_get_ipstr_test) {
  pr_netaddr_t *addr;
  const char *res;

  res = pr_netaddr_get_ipstr(NULL);
  fail_unless(res == NULL, "Failed to handle null argument");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

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

  res = pr_netaddr_get_ipstr(addr);
  fail_unless(res != NULL, "Failed to get IP str for addr: %s",
    strerror(errno));
  fail_unless(strcmp(res, "127.0.0.1") == 0, "Expected '%s', got '%s'",
    "127.0.0.1", res);
  fail_unless(addr->na_have_ipstr == 1, "addr should have cached IP str");

  pr_netaddr_clear(addr);
  res = pr_netaddr_get_ipstr(addr);
  fail_unless(res == NULL, "Expected null, got '%s'", res);

}
コード例 #3
0
ファイル: msg.c プロジェクト: Castaglia/proftpd-mod_proxy
const pr_netaddr_t *proxy_ftp_msg_parse_ext_addr(pool *p, const char *msg,
    const pr_netaddr_t *addr, int cmd_id, const char *net_proto) {
  pr_netaddr_t *res = NULL, na;
  int family = 0;
  unsigned short port = 0;
  char delim, *msg_str, *ptr;
  size_t msglen;

  if (p == NULL ||
      msg == NULL ||
      addr == NULL) {
    errno = EINVAL;
    return NULL;
  }

  if (cmd_id == PR_CMD_EPSV_ID) {
    /* First, find the opening '(' character. */
    ptr = strchr(msg, '(');
    if (ptr == NULL) {
      pr_trace_msg(trace_channel, 12,
        "missing starting '(' character for extended address in '%s'", msg);
      errno = EINVAL;
      return NULL;
    }

    /* Make sure that the last character is a closing ')'. */
    msglen = strlen(ptr);
    if (ptr[msglen-1] != ')') {
      pr_trace_msg(trace_channel, 12,
        "missing ending ')' character for extended address in '%s'", msg);
      errno = EINVAL;
      return NULL;
    }

    msg_str = pstrndup(p, ptr+1, msglen-2);

  } else {
    msg_str = pstrdup(p, msg);
  }

  /* Format is <d>proto<d>ip address<d>port<d> (ASCII in network order),
   * where <d> is an arbitrary delimiter character.
   */
  delim = *msg_str++;

  /* If the network protocol string (e.g. sent by client in EPSV command) is
   * null, then determine the protocol family from the address family we were
   * given.
   */

  /* XXX Hack to skip "all", e.g. "EPSV ALL" commands. */
  if (net_proto != NULL) {
    if (strncasecmp(net_proto, "all", 4) == 0) {
      net_proto = NULL;
    }
  }

  if (net_proto == NULL) {
    if (*msg_str == delim) {
      switch (pr_netaddr_get_family(addr)) {
        case AF_INET:
          family = 1;
          break;

#ifdef PR_USE_IPV6
        case AF_INET6:
          if (pr_netaddr_use_ipv6()) {
            family = 2;
            break;
          }
#endif /* PR_USE_IPV6 */

        default:
          break;
      }

    } else {
      family = atoi(msg_str);
    }

  } else {
    family = atoi(net_proto);
  }

  switch (family) {
    case 1:
      pr_trace_msg(trace_channel, 19, "parsed IPv4 address from '%s'", msg);
      break;

#ifdef PR_USE_IPV6
    case 2:
      pr_trace_msg(trace_channel, 19, "parsed IPv6 address from '%s'", msg);
      if (pr_netaddr_use_ipv6()) {
        break;
      }
#endif /* PR_USE_IPV6 */

    default:
      pr_trace_msg(trace_channel, 12,
        "unsupported network protocol %d", family);
      errno = EPROTOTYPE;
      return NULL;
  }

  /* Now, skip past those numeric characters that atoi() used. */
  while (PR_ISDIGIT(*msg_str)) {
    msg_str++;
  }

  /* If the next character is not the delimiter, it's a badly formatted
   * parameter.
   */
  if (*msg_str == delim) {
    msg_str++;

  } else {
    pr_trace_msg(trace_channel, 17, "rejecting badly formatted message '%s'",
      msg_str);
    errno = EPERM;
    return NULL;
  }

  pr_netaddr_clear(&na);

  /* If the next character IS the delimiter, then the address portion is
   * omitted (which is permissible).
   */
  if (*msg_str == delim) {
    pr_netaddr_set_family(&na, pr_netaddr_get_family(addr));
    pr_netaddr_set_sockaddr(&na, pr_netaddr_get_sockaddr(addr));
    msg_str++;

  } else {
    ptr = strchr(msg_str, delim);
    if (ptr == NULL) {
      /* Badly formatted message. */
      errno = EINVAL;
      return NULL;
    }

    /* Twiddle the string so that just the address portion will be processed
     * by pr_inet_pton().
     */
    *ptr = '\0';

    /* Use pr_inet_pton() to translate the address string into the address
     * value.
     */
    switch (family) {
      case 1: {
        struct sockaddr *sa = NULL;

        pr_netaddr_set_family(&na, AF_INET);
        sa = pr_netaddr_get_sockaddr(&na);
        if (sa) {
          sa->sa_family = AF_INET;
        }

        if (pr_inet_pton(AF_INET, msg_str, pr_netaddr_get_inaddr(&na)) <= 0) {
          pr_trace_msg(trace_channel, 2,
            "error converting IPv4 address '%s': %s", msg_str, strerror(errno));
          errno = EPERM;
          return NULL;
        }

        break;
      }

      case 2: {
        struct sockaddr *sa = NULL;

        pr_netaddr_set_family(&na, AF_INET6);
        sa = pr_netaddr_get_sockaddr(&na);
        if (sa) {
          sa->sa_family = AF_INET6;
        }

        if (pr_inet_pton(AF_INET6, msg_str, pr_netaddr_get_inaddr(&na)) <= 0) {
          pr_trace_msg(trace_channel, 2,
            "error converting IPv6 address '%s': %s", msg_str, strerror(errno));
          errno = EPERM;
          return NULL;
        }

        break;
      }
    }

    /* Advance past the address portion of the argument. */
    msg_str = ++ptr;
  }

  port = atoi(msg_str);

  while (PR_ISDIGIT(*msg_str)) {
    msg_str++;
  }

  /* If the next character is not the delimiter, it's a badly formatted
   * parameter.
   */
  if (*msg_str != delim) {
    pr_trace_msg(trace_channel, 17, "rejecting badly formatted message '%s'",
      msg_str);
    errno = EPERM;
    return NULL;
  }

  /* XXX Use a pool other than session.pool here, in the future. */ 
  res = pr_netaddr_dup(session.pool, &na);
  pr_netaddr_set_port(res, htons(port));

  return res;
}
コード例 #4
0
ファイル: inet.c プロジェクト: rogerhu/dd-wrt
/* Initialize a new connection record, also creates a new subpool just for the
 * new connection.
 */
static conn_t *init_conn(pool *p, int fd, pr_netaddr_t *bind_addr,
    int port, int retry_bind, int reporting) {
  pool *sub_pool = NULL;
  conn_t *c;
  pr_netaddr_t na;
  int addr_family;
  int res = 0, one = 1, hold_errno;

  if (!inet_pool) {
    inet_pool = make_sub_pool(permanent_pool);
    pr_pool_tag(inet_pool, "Inet Pool");
  }

  /* Initialize the netaddr. */
  pr_netaddr_clear(&na);

  sub_pool = make_sub_pool(p);
  pr_pool_tag(sub_pool, "init_conn() subpool");

  c = (conn_t *) pcalloc(sub_pool, sizeof(conn_t));
  c->pool = sub_pool;

  c->local_port = port;
  c->rfd = c->wfd = -1;

  if (bind_addr) {
    addr_family = pr_netaddr_get_family(bind_addr);

  } else if (inet_family) {
    addr_family = inet_family;

  } else {

    /* If no default family has been set, then default to IPv6 (if IPv6
     * support is enabled), otherwise use IPv4.
     */
#ifdef PR_USE_IPV6
    if (pr_netaddr_use_ipv6())
      addr_family = AF_INET6;

    else
      addr_family = AF_INET;
#else
    addr_family = AF_INET;
#endif /* PR_USE_IPV6 */
  }

  /* If fd == -1, there is no currently open socket, so create one.
   */
  if (fd == -1) {
    socklen_t salen;
    register unsigned int i = 0;

    /* Certain versions of Solaris apparently require us to be root
     * in order to create a socket inside a chroot.
     *
     * FreeBSD 2.2.6 (possibly other versions as well), has a security
     * "feature" which disallows SO_REUSEADDR from working if the socket
     * owners don't match.  The easiest thing to do is simply make sure
     * the socket is created as root.  (Note: this "feature" seems to apply
     * to _all_ BSDs.)
     */

#if defined(SOLARIS2) || defined(FREEBSD2) || defined(FREEBSD3) || \
    defined(FREEBSD4) || defined(FREEBSD5) || defined(FREEBSD6) || \
    defined(FREEBSD7) || defined(FREEBSD8) || defined(FREEBSD9) || \
    defined(__OpenBSD__) || defined(__NetBSD__) || \
    defined(DARWIN6) || defined(DARWIN7) || defined(DARWIN8) || \
    defined(DARWIN9) || defined(DARWIN10) || defined(DARWIN11) || \
    defined(SCO3) || defined(CYGWIN) || defined(SYSV4_2MP) || \
    defined(SYSV5SCO_SV6) || defined(SYSV5UNIXWARE7)
# ifdef SOLARIS2
    if (port != INPORT_ANY && port < 1024) {
# endif
      pr_signals_block();
      PRIVS_ROOT
# ifdef SOLARIS2
    }
コード例 #5
0
ファイル: bindings.c プロジェクト: dbarba74/proftpd
pr_namebind_t *pr_namebind_find(const char *name, pr_netaddr_t *addr,
    unsigned int port, unsigned char skip_inactive) {
  pr_ipbind_t *ipbind = NULL;
  pr_namebind_t *namebind = NULL;

  if (name == NULL ||
      addr == NULL) {
    errno = EINVAL;
    return NULL;
  }

  /* First, find an active ipbind for the given addr/port */
  ipbind = pr_ipbind_find(addr, port, skip_inactive);

  if (ipbind == NULL) {
    pr_netaddr_t wildcard_addr;
    int addr_family;

    /* If not found, look for the wildcard address. */

    addr_family = pr_netaddr_get_family(addr);
    pr_netaddr_clear(&wildcard_addr);
    pr_netaddr_set_family(&wildcard_addr, addr_family);
    pr_netaddr_set_sockaddr_any(&wildcard_addr);

    ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE);
#ifdef PR_USE_IPV6
    if (ipbind == FALSE &&
        addr_family == AF_INET6 &&
        pr_netaddr_use_ipv6()) {

      /* No IPv6 wildcard address found; try the IPv4 wildcard address. */
      pr_netaddr_clear(&wildcard_addr);
      pr_netaddr_set_family(&wildcard_addr, AF_INET);
      pr_netaddr_set_sockaddr_any(&wildcard_addr);

      ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE);
    }
#endif /* PR_USE_IPV6 */
  }

  if (ipbind == NULL) {
    errno = ENOENT;
    return NULL;
  }

  if (!ipbind->ib_namebinds) {
    return NULL;

  } else {
    register unsigned int i = 0;
    pr_namebind_t **namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts;

    for (i = 0; i < ipbind->ib_namebinds->nelts; i++) {
      namebind = namebinds[i];

      /* Skip inactive namebinds */
      if (skip_inactive == TRUE &&
          namebind != NULL &&
          namebind->nb_isactive == FALSE) {
        continue;
      }

      /* At present, this looks for an exactly matching name.  In the future,
       * we may want to have something like Apache's matching scheme, which
       * looks for the most specific domain to the most general.  Note that
       * that scheme, however, is specific to DNS; should any other naming
       * scheme be desired, that sort of matching will be unnecessary.
       */
      if (namebind != NULL &&
          namebind->nb_name != NULL) {

        if (namebind->nb_iswildcard == FALSE) {
          if (strcasecmp(namebind->nb_name, name) == 0)
            return namebind;
          }

        } else {
          int match_flags = PR_FNM_NOESCAPE|PR_FNM_CASEFOLD;

          if (pr_fnmatch(namebind->nb_name, name, match_flags) == 0) {
            pr_trace_msg(trace_channel, 9,
              "matched name '%s' against pattern '%s'", name,
              namebind->nb_name);
            return namebind;
          }

          pr_trace_msg(trace_channel, 9,
            "failed to match name '%s' against pattern '%s'", name,
            namebind->nb_name);
        }
    }
  }

  return NULL;
}
コード例 #6
0
ファイル: bindings.c プロジェクト: dbarba74/proftpd
int pr_namebind_create(server_rec *server, const char *name,
    pr_netaddr_t *addr, unsigned int port) {
  pr_ipbind_t *ipbind = NULL;
  pr_namebind_t *namebind = NULL, **namebinds = NULL;

  if (server == NULL ||
      name == NULL) {
    errno = EINVAL;
    return -1;
  }

  /* First, find the ipbind to hold this namebind. */
  ipbind = pr_ipbind_find(addr, port, FALSE);

  if (ipbind == NULL) {
    pr_netaddr_t wildcard_addr;
    int addr_family;

    /* If not found, look for the wildcard address. */

    addr_family = pr_netaddr_get_family(addr);
    pr_netaddr_clear(&wildcard_addr);
    pr_netaddr_set_family(&wildcard_addr, addr_family);
    pr_netaddr_set_sockaddr_any(&wildcard_addr);

    ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE);
#ifdef PR_USE_IPV6
    if (ipbind == FALSE &&
        addr_family == AF_INET6 &&
        pr_netaddr_use_ipv6()) {

      /* No IPv6 wildcard address found; try the IPv4 wildcard address. */
      pr_netaddr_clear(&wildcard_addr);
      pr_netaddr_set_family(&wildcard_addr, AF_INET);
      pr_netaddr_set_sockaddr_any(&wildcard_addr);

      ipbind = pr_ipbind_find(&wildcard_addr, port, FALSE);
    }
#endif /* PR_USE_IPV6 */
  }

  if (ipbind == NULL) {
    errno = ENOENT;
    return -1;
  }

  /* Make sure we can add this namebind. */
  if (!ipbind->ib_namebinds) {
    ipbind->ib_namebinds = make_array(binding_pool, 0, sizeof(pr_namebind_t *));

  } else {
    register unsigned int i = 0;
    namebinds = (pr_namebind_t **) ipbind->ib_namebinds->elts;

    /* See if there is already a namebind for the given name. */
    for (i = 0; i < ipbind->ib_namebinds->nelts; i++) {
      namebind = namebinds[i];
      if (namebind != NULL &&
          namebind->nb_name != NULL) {

        /* DNS names are case-insensitive, hence the case-insensitive check
         * here.
         *
         * XXX Ideally, we should check whether any existing namebinds which
         * are globs will match the newly added namebind as well.
         */

        if (strcasecmp(namebind->nb_name, name) == 0) {
          errno = EEXIST;
          return -1;
        }
      }
    }
  }

  namebind = (pr_namebind_t *) pcalloc(server->pool, sizeof(pr_namebind_t));
  namebind->nb_name = name;
  namebind->nb_server = server;
  namebind->nb_isactive = FALSE;

  if (pr_str_is_fnmatch(name) == TRUE) {
    namebind->nb_iswildcard = TRUE;
  }

  pr_trace_msg(trace_channel, 8,
    "created named binding '%s' for %s#%u, server %p", name,
    pr_netaddr_get_ipstr(server->addr), server->ServerPort, server->ServerName);

  /* The given server should already have the following populated:
   *
   *  server->ServerName
   *  server->ServerAddress
   *  server->ServerFQDN
   */

  /* These TCP socket tweaks will not apply to the control connection (it will
   * already have been established by the time this named vhost is used),
   * but WILL apply to any data connections established to this named vhost.
   */

#if 0
  namebind->nb_server->tcp_mss_len = (server->tcp_mss_len ?
    server->tcp_mss_len : main_server->tcp_mss_len);
  namebind->nb_server->tcp_rcvbuf_len = (server->tcp_rcvbuf_len ?
    server->tcp_rcvbuf_len : main_server->tcp_rcvbuf_len);
  namebind->nb_server->tcp_rcvbuf_override = (server->tcp_rcvbuf_override ?
    TRUE : main_server->tcp_rcvbuf_override);
  namebind->nb_server->tcp_sndbuf_len = (server->tcp_sndbuf_len ?
    server->tcp_sndbuf_len : main_server->tcp_sndbuf_len);
  namebind->nb_server->tcp_sndbuf_override = (server->tcp_sndbuf_override ?
    TRUE : main_server->tcp_sndbuf_override);

  /* XXX Shouldn't need these; the ipbind container handles all of the
   * connection (listener, port, addr) stuff.
   */

  namebind->nb_server->addr = (server->addr ? server->addr :
    main_server->addr);
  namebind->nb_server->ServerPort = (server->ServerPort ? server->ServerPort :
    main_server->ServerPort);
  namebind->nb_listener = (server->listen ? server->listen :
    main_server->listen);
#endif

  *((pr_namebind_t **) push_array(ipbind->ib_namebinds)) = namebind;
  return 0;
}
コード例 #7
0
ファイル: bindings.c プロジェクト: dbarba74/proftpd
server_rec *pr_ipbind_get_server(pr_netaddr_t *addr, unsigned int port) {
  pr_ipbind_t *ipbind = NULL;
  pr_netaddr_t wildcard_addr;
  int addr_family;

  /* If we've got a binding configured for this exact address, return it
   * straightaway.
   */
  ipbind = pr_ipbind_find(addr, port, TRUE);
  if (ipbind != NULL)
    return ipbind->ib_server;

  /* Look for a vhost bound to the wildcard address (i.e. INADDR_ANY).
   *
   * This allows for "<VirtualHost 0.0.0.0>" configurations, where the
   * IP address to which the client might connect is not known at
   * configuration time.  (Usually happens when the same config file
   * is deployed to multiple machines.)
   */

  addr_family = pr_netaddr_get_family(addr);

  pr_netaddr_clear(&wildcard_addr);
  pr_netaddr_set_family(&wildcard_addr, addr_family);
  pr_netaddr_set_sockaddr_any(&wildcard_addr);

  ipbind = pr_ipbind_find(&wildcard_addr, port, TRUE);
  if (ipbind != NULL) {
    pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using "
      "'%s' listening on wildcard address", pr_netaddr_get_ipstr(addr), port,
      ipbind->ib_server->ServerName);
    return ipbind->ib_server;

  } else {
#ifdef PR_USE_IPV6
    if (addr_family == AF_INET6 &&
        pr_netaddr_use_ipv6()) {

      /* The pr_ipbind_find() probably returned NULL because there aren't
       * any <VirtualHost> sections configured explicitly for the wildcard
       * IPv6 address of "::", just the IPv4 wildcard "0.0.0.0" address.
       *
       * So try the pr_ipbind_find() again, this time using the IPv4 wildcard.
       */
      pr_netaddr_clear(&wildcard_addr);
      pr_netaddr_set_family(&wildcard_addr, AF_INET);
      pr_netaddr_set_sockaddr_any(&wildcard_addr);

      ipbind = pr_ipbind_find(&wildcard_addr, port, TRUE);
      if (ipbind != NULL) {
        pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using "
          "'%s' listening on wildcard address", pr_netaddr_get_ipstr(addr),
          port, ipbind->ib_server->ServerName);
        return ipbind->ib_server;
      }
    }
#endif /* PR_USE_IPV6 */
  }

  /* Use the default server, if set. */
  if (ipbind_default_server &&
      ipbind_default_server->ib_isactive) {
    pr_log_debug(DEBUG7, "no matching vhost found for %s#%u, using "
      "DefaultServer '%s'", pr_netaddr_get_ipstr(addr), port,
      ipbind_default_server->ib_server->ServerName);
    return ipbind_default_server->ib_server;
  }

  /* Not found in binding list, and no DefaultServer, so see if it's the
   * loopback address
   */
  if (ipbind_localhost_server &&
      pr_netaddr_is_loopback(addr)) {
    return ipbind_localhost_server->ib_server;
  }

  return NULL;
}
コード例 #8
0
ファイル: netaddr.c プロジェクト: netdna/proftpd
END_TEST

#ifdef PR_USE_IPV6
START_TEST (netaddr_get_dnsstr_ipv6_test) {
  pr_netaddr_t *addr;
  const char *ip, *res;

  ip = "::1";

  res = pr_netaddr_get_dnsstr(NULL);
  fail_unless(res == NULL, "Failed to handle null argument");
  fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");

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

  pr_netaddr_set_reverse_dns(FALSE);

  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));
  fail_unless(strcmp(res, ip) == 0, "Expected '%s', got '%s'", ip, res);

  pr_netaddr_set_reverse_dns(TRUE);

  /* Even though we should expect a DNS name, not an IP address, the
   * previous call to pr_netaddr_get_dnsstr() cached the IP address.
   */
  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));
  fail_unless(strcmp(res, ip) == 0, "Expected '%s', got '%s'", ip, res);

  pr_netaddr_clear(addr);

  /* Clearing the address doesn't work, since that removes even the address
   * info, in addition to the cached strings.
   */
  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));
  fail_unless(strcmp(res, "") == 0, "Expected '%s', got '%s'", "", res);

  /* We need to clear the netaddr internal cache as well. */
  pr_netaddr_clear_ipcache(ip);
  addr = pr_netaddr_get_addr(p, ip, NULL);
  fail_unless(addr != NULL, "Failed to get addr for '%s': %s", ip,
    strerror(errno));

  mark_point();
  fail_unless(addr->na_have_dnsstr == 0, "addr already has cached DNS str");

  mark_point();
  res = pr_netaddr_get_dnsstr(addr);
  fail_unless(res != NULL, "Failed to get DNS str for addr: %s",
    strerror(errno));

  mark_point();

  /* Depending on the contents of /etc/hosts, resolving ::1 could
   * return either "localhost" or "localhost.localdomain".  Perhaps even
   * other variations, although these should be the most common.
   */
  fail_unless(strcmp(res, "localhost") == 0 ||
              strcmp(res, "localhost.localdomain") == 0 ||
              strcmp(res, "localhost6") == 0 ||
              strcmp(res, "localhost6.localdomain") == 0 ||
              strcmp(res, "ip6-localhost") == 0 ||
              strcmp(res, "ip6-loopback") == 0 ||
              strcmp(res, ip) == 0,
    "Expected '%s', got '%s'", "localhost, localhost.localdomain et al", res);
}