예제 #1
0
파일: netaddr.c 프로젝트: OPSF/uClinux
int pr_netaddr_cmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2) {
  if (na1 && !na2)
    return 1;

  if (!na1 && na2)
    return -1;

  if (!na1 && !na2)
    return 0;

  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {
    /* Cannot compare addresses from different families. */
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na1)) {
    case AF_INET:
      return memcmp(&na1->na_addr.v4.sin_addr, &na2->na_addr.v4.sin_addr,
        sizeof(struct in_addr));

#ifdef PR_USE_IPV6
    case AF_INET6:
      return memcmp(&na1->na_addr.v6.sin6_addr, &na2->na_addr.v6.sin6_addr,
        sizeof(struct in6_addr));
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return -1;
}
예제 #2
0
파일: inet.c 프로젝트: netdna/proftpd
/* Copy a connection structure, also creates a sub pool for the new
 * connection.
 */
conn_t *pr_inet_copy_conn(pool *p, conn_t *c) {
  conn_t *res = NULL;
  pool *sub_pool = NULL;

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

  sub_pool = make_sub_pool(p);
  pr_pool_tag(sub_pool, "inet_copy_conn pool");

  res = (conn_t *) pcalloc(sub_pool, sizeof(conn_t));

  memcpy(res, c, sizeof(conn_t));
  res->pool = sub_pool;
  res->instrm = res->outstrm = NULL;

  if (c->local_addr) {
    res->local_addr = pr_netaddr_alloc(res->pool);

    if (pr_netaddr_set_family(res->local_addr,
        pr_netaddr_get_family(c->local_addr)) < 0) {
      destroy_pool(res->pool);
      return NULL;
    }

    pr_netaddr_set_sockaddr(res->local_addr,
      pr_netaddr_get_sockaddr(c->local_addr));
  }

  if (c->remote_addr) {
    res->remote_addr = pr_netaddr_alloc(res->pool);

    if (pr_netaddr_set_family(res->remote_addr,
        pr_netaddr_get_family(c->remote_addr)) < 0) {
      destroy_pool(res->pool);
      return NULL;
    }

    pr_netaddr_set_sockaddr(res->remote_addr,
      pr_netaddr_get_sockaddr(c->remote_addr));
  }

  if (c->remote_name) {
    res->remote_name = pstrdup(res->pool, c->remote_name);
  }

  register_cleanup(res->pool, (void *) res, conn_cleanup_cb, conn_cleanup_cb);
  return res;
}
예제 #3
0
/* A slightly naughty function that should go away. It relies too much on
 * knowledge of the internal structures of struct in_addr, struct in6_addr.
 */
