You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by tr...@apache.org on 2001/03/15 19:28:10 UTC
cvs commit: apr/network_io/unix sa_common.c
trawick 01/03/15 10:28:09
Modified: . CHANGES
test .cvsignore Makefile.in
include apr_errno.h apr_network_io.h
misc/unix errorcodes.c
network_io/unix sa_common.c
Added: test testipsub.c
Log:
Add apr_ipsubnet_create() and apr_ipsubnet_test() for testing
whether or not an address is within a subnet.
Revision Changes Path
1.74 +3 -0 apr/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/apr/CHANGES,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -r1.73 -r1.74
--- CHANGES 2001/03/08 20:06:57 1.73
+++ CHANGES 2001/03/15 18:27:41 1.74
@@ -1,5 +1,8 @@
Changes with APR b1
+ *) Add apr_ipsubnet_create() and apr_ipsubnet_test() for testing
+ whether or not an address is within a subnet. [Jeff Trawick]
+
*) Add apr_sendto and apr_recvfrom for Unix. Start of adding UDP
support. [David Reid]
1.14 +2 -0 apr/test/.cvsignore
Index: .cvsignore
===================================================================
RCS file: /home/cvs/apr/test/.cvsignore,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- .cvsignore 2001/01/25 12:20:29 1.13
+++ .cvsignore 2001/03/15 18:27:46 1.14
@@ -28,3 +28,5 @@
testfile.tmp
testflock
testsockopt
+testipsub
+
1.42 +4 -0 apr/test/Makefile.in
Index: Makefile.in
===================================================================
RCS file: /home/cvs/apr/test/Makefile.in,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- Makefile.in 2001/02/19 18:42:18 1.41
+++ Makefile.in 2001/03/15 18:27:47 1.42
@@ -18,6 +18,7 @@
testoc@EXEEXT@ \
testuuid@EXEEXT@ \
testsockopt@EXEEXT@ \
+ testipsub@EXEEXT@ \
occhild@EXEEXT@ \
mod_test.so
@@ -96,5 +97,8 @@
testsockopt@EXEEXT@: testsockopt.lo ../libapr.la
$(LINK) testsockopt.lo $(ALL_LIBS)
+
+testipsub@EXEEXT@: testipsub.lo ../libapr.la
+ $(LINK) testipsub.lo $(ALL_LIBS)
# DO NOT REMOVE
1.1 apr/test/testipsub.c
Index: testipsub.c
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
#include <assert.h>
#include <stdlib.h>
#include "apr_general.h"
#include "apr_network_io.h"
#include "apr_errno.h"
static void closeapr(void)
{
apr_terminate();
}
static void test_bad_input(apr_pool_t *p)
{
struct {
const char *ipstr;
const char *mask;
apr_status_t expected_rv;
} testcases[] =
{
/* so we have a few good inputs in here; sue me */
{"my.host.name", NULL, APR_EINVAL}
,{"127.0.0.256", NULL, APR_EBADIP}
,{"127.0.0.1", NULL, APR_SUCCESS}
,{"127.0.0.1", "32", APR_SUCCESS}
,{"127.0.0.1", "1", APR_SUCCESS}
,{"127.0.0.1", "15", APR_SUCCESS}
,{"127.0.0.1", "-1", APR_EBADMASK}
,{"127.0.0.1", "0", APR_EBADMASK}
,{"127.0.0.1", "33", APR_EBADMASK}
,{"127.0.0.1", "255.0.0.0", APR_SUCCESS}
,{"127.0.0.1", "255.0", APR_EBADMASK}
,{"127.0.0.1", "255.255.256.0", APR_EBADMASK}
,{"127.0.0.1", "abc", APR_EBADMASK}
,{"127", NULL, APR_SUCCESS}
,{"127.0.0.1.2", NULL, APR_EBADIP}
,{"127.0.0.1.2", "8", APR_EBADIP}
,{"127", "255.0.0.0", APR_EBADIP} /* either EBADIP or EBADMASK seems fine */
#if APR_HAVE_IPV6
,{"::1", NULL, APR_SUCCESS}
,{"::1", "20", APR_SUCCESS}
,{"fe80::", "16", APR_SUCCESS}
,{"fe80::", "255.0.0.0", APR_EBADMASK}
,{"fe80::1", "0", APR_EBADMASK}
,{"fe80::1", "-1", APR_EBADMASK}
,{"fe80::1", "1", APR_SUCCESS}
,{"fe80::1", "33", APR_SUCCESS}
,{"fe80::1", "128", APR_SUCCESS}
,{"fe80::1", "129", APR_EBADMASK}
#else
/* do some IPv6 stuff and verify that it fails with APR_EBADIP */
#endif
};
int i;
apr_ipsubnet_t *ipsub;
apr_status_t rv;
for (i = 0; i < (sizeof testcases / sizeof testcases[0]); i++) {
rv = apr_ipsubnet_create(&ipsub, testcases[i].ipstr, testcases[i].mask, p);
assert(rv == testcases[i].expected_rv);
}
}
static void test_singleton_subnets(apr_pool_t *p)
{
const char *v4addrs[] = {
"127.0.0.1", "129.42.18.99", "63.161.155.20", "207.46.230.229", "64.208.42.36",
"198.144.203.195", "192.18.97.241", "198.137.240.91", "62.156.179.119",
"204.177.92.181"
};
apr_ipsubnet_t *ipsub;
apr_sockaddr_t *sa;
apr_status_t rv;
int i, j, rc;
for (i = 0; i < sizeof v4addrs / sizeof v4addrs[0]; i++) {
rv = apr_ipsubnet_create(&ipsub, v4addrs[i], NULL, p);
assert(rv == APR_SUCCESS);
for (j = 0; j < sizeof v4addrs / sizeof v4addrs[0]; j++) {
rv = apr_sockaddr_info_get(&sa, v4addrs[j], APR_INET, 0, 0, p);
assert(rv == APR_SUCCESS);
rc = apr_ipsubnet_test(ipsub, sa);
if (!strcmp(v4addrs[i], v4addrs[j])) {
assert(rc != 0);
}
else {
assert(rc == 0);
}
}
}
/* same for v6? */
}
static void test_interesting_subnets(apr_pool_t *p)
{
struct {
const char *ipstr, *mask;
int family;
char *in_subnet, *not_in_subnet;
} testcases[] =
{
{"9.67", NULL, APR_INET, "9.67.113.15", "10.1.2.3"}
,{"9.67.0.0", "16", APR_INET, "9.67.113.15", "10.1.2.3"}
,{"9.67.0.0", "255.255.0.0", APR_INET, "9.67.113.15", "10.1.2.3"}
,{"9.67.113.99", "16", APR_INET, "9.67.113.15", "10.1.2.3"}
,{"9.67.113.99", "255.255.255.0", APR_INET, "9.67.113.15", "10.1.2.3"}
#if APR_HAVE_IPV6
,{"fe80::", "8", APR_INET6, "fe80::1", "ff01::1"}
,{"ff01::", "8", APR_INET6, "ff01::1", "fe80::1"}
,{"3FFE:8160::", "28", APR_INET6, "3ffE:816e:abcd:1234::1", "3ffe:8170::1"}
#endif
};
apr_ipsubnet_t *ipsub;
apr_sockaddr_t *sa;
apr_status_t rv;
int i, rc;
for (i = 0; i < sizeof testcases / sizeof testcases[0]; i++) {
rv = apr_ipsubnet_create(&ipsub, testcases[i].ipstr, testcases[i].mask, p);
assert(rv == APR_SUCCESS);
rv = apr_sockaddr_info_get(&sa, testcases[i].in_subnet, testcases[i].family, 0, 0, p);
assert(rv == APR_SUCCESS);
rc = apr_ipsubnet_test(ipsub, sa);
assert(rc != 0);
rv = apr_sockaddr_info_get(&sa, testcases[i].not_in_subnet, testcases[i].family, 0, 0, p);
assert(rv == APR_SUCCESS);
rc = apr_ipsubnet_test(ipsub, sa);
assert(rc == 0);
}
}
int main(void)
{
apr_status_t rv;
apr_pool_t *p;
char buf[128];
rv = apr_initialize();
if (rv != APR_SUCCESS) {
fprintf(stderr, "apr_initialize()->%d/%s\n",
rv,
apr_strerror(rv, buf, sizeof buf));
exit(1);
}
atexit(closeapr);
rv = apr_pool_create(&p, NULL);
if (rv != APR_SUCCESS) {
fprintf(stderr, "apr_pool_create()->%d/%s\n",
rv,
apr_strerror(rv, buf, sizeof buf));
exit(1);
}
test_bad_input(p);
test_singleton_subnets(p);
test_interesting_subnets(p);
printf("error strings:\n");
printf("\tAPR_EBADIP\t`%s'\n", apr_strerror(APR_EBADIP, buf, sizeof buf));
printf("\tAPR_EBADMASK\t`%s'\n", apr_strerror(APR_EBADMASK, buf, sizeof buf));
return 0;
}
1.55 +6 -4 apr/include/apr_errno.h
Index: apr_errno.h
===================================================================
RCS file: /home/cvs/apr/include/apr_errno.h,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -r1.54 -r1.55
--- apr_errno.h 2001/02/16 04:15:42 1.54
+++ apr_errno.h 2001/03/15 18:27:53 1.55
@@ -177,6 +177,8 @@
* APR_EDSOOPEN APR was unable to open the dso object. For more
* information call apr_dso_error().
* APR_EGENERAL General failure (specific information not available)
+ * APR_EBADIP The specified IP address is invalid
+ * APR_EBADMASK The specified netmask is invalid
* </PRE>
*
* <PRE>
@@ -232,8 +234,8 @@
#define APR_ENOTHDKEY (APR_OS_START_ERROR + 13)
#define APR_EGENERAL (APR_OS_START_ERROR + 14)
#define APR_ENOSHMAVAIL (APR_OS_START_ERROR + 15)
-/* empty slot: +16 */
-/* empty slot: +17 */
+#define APR_EBADIP (APR_OS_START_ERROR + 16)
+#define APR_EBADMASK (APR_OS_START_ERROR + 17)
/* empty slot: +18 */
#define APR_EDSOOPEN (APR_OS_START_ERROR + 19)
@@ -254,8 +256,8 @@
#define APR_STATUS_IS_ENOTHDKEY(s) ((s) == APR_ENOTHDKEY)
#define APR_STATUS_IS_EGENERAL(s) ((s) == APR_EGENERAL)
#define APR_STATUS_IS_ENOSHMAVAIL(s) ((s) == APR_ENOSHMAVAIL)
-/* empty slot: +16 */
-/* empty slot: +17 */
+#define APR_STATUS_IS_EBADIP(s) ((s) == APR_EBADIP)
+#define APR_STATUS_IS_EBADMASK(s) ((s) == APR_EBADMASK)
/* empty slot: +18 */
#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN)
1.100 +33 -0 apr/include/apr_network_io.h
Index: apr_network_io.h
===================================================================
RCS file: /home/cvs/apr/include/apr_network_io.h,v
retrieving revision 1.99
retrieving revision 1.100
diff -u -r1.99 -r1.100
--- apr_network_io.h 2001/03/08 19:58:35 1.99
+++ apr_network_io.h 2001/03/15 18:27:54 1.100
@@ -218,6 +218,19 @@
int numtrailers;
};
+/** A structure to represent an IP subnet */
+typedef struct apr_ipsubnet_t apr_ipsubnet_t;
+struct apr_ipsubnet_t {
+ int family;
+#if APR_HAVE_IPV6
+ apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
+ apr_uint32_t mask[4];
+#else
+ apr_uint32_t sub[1];
+ apr_uint32_t mask[1];
+#endif
+};
+
/* function definitions */
/**
@@ -753,6 +766,26 @@
*/
APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr,
const char *servname);
+
+/**
+ * Build an ip-subnet representation from an IP address and optional netmask or
+ * number-of-bits.
+ * @param ipsub The new ip-subnet representation
+ * @param ipstr The input IP address string
+ * @param mask_or_numbits The input netmask or number-of-bits string, or NULL
+ * @param p The pool to allocate from
+ */
+APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr,
+ const char *mask_or_numbits, apr_pool_t *p);
+
+/**
+ * Test the IP address in an apr_sockaddr_t against a pre-built ip-subnet
+ * representation.
+ * @param ipsub The ip-subnet representation
+ * @param sa The socket address to test
+ * @return non-zero if the socket address is within the subnet, 0 otherwise
+ */
+APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa);
#ifdef __cplusplus
}
1.34 +4 -0 apr/misc/unix/errorcodes.c
Index: errorcodes.c
===================================================================
RCS file: /home/cvs/apr/misc/unix/errorcodes.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -r1.33 -r1.34
--- errorcodes.c 2001/02/25 20:39:34 1.33
+++ errorcodes.c 2001/03/15 18:28:00 1.34
@@ -111,6 +111,10 @@
return "DSO load failed";
#endif /* HAVE_LIBDL */
#endif /* APR_HAS_DSO */
+ case APR_EBADIP:
+ return "The specified IP address is invalid.";
+ case APR_EBADMASK:
+ return "The specified network mask is invalid.";
case APR_INCHILD:
return
"Your code just forked, and you are currently executing in the "
1.30 +231 -0 apr/network_io/unix/sa_common.c
Index: sa_common.c
===================================================================
RCS file: /home/cvs/apr/network_io/unix/sa_common.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- sa_common.c 2001/02/25 20:39:35 1.29
+++ sa_common.c 2001/03/15 18:28:04 1.30
@@ -498,3 +498,234 @@
return errno;
}
+static apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network)
+{
+ /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */
+ int shift;
+ char *s, *t;
+ int octet;
+ char buf[sizeof "255.255.255.255"];
+
+ if (strlen(network) < sizeof buf) {
+ strcpy(buf, network);
+ }
+ else {
+ return APR_EBADIP;
+ }
+
+ /* parse components */
+ s = buf;
+ ipsub->sub[0] = 0;
+ ipsub->mask[0] = 0;
+ shift = 24;
+ while (*s) {
+ t = s;
+ if (!apr_isdigit(*t)) {
+ return APR_EBADIP;
+ }
+ while (apr_isdigit(*t)) {
+ ++t;
+ }
+ if (*t == '.') {
+ *t++ = 0;
+ }
+ else if (*t) {
+ return APR_EBADIP;
+ }
+ if (shift < 0) {
+ return APR_EBADIP;
+ }
+ octet = atoi(s);
+ if (octet < 0 || octet > 255) {
+ return APR_EBADIP;
+ }
+ ipsub->sub[0] |= octet << shift;
+ ipsub->mask[0] |= 0xFFUL << shift;
+ s = t;
+ shift -= 8;
+ }
+ ipsub->sub[0] = ntohl(ipsub->sub[0]);
+ ipsub->mask[0] = ntohl(ipsub->mask[0]);
+ ipsub->family = AF_INET;
+ return APR_SUCCESS;
+}
+
+/* return values:
+ * APR_EINVAL not an IP address; caller should see if it is something else
+ * APR_BADIP IP address portion is is not valid
+ * APR_BADMASK mask portion is not valid
+ */
+
+static apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed)
+{
+ /* supported flavors of IP:
+ *
+ * . IPv6 numeric address string (e.g., "fe80::1")
+ *
+ * . IPv4 numeric address string (e.g., "127.0.0.1")
+ *
+ * . IPv4 network string (e.g., "9.67")
+ *
+ * IMPORTANT: This network form is only allowed if network_allowed is on.
+ */
+ int rc;
+
+#if APR_HAVE_IPV6
+ rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub);
+ if (rc == 1) {
+ ipsub->family = AF_INET6;
+ }
+ else
+#endif
+ {
+ rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub);
+ if (rc == 1) {
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) {
+ /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6
+ * addresses; this of course forces the user to specify IPv4 addresses
+ * in a.b.c.d style instead of ::ffff:a.b.c.d style.
+ */
+ return APR_EBADIP;
+ }
+ ipsub->family = AF_INET;
+ }
+ }
+ if (rc != 1) {
+ if (network_allowed) {
+ return parse_network(ipsub, ipstr);
+ }
+ else {
+ return APR_EBADIP;
+ }
+ }
+ return APR_SUCCESS;
+}
+
+static int looks_like_ip(const char *ipstr)
+{
+ if (strchr(ipstr, ':')) {
+ /* definitely not a hostname; assume it is intended to be an IPv6 address */
+ return 1;
+ }
+
+ /* simple IPv4 address string check */
+ while ((*ipstr == '.') || apr_isdigit(*ipstr))
+ ipstr++;
+ return (*ipstr == '\0');
+}
+
+static void fix_subnet(apr_ipsubnet_t *ipsub)
+{
+ /* in case caller specified more bits in network address than are
+ * valid according to the mask, turn off the extra bits
+ */
+ int i;
+
+ for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) {
+ ipsub->sub[i] &= ipsub->mask[i];
+ }
+}
+
+/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */
+APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr,
+ const char *mask_or_numbits, apr_pool_t *p)
+{
+ apr_status_t rv;
+ char *endptr;
+ long bits, maxbits;
+
+ /* filter out stuff which doesn't look remotely like an IP address; this helps
+ * callers like mod_access which have a syntax allowing hostname or IP address;
+ * APR_EINVAL tells the caller that it was probably not intended to be an IP
+ * address
+ */
+ if (!looks_like_ip(ipstr)) {
+ return APR_EINVAL;
+ }
+
+ *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t));
+
+ /* assume ipstr is an individual IP address, not a subnet */
+ memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask);
+
+ rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ if (mask_or_numbits) {
+ if ((*ipsub)->family == AF_INET) {
+ maxbits = 32;
+ }
+#if APR_HAVE_IPV6
+ else {
+ maxbits = 128;
+ }
+#endif
+ bits = strtol(mask_or_numbits, &endptr, 10);
+ if (*endptr == '\0' && bits > 0 && bits <= maxbits) {
+ /* valid num-bits string; fill in mask appropriately */
+ int cur_entry = 0;
+ apr_int32_t cur_bit_value;
+
+ memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask);
+ while (bits > 32) {
+ (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */
+ bits -= 32;
+ ++cur_entry;
+ }
+ cur_bit_value = 0x80000000;
+ while (bits) {
+ (*ipsub)->mask[cur_entry] |= cur_bit_value;
+ --bits;
+ cur_bit_value /= 2;
+ }
+ (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]);
+ }
+ else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 &&
+ (*ipsub)->family == AF_INET) {
+ /* valid IPv4 netmask */
+ }
+ else {
+ return APR_EBADMASK;
+ }
+ }
+
+ fix_subnet(*ipsub);
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa)
+{
+#if APR_HAVE_IPV6
+ if (sa->sa.sin.sin_family == AF_INET) {
+ if (ipsub->family == AF_INET &&
+ ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) {
+ return 1;
+ }
+ }
+ else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) {
+ if (ipsub->family == AF_INET &&
+ (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) {
+ return 1;
+ }
+ }
+ else {
+ apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr;
+
+ if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] &&
+ (addr[1] & ipsub->mask[1]) == ipsub->sub[1] &&
+ (addr[2] & ipsub->mask[2]) == ipsub->sub[2] &&
+ (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) {
+ return 1;
+ }
+ }
+#else
+ if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) {
+ return 1;
+ }
+#endif /* APR_HAVE_IPV6 */
+ return 0; /* no match */
+}
+