/* 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; }
END_TEST START_TEST (netaddr_dup_test) { pr_netaddr_t *res, *addr; res = pr_netaddr_dup(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL"); res = pr_netaddr_dup(p, NULL); fail_unless(res == NULL, "Failed to handle null addr"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL"); addr = pr_netaddr_alloc(p); pr_netaddr_set_family(addr, AF_INET); res = pr_netaddr_dup(NULL, addr); fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL"); res = pr_netaddr_dup(p, addr); fail_unless(res != NULL, "Failed to dup netaddr: %s", strerror(errno)); fail_unless(res->na_family == addr->na_family, "Expected family %d, got %d", addr->na_family, res->na_family); }
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"); }
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; }
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; }
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; }
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; }