unsigned int pr_netaddr_get_addrno(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return na->na_addr.v4.sin_addr.s_addr;

#ifdef PR_USE_IPV6
    case AF_INET6: {

      /* Linux defines s6_addr32 in its netinet/in.h header.
       * FreeBSD defines s6_addr32 in KAME's netinet6/in6.h header.
       * Solaris defines s6_addr32 in its netinet/in.h header, but only
       * for kernel builds.
       */
#if 0
      int *addrs = ((struct sockaddr_in6 *) pr_netaddr_get_inaddr(na))->s6_addr32;
      return addrs[0];
#else
      return 0;
#endif
    }
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return -1;
}
예제 #4
0
int pr_netaddr_is_v4mappedv6(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:

      /* This function tests only IPv6 addresses, not IPv4 addresses. */
      errno = EINVAL;
      return -1;

#ifdef PR_USE_IPV6
    case AF_INET6: {
      if (!use_ipv6) {
        errno = EINVAL;
        return -1;
      }

# ifndef LINUX
      return IN6_IS_ADDR_V4MAPPED(
        (struct in6_addr *) pr_netaddr_get_inaddr(na));
# else
      return IN6_IS_ADDR_V4MAPPED(
        ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32);
# endif
    }
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return -1;
}
예제 #5
0
int pr_netaddr_is_loopback(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return IN_IS_ADDR_LOOPBACK(
        (struct in_addr *) pr_netaddr_get_inaddr(na));

#ifdef PR_USE_IPV6
    case AF_INET6:
      /* XXX *sigh* Different platforms implement the IN6_IS_ADDR macros
       * differently.  For example, on Linux, those macros expect to operate
       * on s6_addr32, while on Solaris, the macros operate on struct in6_addr.
       * Certain Drafts define the macros to work on struct in6_addr *, as
       * Solaris does, so Linux may have it wrong.  Tentative research on
       * Google shows some BSD netinet6/in6.h headers that define these
       * macros in terms of struct in6_addr *, so I'll go with that for now.
       * Joy. =P
       */
# ifndef LINUX
      return IN6_IS_ADDR_LOOPBACK(
        (struct in6_addr *) pr_netaddr_get_inaddr(na));
# else
      return IN6_IS_ADDR_LOOPBACK(
        ((struct in6_addr *) pr_netaddr_get_inaddr(na))->s6_addr32);
# endif
#endif /* PR_USE_IPV6 */
  }

  return FALSE;
}
예제 #6
0
void pr_netaddr_set_sess_addrs(void) {
  pr_netaddr_set_family(&sess_local_addr,
    pr_netaddr_get_family(session.c->local_addr));
  pr_netaddr_set_sockaddr(&sess_local_addr,
    pr_netaddr_get_sockaddr(session.c->local_addr));
  have_sess_local_addr = TRUE;

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

  memset(sess_remote_name, '\0', sizeof(sess_remote_name));
  sstrncpy(sess_remote_name, session.c->remote_name, sizeof(sess_remote_name));
  have_sess_remote_addr = TRUE;
}
예제 #7
0
파일: mod_qos.c 프로젝트: Nakor78/proftpd
static void qos_data_connect_ev(const void *event_data, void *user_data) {
  const struct socket_ctx *sc;

  sc = event_data;

  /* Only set TOS flags on IPv4 sockets; IPv6 sockets don't seem to support
   * them.
   */
  if (pr_netaddr_get_family(sc->addr) == AF_INET) {
    config_rec *c;
    c = find_config(sc->server->conf, CONF_PARAM, "QoSOptions", FALSE);
    if (c) {
      int dataqos, res;

      dataqos = *((int *) c->argv[1]);

      res = setsockopt(sc->sockfd, ip_level, IP_TOS, (void *) &dataqos,
        sizeof(dataqos));
      if (res < 0) {
        pr_log_pri(PR_LOG_NOTICE, MOD_QOS_VERSION
          ": error setting data socket IP_TOS: %s", strerror(errno));
      }
    }
  }
}
예제 #8
0
int pr_netaddr_set_sockaddr_any(pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET: {
      struct in_addr in4addr_any;
      in4addr_any.s_addr = htonl(INADDR_ANY);
      na->na_addr.v4.sin_family = AF_INET;
#ifdef SIN_LEN
      na->na_addr.v4.sin_len = sizeof(struct sockaddr_in);
#endif /* SIN_LEN */
      memcpy(&na->na_addr.v4.sin_addr, &in4addr_any, sizeof(struct in_addr));
      return 0;
    }

#ifdef PR_USE_IPV6
    case AF_INET6:
      if (use_ipv6) {
        na->na_addr.v6.sin6_family = AF_INET6;
#ifdef SIN6_LEN
        na->na_addr.v6.sin6_len = sizeof(struct sockaddr_in6);
#endif /* SIN6_LEN */
        memcpy(&na->na_addr.v6.sin6_addr, &in6addr_any, sizeof(struct in6_addr));
        return 0;
      }
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return -1;
}
예제 #9
0
파일: netaddr.c 프로젝트: netdna/proftpd
END_TEST

START_TEST (netaddr_get_family_test) {
  pr_netaddr_t *addr;
  int res;

  res = pr_netaddr_get_family(NULL);
  fail_unless(res == -1, "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_family(addr);
  fail_unless(res == AF_INET, "Expected family %d, got %d", AF_INET,
    res);
}
예제 #10
0
파일: netaddr.c 프로젝트: netdna/proftpd
END_TEST

START_TEST (netaddr_v6tov4_test) {
  pr_netaddr_t *addr, *addr2;
  const char *name, *ipstr;

  addr = pr_netaddr_v6tov4(NULL, NULL);
  fail_unless(addr == NULL, "Failed to handle null arguments");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

  addr = pr_netaddr_v6tov4(p, NULL);
  fail_unless(addr == NULL, "Failed to handle null address");
  fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
    strerror(errno), errno);

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

  addr = pr_netaddr_v6tov4(p, addr2);
  fail_unless(addr == NULL, "Converted '%s' to IPv4 address unexpectedly",
    name);
  fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
    strerror(errno), errno);

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

  addr = pr_netaddr_v6tov4(p, addr2);
  fail_unless(addr != NULL, "Failed to convert '%s' to IPv4 addres: %s",
    name, strerror(errno));
  fail_unless(pr_netaddr_get_family(addr) == AF_INET,
    "Expected %d, got %d", AF_INET, pr_netaddr_get_family(addr));

  ipstr = pr_netaddr_get_ipstr(addr);
  fail_unless(strcmp(ipstr, "127.0.0.1") == 0,
    "Expected '127.0.0.1', got '%s'", ipstr);
}
예제 #11
0
pr_netaddr_t *pr_netaddr_dup(pool *p, pr_netaddr_t *na) {
  pr_netaddr_t *dup_na;

  if (!p || !na) {
    errno = EINVAL;
    return NULL;
  }

  dup_na = pr_netaddr_alloc(p);

  pr_netaddr_set_family(dup_na, pr_netaddr_get_family(na));
  pr_netaddr_set_sockaddr(dup_na, pr_netaddr_get_sockaddr(na));  

  return dup_na;
}
예제 #12
0
파일: netaddr.c 프로젝트: OPSF/uClinux
size_t pr_netaddr_get_inaddr_len(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return sizeof(struct in_addr);

#ifdef PR_USE_IPV6
    case AF_INET6:
      return sizeof(struct in6_addr);
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return -1;
}
예제 #13
0
파일: netaddr.c 프로젝트: OPSF/uClinux
struct sockaddr *pr_netaddr_get_sockaddr(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return NULL;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return (struct sockaddr *) &na->na_addr.v4;

#ifdef PR_USE_IPV6
    case AF_INET6:
      return (struct sockaddr *) &na->na_addr.v6;
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return NULL;
}
예제 #14
0
파일: netaddr.c 프로젝트: OPSF/uClinux
unsigned int pr_netaddr_get_port(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return 0;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return na->na_addr.v4.sin_port;

#ifdef PR_USE_IPV6
    case AF_INET6:
      return na->na_addr.v6.sin6_port;
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return 0;
}
예제 #15
0
파일: netaddr.c 프로젝트: OPSF/uClinux
void *pr_netaddr_get_inaddr(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return NULL;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return (void *) &na->na_addr.v4.sin_addr;

#ifdef PR_USE_IPV6
    case AF_INET6:
      return (void *) &na->na_addr.v6.sin6_addr;
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return NULL;
}
예제 #16
0
size_t pr_netaddr_get_sockaddr_len(const pr_netaddr_t *na) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      return sizeof(struct sockaddr_in);
 
#ifdef PR_USE_IPV6
    case AF_INET6:
      if (use_ipv6)
        return sizeof(struct sockaddr_in6);
#endif /* PR_USE_IPV6 */   
  }

  errno = EPERM;
  return -1;
}
예제 #17
0
파일: netacl.c 프로젝트: laoflch/proftpd
pr_netacl_t *pr_netacl_dup(pool *p, const pr_netacl_t *acl) {
  pr_netacl_t *acl2;

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

  acl2 = pcalloc(p, sizeof(pr_netacl_t));

  /* A simple memcpy(3) won't suffice; we need a deep copy. */
  acl2->type = acl->type;

  if (acl->pattern != NULL) {
    acl2->pattern = pstrdup(p, acl->pattern);
  }

  acl2->negated = acl->negated;

  if (acl->addr != NULL) {
    pr_netaddr_t *addr;

    addr = pr_netaddr_alloc(p);
    pr_netaddr_set_family(addr, pr_netaddr_get_family(acl->addr));
    pr_netaddr_set_sockaddr(addr, pr_netaddr_get_sockaddr(acl->addr));

    acl2->addr = addr;
  }

  acl2->masklen = acl->masklen;

  if (acl->aclstr != NULL) {
    acl2->aclstr = pstrdup(p, acl->aclstr);
  }

  return acl2;
}
예제 #18
0
int pr_netaddr_set_port(pr_netaddr_t *na, unsigned int port) {
  if (!na) {
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na)) {
    case AF_INET:
      na->na_addr.v4.sin_port = port;
      return 0;

#ifdef PR_USE_IPV6
    case AF_INET6:
      if (use_ipv6) {
        na->na_addr.v6.sin6_port = port;
        return 0;
      }
#endif /* PR_USE_IPV6 */
  }

  errno = EPERM;
  return 0;
}
예제 #19
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;
}
예제 #20
0
파일: netaddr.c 프로젝트: OPSF/uClinux
/* This differs from pr_netaddr_get_ipstr() in that pr_netaddr_get_ipstr()
 * returns a string of the numeric form of the given network address, whereas
 * this function returns a string of the DNS name (if present).
 */
const char *pr_netaddr_get_dnsstr(pr_netaddr_t *na) {
  char *name = NULL;
  char buf[256];

  if (!na) {
    errno = EINVAL;
    return NULL;
  }

  /* If this pr_netaddr_t has already been resolved to an DNS string, return the
   * cached string.
   */
  if (na->na_have_dnsstr)
    return na->na_dnsstr;

  if (reverse_dns) {
    int res = 0;

    memset(buf, '\0', sizeof(buf));
    res = pr_getnameinfo(pr_netaddr_get_sockaddr(na),
      pr_netaddr_get_sockaddr_len(na), buf, sizeof(buf), NULL, 0, NI_NAMEREQD);

    if (res == 0) {
      char **checkaddr;
      struct hostent *hent = NULL;
      unsigned char ok = FALSE;
      int family = pr_netaddr_get_family(na);
      void *inaddr = pr_netaddr_get_inaddr(na);
    
#ifdef HAVE_GETHOSTBYNAME2
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
        family = AF_INET;
        inaddr = get_v4inaddr(na);
      }

      hent = gethostbyname2(buf, family);
#else
      hent = gethostbyname(buf);
#endif /* HAVE_GETHOSTBYNAME2 */

      if (hent != NULL) {
        switch (hent->h_addrtype) {
          case AF_INET:
            if (family == AF_INET) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;

#ifdef PR_USE_IPV6
          case AF_INET6:
            if (family == AF_INET6) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;
#endif /* PR_USE_IPV6 */
        }

        name = ok ? buf : NULL;

      } else
        pr_log_debug(DEBUG1, "notice: unable to resolve '%s': %s", buf,
          hstrerror(errno));
    }
  }

  if (!name)
    name = (char *) pr_netaddr_get_ipstr(na);

  name = pr_inet_validate(name);

  /* Copy the string into the pr_netaddr_t cache as well, so we only
   * have to do this once for this pr_netaddr_t.
   */
  memset(na->na_dnsstr, '\0', sizeof(na->na_dnsstr));
  sstrncpy(na->na_dnsstr, name, sizeof(na->na_dnsstr));
  na->na_have_dnsstr = TRUE;

  return na->na_dnsstr;
}
예제 #21
0
파일: netaddr.c 프로젝트: OPSF/uClinux
int pr_netaddr_ncmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2,
    unsigned int bitlen) {
  unsigned int nbytes, nbits;
  const unsigned char *in1, *in2;

  if (na1 && !na2)
    return 1;

  if (!na1 && na2)
    return -1;

  if (!na1 && !na2)
    return 0;

  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {
    /* Cannot compare addresses from different families. */
    errno = EINVAL;
    return -1;
  }

  switch (pr_netaddr_get_family(na1)) {
    case AF_INET: {
      /* Make sure that the given number of bits is not more than supported
       * for IPv4 addresses (32).
       */
      if (bitlen > 32) {
        errno = EINVAL;
        return -1;
      }

      break;
    }

#ifdef PR_USE_IPV6
    case AF_INET6: {
      /* Make sure that the given number of bits is not more than supported
       * for IPv6 addresses (128).
       */
      if (bitlen > 128) {
        errno = EINVAL;
        return -1;
      }

      break;
    }
#endif /* PR_USE_IPV6 */

    default:
      errno = EPERM;
      return -1;
  }

  /* Retrieve pointers to the contained in_addrs. */
  in1 = (const unsigned char *) pr_netaddr_get_inaddr(na1);
  in2 = (const unsigned char *) pr_netaddr_get_inaddr(na2);

  /* Determine the number of bytes, and leftover bits, in the given
   * bit length.
   */
  nbytes = bitlen / 8;
  nbits = bitlen % 8;

  /* Compare bytes, using memcmp(3), first. */
  if (nbytes > 0) {
    int res = memcmp(in1, in2, nbytes);

    /* No need to continue comparing the addresses if they differ already. */
    if (res != 0)
      return res;
  }

  /* Next, compare the remaining bits in the addresses. */
  if (nbits > 0) {
    unsigned char mask;

    /* Get the bytes in the addresses that have not yet been compared. */
    unsigned char in1byte = in1[nbytes];
    unsigned char in2byte = in2[nbytes];

    /* Build up a mask covering the bits left to be checked. */
    mask = (0xff << (8 - nbits)) & 0xff;

    if ((in1byte & mask) > (in2byte & mask))
      return 1;

    if ((in1byte & mask) < (in2byte & mask))
      return -1;
  }

  /* If we've made it this far, the addresses match, for the given bit
   * length.
   */
  return 0;
}
예제 #22
0
파일: bindings.c 프로젝트: dbarba74/proftpd
static int init_standalone_bindings(void) {
  int res = 0;
  server_rec *serv = NULL;
  unsigned char *default_server = NULL, is_default = FALSE;

  /* If a port is set to zero, the address/port is not bound to a socket
   * at all.
   */
  if (main_server->ServerPort) {

    /* If SocketBindTight is off, then pr_inet_create_conn() will
     * create and bind to a wildcard socket.  However, should it be an
     * IPv4 or an IPv6 wildcard socket?
     */
    if (!SocketBindTight) {
#ifdef PR_USE_IPV6
      if (pr_netaddr_use_ipv6()) {
        pr_inet_set_default_family(NULL, AF_INET6);

      } else {
        int default_family;

        default_family = pr_netaddr_get_family(main_server->addr);
        pr_inet_set_default_family(NULL, default_family);
      }
#else
      pr_inet_set_default_family(NULL,
        pr_netaddr_get_family(main_server->addr));
#endif /* PR_USE_IPV6 */
    }

    main_server->listen = pr_ipbind_get_listening_conn(main_server,
      (SocketBindTight ? main_server->addr : NULL), main_server->ServerPort);
    if (main_server->listen == NULL) {
      return -1;
    }

  } else {
    main_server->listen = NULL;
  }

  default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE);
  if (default_server != NULL &&
      *default_server == TRUE) {
    is_default = TRUE;
  }

  if (main_server->ServerPort ||
      is_default) {
    PR_CREATE_IPBIND(main_server, main_server->addr, main_server->ServerPort);
    PR_OPEN_IPBIND(main_server->addr, main_server->ServerPort,
      main_server->listen, is_default, TRUE, TRUE);
    PR_ADD_IPBINDS(main_server);
  }

  for (serv = main_server->next; serv; serv = serv->next) {
    config_rec *c;
    int is_namebind = FALSE;

    /* See if this server is a namebind, to be part of an existing ipbind. */
    c = find_config(serv->conf, CONF_PARAM, "ServerAlias", FALSE);
    while (c != NULL) {
      pr_signals_handle();

      res = pr_namebind_create(serv, c->argv[0], serv->addr, serv->ServerPort);
      if (res == 0) {
        is_namebind = TRUE;

        res = pr_namebind_open(c->argv[0], serv->addr, serv->ServerPort);
        if (res < 0) {
          pr_log_pri(PR_LOG_NOTICE,
            "%s:%d: notice: unable to open namebind '%s': %s", __FILE__,
            __LINE__, (char *) c->argv[0], strerror(errno));
        }

      } else {
        pr_log_pri(PR_LOG_NOTICE,
          "unable to create namebind for '%s' to %s#%u: %s",
          (char *) c->argv[0], pr_netaddr_get_ipstr(serv->addr),
          serv->ServerPort, strerror(errno));
      }

      c = find_config_next(c, c->next, CONF_PARAM, "ServerAlias", FALSE);
    }

    if (is_namebind == TRUE) {
      continue;
    }

    if (serv->ServerPort != main_server->ServerPort ||
        SocketBindTight ||
        !main_server->listen) {
      is_default = FALSE;

      default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE);
      if (default_server != NULL &&
          *default_server == TRUE) {
        is_default = TRUE;
      }

      if (serv->ServerPort) {
        if (!SocketBindTight) {
#ifdef PR_USE_IPV6
          if (pr_netaddr_use_ipv6()) {
            pr_inet_set_default_family(NULL, AF_INET6);

          } else {
            pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr));
          }
#else
          pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr));
#endif /* PR_USE_IPV6 */
        }

        serv->listen = pr_ipbind_get_listening_conn(serv,
          (SocketBindTight ? serv->addr : NULL), serv->ServerPort);
        if (serv->listen == NULL) {
          return -1;
        }

        PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
        PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default,
          FALSE, TRUE);
        PR_ADD_IPBINDS(serv);

      } else if (is_default) {
        serv->listen = NULL;

        PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
        PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default,
          FALSE, TRUE);
        PR_ADD_IPBINDS(serv);

      } else {
        serv->listen = NULL;
      }

    } else {
      /* Because this server is sharing the connection with the main server,
       * we need a cleanup handler to remove the server's reference when the
       * original connection's pool is destroyed.
       */

      is_default = FALSE;
      default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE);
      if (default_server != NULL &&
          *default_server == TRUE) {
        is_default = TRUE;
      }

      serv->listen = main_server->listen;
      register_cleanup(serv->listen->pool, &serv->listen, server_cleanup_cb,
        server_cleanup_cb);

      PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort);
      PR_OPEN_IPBIND(serv->addr, serv->ServerPort, NULL, is_default, FALSE,
        TRUE);
      PR_ADD_IPBINDS(serv);
    }
  }

  /* Any "unclaimed" listening conns can be removed and closed. */
  if (listening_conn_list) {
    struct listener_rec *lr, *lrn;

    for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lrn) {
      lrn = lr->next;

      if (!lr->claimed) {
        xaset_remove(listening_conn_list, (xasetmember_t *) lr);
        destroy_pool(lr->pool);
      }
    }
  }

  return 0;
}
예제 #23
0
int pr_netaddr_cmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2) {
  pool *tmp_pool = NULL;
  pr_netaddr_t *a, *b;
  int res;

  if (na1 && !na2)
    return 1;

  if (!na1 && na2)
    return -1;

  if (!na1 && !na2)
    return 0;

  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {

    /* Cannot compare addresses from different families, unless one
     * of the netaddrs has an AF_INET family, and the other has an
     * AF_INET6 family AND is an IPv4-mapped IPv6 address.
     */

    if (pr_netaddr_is_v4mappedv6(na1) != TRUE &&
        pr_netaddr_is_v4mappedv6(na2) != TRUE) {
      errno = EINVAL;
      return -1;
    }

    if (pr_netaddr_is_v4mappedv6(na1) == TRUE) {
      tmp_pool = make_sub_pool(permanent_pool);

      /* This case means that na1 is an IPv4-mapped IPv6 address, and
       * na2 is an IPv4 address.
       */
      a = pr_netaddr_alloc(tmp_pool);
      pr_netaddr_set_family(a, AF_INET);
      pr_netaddr_set_port(a, pr_netaddr_get_port(na1));
      memcpy(&a->na_addr.v4.sin_addr, get_v4inaddr(na1),
        sizeof(struct in_addr));

      b = (pr_netaddr_t *) na2;

      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(b),
        pr_netaddr_get_ipstr(a));

    } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) {
      tmp_pool = make_sub_pool(permanent_pool);

      /* This case means that na is an IPv4 address, and na2 is an
       * IPv4-mapped IPv6 address.
       */
      a = (pr_netaddr_t *) na1;

      b = pr_netaddr_alloc(tmp_pool);
      pr_netaddr_set_family(b, AF_INET);
      pr_netaddr_set_port(b, pr_netaddr_get_port(na2));
      memcpy(&b->na_addr.v4.sin_addr, get_v4inaddr(na2),
        sizeof(struct in_addr));

      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a),
        pr_netaddr_get_ipstr(b));

    } else {
      a = (pr_netaddr_t *) na1;
      b = (pr_netaddr_t *) na2;
    }

  } else {
    a = (pr_netaddr_t *) na1;
    b = (pr_netaddr_t *) na2;
  }

  switch (pr_netaddr_get_family(a)) {
    case AF_INET:
      res = memcmp(&a->na_addr.v4.sin_addr, &b->na_addr.v4.sin_addr,
        sizeof(struct in_addr));
      if (tmp_pool)
        destroy_pool(tmp_pool);
      return res;

#ifdef PR_USE_IPV6
    case AF_INET6:
      if (use_ipv6) {
        res = memcmp(&a->na_addr.v6.sin6_addr, &b->na_addr.v6.sin6_addr,
          sizeof(struct in6_addr));
        if (tmp_pool)
          destroy_pool(tmp_pool);
        return res;
      }
#endif /* PR_USE_IPV6 */
  }

  if (tmp_pool)
    destroy_pool(tmp_pool);

  errno = EPERM;
  return -1;
}
예제 #24
0
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;
}
예제 #25
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
    }
예제 #26
0
/* This differs from pr_netaddr_get_ipstr() in that pr_netaddr_get_ipstr()
 * returns a string of the numeric form of the given network address, whereas
 * this function returns a string of the DNS name (if present).
 */
const char *pr_netaddr_get_dnsstr(pr_netaddr_t *na) {
  char *name = NULL;
  char buf[256];

  if (!na) {
    errno = EINVAL;
    return NULL;
  }

  /* If this pr_netaddr_t has already been resolved to an DNS string, return the
   * cached string.
   */
  if (na->na_have_dnsstr)
    return na->na_dnsstr;

  if (reverse_dns) {
    int res = 0;

    pr_trace_msg(trace_channel, 3,
      "verifying DNS name for IP address %s via reverse DNS lookup",
      pr_netaddr_get_ipstr(na));

    memset(buf, '\0', sizeof(buf));
    res = pr_getnameinfo(pr_netaddr_get_sockaddr(na),
      pr_netaddr_get_sockaddr_len(na), buf, sizeof(buf), NULL, 0, NI_NAMEREQD);
    buf[sizeof(buf)-1] = '\0';

    if (res == 0) {
      char **checkaddr;
      struct hostent *hent = NULL;
      unsigned char ok = FALSE;
      int family = pr_netaddr_get_family(na);
      void *inaddr = pr_netaddr_get_inaddr(na);
    
#ifdef HAVE_GETHOSTBYNAME2
      if (pr_netaddr_is_v4mappedv6(na) == TRUE) {
        family = AF_INET;
        inaddr = get_v4inaddr(na);
      }

      hent = gethostbyname2(buf, family);
#else
      hent = gethostbyname(buf);
#endif /* HAVE_GETHOSTBYNAME2 */

      if (hent != NULL) {
        char **alias;

        pr_trace_msg(trace_channel, 10,
          "checking addresses associated with host '%s'",
          hent->h_name ? hent->h_name : "(null)");
        for (alias = hent->h_aliases; *alias; ++alias) {
          pr_trace_msg(trace_channel, 10, "host '%s' has alias '%s'",
            hent->h_name ? hent->h_name : "(null)", *alias);
        }
        
        switch (hent->h_addrtype) {
          case AF_INET:
            if (family == AF_INET) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;

#ifdef PR_USE_IPV6
          case AF_INET6:
            if (use_ipv6 && family == AF_INET6) {
              for (checkaddr = hent->h_addr_list; *checkaddr; ++checkaddr) {
                if (memcmp(*checkaddr, inaddr, hent->h_length) == 0) {
                  ok = TRUE;
                  break;
                }
              }
            } 
            break;
#endif /* PR_USE_IPV6 */
        }

        if (ok) {
          name = buf;
          pr_trace_msg(trace_channel, 8,
            "using DNS name '%s' for IP address '%s'", name,
            pr_netaddr_get_ipstr(na));

        } else {
          name = NULL;
          pr_trace_msg(trace_channel, 8,
            "unable to verify any DNS names for IP address '%s'",
            pr_netaddr_get_ipstr(na));
        }

      } else
        pr_log_debug(DEBUG1, "notice: unable to resolve '%s': %s", buf,
          hstrerror(errno));
    }

  } else
    pr_log_debug(DEBUG10,
      "UseReverseDNS off, returning IP address instead of DNS name");

  if (name) {
    name = pr_inet_validate(name);

  } else {
    name = (char *) pr_netaddr_get_ipstr(na);
  }

  /* Copy the string into the pr_netaddr_t cache as well, so we only
   * have to do this once for this pr_netaddr_t.
   */
  memset(na->na_dnsstr, '\0', sizeof(na->na_dnsstr));
  sstrncpy(na->na_dnsstr, name, sizeof(na->na_dnsstr));
  na->na_have_dnsstr = TRUE;

  return na->na_dnsstr;
}
예제 #27
0
int pr_netaddr_ncmp(const pr_netaddr_t *na1, const pr_netaddr_t *na2,
    unsigned int bitlen) {
  pool *tmp_pool = NULL;
  pr_netaddr_t *a, *b;
  unsigned int nbytes, nbits;
  const unsigned char *in1, *in2;

  if (na1 && !na2)
    return 1;

  if (!na1 && na2)
    return -1;

  if (!na1 && !na2)
    return 0;

  if (pr_netaddr_get_family(na1) != pr_netaddr_get_family(na2)) {

    /* Cannot compare addresses from different families, unless one
     * of the netaddrs has an AF_INET family, and the other has an
     * AF_INET6 family AND is an IPv4-mapped IPv6 address.
     */

    if (pr_netaddr_is_v4mappedv6(na1) != TRUE &&
        pr_netaddr_is_v4mappedv6(na2) != TRUE) {
      errno = EINVAL;
      return -1;
    }

    if (pr_netaddr_is_v4mappedv6(na1) == TRUE) {
      tmp_pool = make_sub_pool(permanent_pool);

      /* This case means that na1 is an IPv4-mapped IPv6 address, and
       * na2 is an IPv4 address.
       */
      a = pr_netaddr_alloc(tmp_pool);
      pr_netaddr_set_family(a, AF_INET);
      pr_netaddr_set_port(a, pr_netaddr_get_port(na1));
      memcpy(&a->na_addr.v4.sin_addr, get_v4inaddr(na1),
        sizeof(struct in_addr));

      b = (pr_netaddr_t *) na2;

      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(b),
        pr_netaddr_get_ipstr(a));

    } else if (pr_netaddr_is_v4mappedv6(na2) == TRUE) {
      tmp_pool = make_sub_pool(permanent_pool);

      /* This case means that na is an IPv4 address, and na2 is an
       * IPv4-mapped IPv6 address.
       */
      a = (pr_netaddr_t *) na1;

      b = pr_netaddr_alloc(tmp_pool);
      pr_netaddr_set_family(b, AF_INET);
      pr_netaddr_set_port(b, pr_netaddr_get_port(na2));
      memcpy(&b->na_addr.v4.sin_addr, get_v4inaddr(na2),
        sizeof(struct in_addr));

      pr_trace_msg(trace_channel, 6, "comparing IPv4 address '%s' against "
        "IPv4-mapped IPv6 address '%s'", pr_netaddr_get_ipstr(a),
        pr_netaddr_get_ipstr(b));

    } else {
      a = (pr_netaddr_t *) na1;
      b = (pr_netaddr_t *) na2;
    }

  } else {
    a = (pr_netaddr_t *) na1;
    b = (pr_netaddr_t *) na2;
  }

  switch (pr_netaddr_get_family(a)) {
    case AF_INET: {
      /* Make sure that the given number of bits is not more than supported
       * for IPv4 addresses (32).
       */
      if (bitlen > 32) {
        errno = EINVAL;
        return -1;
      }

      break;
    }

#ifdef PR_USE_IPV6
    case AF_INET6: {
      if (use_ipv6) {
        /* Make sure that the given number of bits is not more than supported
         * for IPv6 addresses (128).
         */
        if (bitlen > 128) {
          errno = EINVAL;
          return -1;
        }

        break;
      }
    }
#endif /* PR_USE_IPV6 */

    default:
      errno = EPERM;
      return -1;
  }

  /* Retrieve pointers to the contained in_addrs. */
  in1 = (const unsigned char *) pr_netaddr_get_inaddr(a);
  in2 = (const unsigned char *) pr_netaddr_get_inaddr(b);

  /* Determine the number of bytes, and leftover bits, in the given
   * bit length.
   */
  nbytes = bitlen / 8;
  nbits = bitlen % 8;

  /* Compare bytes, using memcmp(3), first. */
  if (nbytes > 0) {
    int res = memcmp(in1, in2, nbytes);

    /* No need to continue comparing the addresses if they differ already. */
    if (res != 0) {
      if (tmp_pool)
        destroy_pool(tmp_pool);

      return res;
    }
  }

  /* Next, compare the remaining bits in the addresses. */
  if (nbits > 0) {
    unsigned char mask;

    /* Get the bytes in the addresses that have not yet been compared. */
    unsigned char in1byte = in1[nbytes];
    unsigned char in2byte = in2[nbytes];

    /* Build up a mask covering the bits left to be checked. */
    mask = (0xff << (8 - nbits)) & 0xff;

    if ((in1byte & mask) > (in2byte & mask)) {
      if (tmp_pool)
        destroy_pool(tmp_pool);

      return 1;
    }

    if ((in1byte & mask) < (in2byte & mask)) {
      if (tmp_pool)
        destroy_pool(tmp_pool);

      return -1;
    }
  }

  if (tmp_pool)
    destroy_pool(tmp_pool);

  /* If we've made it this far, the addresses match, for the given bit
   * length.
   */
  return 0;
}
예제 #28
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;
}
예제 #29
0
const char *proxy_ftp_msg_fmt_ext_addr(pool *p, const pr_netaddr_t *addr,
    unsigned short port, int cmd_id, int use_masqaddr) {
  const char *addr_str;
  char delim = '|', *msg;
  int family = 0;
  size_t addr_strlen, msglen;

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

  if (use_masqaddr) {
    config_rec *c;

    /* Handle MasqueradeAddress. */
    c = find_config(main_server->conf, CONF_PARAM, "MasqueradeAddress", FALSE);
    if (c != NULL) {
      addr = c->argv[0];
    }
  }

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

  switch (pr_netaddr_get_family(addr)) {
    case AF_INET:
      family = 1;
      break;

#ifdef PR_USE_IPV6
    case AF_INET6:
      family = 2;
      break;
#endif /* PR_USE_IPV6 */

    default:
      /* Unlikely to happen. */
      errno = EINVAL;
      return NULL;
  }

  addr_str = pr_netaddr_get_ipstr(addr);
  addr_strlen = strlen(addr_str);

  /* 4 delimiters, the network protocol, the IP address, the port, and a NUL. */
  msglen = (4 * 1) + addr_strlen + 6 + 1;

  msg = pcalloc(p, msglen);
  switch (cmd_id) {
    case PR_CMD_EPRT_ID:
      snprintf(msg, msglen, "%c%d%c%s%c%hu%c", delim, family, delim,
        addr_str, delim, port, delim);
      break;

    case PR_CMD_EPSV_ID:
      snprintf(msg, msglen-1, "%c%c%c%u%c", delim, delim, delim, port, delim);
      break;

    default:
      pr_trace_msg(trace_channel, 3, "invalid/unsupported command ID: %d",
        cmd_id);
      errno = EINVAL;
      return NULL;
  }

  return msg;
}
예제 #30
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;
}