]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add ks_acl
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 25 Jan 2017 23:10:50 +0000 (17:10 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Wed, 25 Jan 2017 23:10:50 +0000 (17:10 -0600)
libs/libks/Makefile.am
libs/libks/src/include/ks.h
libs/libks/src/include/ks_acl.h [new file with mode: 0644]
libs/libks/src/include/ks_pool.h
libs/libks/src/include/ks_types.h
libs/libks/src/ks_acl.c [new file with mode: 0644]
libs/libks/src/ks_pool.c
libs/libks/src/ks_string.c
libs/libks/test/Makefile.am
libs/libks/test/testacl.c [new file with mode: 0644]

index 44abb688e3df830dac29ef0a196eddc26a363c28..f49cb238d2f60a1e83b3a730393bb527f9dd9eb8 100644 (file)
@@ -18,6 +18,7 @@ libks_la_SOURCES += src/dht/ks_dht_job.c src/dht/ks_dht_search.c src/dht/ks_dht_
 libks_la_SOURCES += src/dht/ks_dht_bucket.c
 libks_la_SOURCES += crypt/aeskey.c crypt/aestab.c crypt/sha2.c crypt/twofish.c crypt/aes_modes.c crypt/aescrypt.c crypt/twofish_cfb.c 
 #aes.h aescpp.h brg_endian.h aesopt.h aestab.h brg_types.h sha2.h twofish.h
+libks_la_SOURCES += src/ks_acl.c
 
 libks_la_CFLAGS          = $(AM_CFLAGS)
 libks_la_CPPFLAGS = -DPOSIX
@@ -30,7 +31,7 @@ library_include_HEADERS += src/include/ks_pool.h src/include/simclist.h src/incl
 library_include_HEADERS += src/include/ks_dso.h src/include/ks_platform.h src/include/ks_types.h # src/include/ks_rng.h src/include/ks_dht.h
 library_include_HEADERS += src/include/ks_printf.h src/include/ks_hash.h src/include/ks_ssl.h src/include/kws.h
 library_include_HEADERS += src/utp/utp_internal.h src/utp/utp.h src/utp/utp_types.h src/utp/utp_callbacks.h src/utp/utp_templates.h
-library_include_HEADERS += src/utp/utp_hash.h src/utp/utp_packedsockaddr.h src/utp/utp_utils.h src/include/ks_utp.h
+library_include_HEADERS += src/utp/utp_hash.h src/utp/utp_packedsockaddr.h src/utp/utp_utils.h src/include/ks_utp.h src/include/ks_acl.h
 
 tests: libks.la
        $(MAKE) -C test tests
index 382780d407d6d1ae52e7d7d14bafb92ba17b5592..b19f62e463f571cf76f991d1051636ed689a725e 100644 (file)
@@ -98,7 +98,11 @@ KS_DECLARE(int) ks_toupper(int c);
 KS_DECLARE(int) ks_tolower(int c);
 KS_DECLARE(char *) ks_copy_string(char *from_str, const char *to_str, ks_size_t from_str_len);
 KS_DECLARE(int) ks_snprintf(char *buffer, size_t count, const char *fmt, ...);
-KS_DECLARE(unsigned int) ks_separate_string(char *buf, const char *delim, char **array, unsigned int arraylen);
+KS_DECLARE(unsigned int) ks_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen);
+KS_DECLARE(unsigned int) ks_separate_string(char *buf, char delim, char **array, unsigned int arraylen);
+
+#define ks_inet_pton inet_pton
+
 KS_DECLARE(int) ks_cpu_count(void);
        static __inline__ int ks_safe_strcasecmp(const char *s1, const char *s2) {
                if (!(s1 && s2)) {
@@ -111,6 +115,8 @@ KS_DECLARE(int) ks_cpu_count(void);
 
 KS_DECLARE(void) ks_random_string(char *buf, uint16_t len, char *set);
 
+#define ks_str_nil(s) (s ? s : "")
+
 #include "ks_pool.h"
 #include "ks_printf.h"
 #include "ks_json.h"
@@ -130,6 +136,7 @@ KS_DECLARE(void) ks_random_string(char *buf, uint16_t len, char *set);
 #include "kws.h"
 #include "ks_bencode.h"
 #include "ks_rng.h"
+#include "ks_acl.h"
 
 KS_END_EXTERN_C
 
diff --git a/libs/libks/src/include/ks_acl.h b/libs/libks/src/include/ks_acl.h
new file mode 100644 (file)
index 0000000..c75612f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007-2014, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * 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.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER
+ * OR 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.
+ */
+
+
+#ifndef _KS_ACL_H_
+#define _KS_ACL_H_
+
+KS_BEGIN_EXTERN_C
+
+typedef union{
+       uint32_t v4;
+       struct in6_addr v6;
+} ks_ip_t;
+
+
+#define switch_network_list_validate_ip(_list, _ip) switch_network_list_validate_ip_token(_list, _ip, NULL);
+
+#define switch_test_subnet(_ip, _net, _mask) (_mask ? ((_net & _mask) == (_ip & _mask)) : _net ? _net == _ip : 1)
+
+
+KS_DECLARE(int) ks_parse_cidr(const char *string, ks_ip_t *ip, ks_ip_t *mask, uint32_t *bitp);
+KS_DECLARE(ks_status_t) ks_network_list_create(ks_network_list_t **list, const char *name, ks_bool_t default_type,
+                                                                                                                  ks_pool_t *pool);
+KS_DECLARE(ks_status_t) ks_network_list_add_cidr_token(ks_network_list_t *list, const char *cidr_str, ks_bool_t ok, const char *token);
+#define ks_network_list_add_cidr(_list, _cidr_str, _ok) ks_network_list_add_cidr_token(_list, _cidr_str, _ok, NULL)
+
+KS_DECLARE(char *) ks_network_ipv4_mapped_ipv6_addr(const char* ip_str);
+KS_DECLARE(ks_status_t) ks_network_list_add_host_mask(ks_network_list_t *list, const char *host, const char *mask_str, ks_bool_t ok);
+KS_DECLARE(ks_bool_t) ks_network_list_validate_ip_token(ks_network_list_t *list, uint32_t ip, const char **token);
+KS_DECLARE(ks_bool_t) ks_network_list_validate_ip6_token(ks_network_list_t *list, ks_ip_t ip, const char **token);
+
+#define ks_network_list_validate_ip(_list, _ip) ks_network_list_validate_ip_token(_list, _ip, NULL);
+
+#define ks_test_subnet(_ip, _net, _mask) (_mask ? ((_net & _mask) == (_ip & _mask)) : _net ? _net == _ip : 1)
+
+KS_DECLARE(ks_bool_t) ks_check_network_list_ip_cidr(const char *ip_str, const char *cidr_str);
+KS_DECLARE(ks_bool_t) ks_check_network_list_ip_token(const char *ip_str, ks_network_list_t *list, const char **token);
+#define ks_check_network_list_ip(_i, _l) ks_check_network_list_ip_token(_i, _l, NULL)
+
+KS_END_EXTERN_C
+#endif                                                 /* defined(_KS_ACL_H_) */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
+
index 57dc5a725c9bbacfc71409c80eca4c8715d2e854..9d0ff0fadf9e5c70f613004d466193cdfe64e86f 100644 (file)
@@ -462,6 +462,7 @@ KS_DECLARE(char *) ks_pstrndup(ks_pool_t *pool, const char *str, size_t len);
 KS_DECLARE(char *) ks_pstrmemdup(ks_pool_t *pool, const char *str, size_t len);
 KS_DECLARE(void *) ks_pmemdup(ks_pool_t *pool, const void *buf, size_t len);
 KS_DECLARE(char *) ks_pstrcat(ks_pool_t *pool, ...);
+KS_DECLARE(char *) ks_psprintf(ks_pool_t *pool, const char *fmt, ...);
 
 KS_END_EXTERN_C
 
index 8c088bdd4005964cece2f0d6a13b8a46adcb469e..9e1cba61c07ab73840a40ed881cc2c71c0bdb0c6 100644 (file)
@@ -212,6 +212,10 @@ typedef void (*ks_flush_fn_t)(ks_q_t *q, void *ptr, void *flush_data);
 
 typedef struct ks_thread_pool_s ks_thread_pool_t;
 
+struct ks_network_list;
+typedef struct ks_network_list ks_network_list_t;
+
+
 KS_END_EXTERN_C
 
 #endif                                                 /* defined(_KS_TYPES_H_) */
diff --git a/libs/libks/src/ks_acl.c b/libs/libks/src/ks_acl.c
new file mode 100644 (file)
index 0000000..2dadec3
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2007-2014, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * 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.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER
+ * OR 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.
+ */
+
+#include <ks.h>
+
+
+struct ks_network_node {
+       ks_ip_t ip;
+       ks_ip_t mask;
+       uint32_t bits;
+       int family;
+       ks_bool_t ok;
+       char *token;
+       char *str;
+       struct ks_network_node *next;
+};
+typedef struct ks_network_node ks_network_node_t;
+
+struct ks_network_list {
+       struct ks_network_node *node_head;
+       ks_bool_t default_type;
+       ks_pool_t *pool;
+       char *name;
+};
+
+
+KS_DECLARE(ks_status_t) ks_network_list_create(ks_network_list_t **list, const char *name, ks_bool_t default_type,
+                                                                                                                  ks_pool_t *pool)
+{
+       ks_network_list_t *new_list;
+
+       if (!pool) {
+               ks_pool_open(&pool);
+       }
+
+       new_list = ks_pool_alloc(pool, sizeof(**list));
+       new_list->pool = pool;
+       new_list->default_type = default_type;
+       new_list->name = ks_pstrdup(new_list->pool, name);
+
+       *list = new_list;
+
+       return KS_STATUS_SUCCESS;
+}
+
+#define IN6_AND_MASK(result, ip, mask) \
+       ((uint32_t *) (result))[0] =((const uint32_t *) (ip))[0] & ((const uint32_t *)(mask))[0]; \
+       ((uint32_t *) (result))[1] =((const uint32_t *) (ip))[1] & ((const uint32_t *)(mask))[1]; \
+       ((uint32_t *) (result))[2] =((const uint32_t *) (ip))[2] & ((const uint32_t *)(mask))[2]; \
+       ((uint32_t *) (result))[3] =((const uint32_t *) (ip))[3] & ((const uint32_t *)(mask))[3];
+KS_DECLARE(ks_bool_t) ks_testv6_subnet(ks_ip_t _ip, ks_ip_t _net, ks_ip_t _mask) {
+               if (!IN6_IS_ADDR_UNSPECIFIED(&_mask.v6)) {
+                       struct in6_addr a, b;
+                       IN6_AND_MASK(&a, &_net, &_mask);
+                       IN6_AND_MASK(&b, &_ip, &_mask);
+                       return !memcmp(&a,&b, sizeof(struct in6_addr));
+               } else {
+                       if (!IN6_IS_ADDR_UNSPECIFIED(&_net.v6)) {
+                               return !memcmp(&_net,&_ip,sizeof(struct in6_addr));
+                       }
+                       else return KS_TRUE;
+               }
+}
+KS_DECLARE(ks_bool_t) ks_network_list_validate_ip6_token(ks_network_list_t *list, ks_ip_t ip, const char **token)
+{
+       ks_network_node_t *node;
+       ks_bool_t ok = list->default_type;
+       uint32_t bits = 0;
+
+       for (node = list->node_head; node; node = node->next) {
+               if (node->family == AF_INET) continue;
+
+               if (node->bits >= bits && ks_testv6_subnet(ip, node->ip, node->mask)) {
+                       if (node->ok) {
+                               ok = KS_TRUE;
+                       } else {
+                               ok = KS_FALSE;
+                       }
+
+                       bits = node->bits;
+
+                       if (token) {
+                               *token = node->token;
+                       }
+               }
+       }
+
+       return ok;
+}
+
+KS_DECLARE(ks_bool_t) ks_network_list_validate_ip_token(ks_network_list_t *list, uint32_t ip, const char **token)
+{
+       ks_network_node_t *node;
+       ks_bool_t ok = list->default_type;
+       uint32_t bits = 0;
+
+       for (node = list->node_head; node; node = node->next) {
+               if (node->family == AF_INET6) continue; /* want AF_INET */
+               if (node->bits >= bits && ks_test_subnet(ip, node->ip.v4, node->mask.v4)) {
+                       if (node->ok) {
+                               ok = KS_TRUE;
+                       } else {
+                               ok = KS_FALSE;
+                       }
+
+                       bits = node->bits;
+
+                       if (token) {
+                               *token = node->token;
+                       }
+               }
+       }
+
+       return ok;
+}
+
+KS_DECLARE(char *) ks_network_ipv4_mapped_ipv6_addr(const char* ip_str)
+{
+       /* ipv4 mapped ipv6 address */
+
+       if (strncasecmp(ip_str, "::ffff:", 7)) {
+               return NULL;
+       }
+
+       return strdup(ip_str + 7);
+}
+
+
+KS_DECLARE(int) ks_parse_cidr(const char *string, ks_ip_t *ip, ks_ip_t *mask, uint32_t *bitp)
+{
+       char host[128];
+       char *bit_str;
+       int32_t bits;
+       const char *ipv6;
+       ks_ip_t *maskv = mask;
+       ks_ip_t *ipv = ip;
+
+       ks_copy_string(host, string, sizeof(host)-1);
+       bit_str = strchr(host, '/');
+
+       if (!bit_str) {
+               return -1;
+       }
+
+       *bit_str++ = '\0';
+       bits = atoi(bit_str);
+       ipv6 = strchr(string, ':');
+       if (ipv6) {
+               int i,n;
+               if (bits < 0 || bits > 128) {
+                       return -2;
+               }
+               bits = atoi(bit_str);
+               ks_inet_pton(AF_INET6, host, (unsigned char *)ip);
+               for (n=bits,i=0 ;i < 16; i++){
+                       if (n >= 8) {
+                               maskv->v6.s6_addr[i] = 0xFF;
+                               n -= 8;
+                       } else if (n < 8) {
+                               maskv->v6.s6_addr[i] = 0xFF & ~(0xFF >> n);
+                               n -= n;
+                       } else if (n == 0) {
+                               maskv->v6.s6_addr[i] = 0x00;
+                       }
+               }
+       } else {
+               if (bits < 0 || bits > 32) {
+                       return -2;
+               }
+
+               bits = atoi(bit_str);
+               ks_inet_pton(AF_INET, host, (unsigned char *)ip);
+               ipv->v4 = htonl(ipv->v4);
+
+               maskv->v4 = 0xFFFFFFFF & ~(0xFFFFFFFF >> bits);
+       }
+       *bitp = bits;
+
+       return 0;
+}
+
+
+
+
+KS_DECLARE(ks_status_t) ks_network_list_perform_add_cidr_token(ks_network_list_t *list, const char *cidr_str, ks_bool_t ok,
+                                                                                                                                                  const char *token)
+{
+       ks_ip_t ip, mask;
+       uint32_t bits;
+       ks_network_node_t *node;
+       char *ipv4 = NULL;
+
+       if ((ipv4 = ks_network_ipv4_mapped_ipv6_addr(cidr_str))) {
+               cidr_str = ipv4;
+       }
+
+       if (ks_parse_cidr(cidr_str, &ip, &mask, &bits)) {
+               ks_log(KS_LOG_ERROR, "Error Adding %s (%s) [%s] to list %s\n",
+                                                 cidr_str, ok ? "allow" : "deny", ks_str_nil(token), list->name);
+               ks_safe_free(ipv4);
+               return KS_STATUS_GENERR;
+       }
+
+       node = ks_pool_alloc(list->pool, sizeof(*node));
+
+       node->ip = ip;
+       node->mask = mask;
+       node->ok = ok;
+       node->bits = bits;
+       node->str = ks_pstrdup(list->pool, cidr_str);
+
+       if (strchr(cidr_str,':')) {
+               node->family = AF_INET6;
+       } else {
+               node->family = AF_INET;
+       }
+
+       if (!zstr(token)) {
+               node->token = ks_pstrdup(list->pool, token);
+       }
+
+       node->next = list->node_head;
+       list->node_head = node;
+
+       ks_log(KS_LOG_NOTICE, "Adding %s (%s) [%s] to list %s\n",
+                                         cidr_str, ok ? "allow" : "deny", ks_str_nil(token), list->name);
+
+       ks_safe_free(ipv4);
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) ks_network_list_add_cidr_token(ks_network_list_t *list, const char *cidr_str, ks_bool_t ok, const char *token)
+{
+       char *cidr_str_dup = NULL;
+       ks_status_t status = KS_STATUS_SUCCESS;
+
+       if (strchr(cidr_str, ',')) {
+               char *argv[32] = { 0 };
+               int i, argc;
+               cidr_str_dup = strdup(cidr_str);
+
+               ks_assert(cidr_str_dup);
+               if ((argc = ks_separate_string(cidr_str_dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) {
+                       for (i = 0; i < argc; i++) {
+                               ks_status_t this_status;
+                               if ((this_status = ks_network_list_perform_add_cidr_token(list, argv[i], ok, token)) != KS_STATUS_SUCCESS) {
+                                       status = this_status;
+                               }
+                       }
+               }
+       } else {
+               status = ks_network_list_perform_add_cidr_token(list, cidr_str, ok, token);
+       }
+
+       ks_safe_free(cidr_str_dup);
+       return status;
+}
+
+KS_DECLARE(ks_status_t) ks_network_list_add_host_mask(ks_network_list_t *list, const char *host, const char *mask_str, ks_bool_t ok)
+{
+       ks_ip_t ip, mask;
+       ks_network_node_t *node;
+
+       ks_inet_pton(AF_INET, host, &ip);
+       ks_inet_pton(AF_INET, mask_str, &mask);
+
+       node = ks_pool_alloc(list->pool, sizeof(*node));
+
+       node->ip.v4 = ntohl(ip.v4);
+       node->mask.v4 = ntohl(mask.v4);
+       node->ok = ok;
+
+       /* http://graphics.stanford.edu/~seander/bithacks.html */
+       mask.v4 = mask.v4 - ((mask.v4 >> 1) & 0x55555555);
+       mask.v4 = (mask.v4 & 0x33333333) + ((mask.v4 >> 2) & 0x33333333);
+       node->bits = (((mask.v4 + (mask.v4 >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+
+       node->str = ks_psprintf(list->pool, "%s:%s", host, mask_str);
+
+       node->next = list->node_head;
+       list->node_head = node;
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_bool_t) ks_check_network_list_ip_cidr(const char *ip_str, const char *cidr_str)
+{
+       ks_ip_t  ip, mask, net;
+       uint32_t bits;
+       char *ipv6 = strchr(ip_str,':');
+       ks_bool_t ok = KS_FALSE;
+       char *ipv4 = NULL;
+
+       if ((ipv4 = ks_network_ipv4_mapped_ipv6_addr(ip_str))) {
+               ip_str = ipv4;
+               ipv6 = NULL;
+       }
+
+       if (ipv6) {
+               ks_inet_pton(AF_INET6, ip_str, &ip);
+       } else {
+               ks_inet_pton(AF_INET, ip_str, &ip);
+               ip.v4 = htonl(ip.v4);
+       }
+
+       ks_parse_cidr(cidr_str, &net, &mask, &bits);
+       
+       if (ipv6) {
+               ok = ks_testv6_subnet(ip, net, mask);
+       } else {
+               ok = ks_test_subnet(ip.v4, net.v4, mask.v4);
+       }
+
+       ks_safe_free(ipv4);
+
+       return ok;
+}
+
+KS_DECLARE(ks_bool_t) ks_check_network_list_ip_token(const char *ip_str, ks_network_list_t *list, const char **token)
+{
+       ks_ip_t ip;
+       char *ipv6 = strchr(ip_str,':');
+       ks_bool_t ok = KS_FALSE;
+       char *ipv4 = NULL;
+
+       if ((ipv4 = ks_network_ipv4_mapped_ipv6_addr(ip_str))) {
+               ip_str = ipv4;
+               ipv6 = NULL;
+       }
+
+       if (ipv6) {
+               ks_inet_pton(AF_INET6, ip_str, &ip);
+       } else {
+               ks_inet_pton(AF_INET, ip_str, &ip);
+               ip.v4 = htonl(ip.v4);
+       }
+
+       
+       if (ipv6) {
+               ok = ks_network_list_validate_ip6_token(list, ip, token);
+       } else {
+               ok = ks_network_list_validate_ip_token(list, ip.v4, token);
+       }
+
+       ks_safe_free(ipv4);
+
+       return ok;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
index a2a95032340c45b7fd0d133c011965c4f1fa1d67..8b18ea0cbbcc2d54c0dacbbc0db36f8c2047a9e5 100644 (file)
@@ -2182,6 +2182,19 @@ KS_DECLARE(char *) ks_pstrcat(ks_pool_t *pool, ...)
     return result;
 }
 
+KS_DECLARE(char *) ks_psprintf(ks_pool_t *pool, const char *fmt, ...)
+{
+       va_list ap;
+       char *result;
+       va_start(ap, fmt);
+       result = ks_vpprintf(pool, fmt, ap);
+       va_end(ap);
+
+       return result;
+}
+
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c
index 039398f8fe0c5319b594037415e07c2ac40af686..8ac3054cc6405c0ecd45f885943185107ebf595d 100644 (file)
@@ -33,6 +33,8 @@
 
 #include <ks.h>
 
+#define ESCAPE_META '\\'
+
 /* Written by Marc Espie, public domain */
 #define KS_CTYPE_NUM_CHARS       256
 
@@ -230,7 +232,87 @@ KS_DECLARE(int) ks_snprintf(char *buffer, size_t count, const char *fmt, ...)
 }
 
 
-KS_DECLARE(unsigned int) ks_separate_string(char *buf, const char *delim, char **array, unsigned int arraylen)
+/* Helper function used when separating strings to unescape a character. The
+   supported characters are:
+
+   \n  linefeed
+   \r  carriage return
+   \t  tab
+   \s  space
+
+   Any other character is returned as it was received. */
+static char unescape_char(char escaped)
+{
+       char unescaped;
+
+       switch (escaped) {
+       case 'n':
+               unescaped = '\n';
+               break;
+       case 'r':
+               unescaped = '\r';
+               break;
+       case 't':
+               unescaped = '\t';
+               break;
+       case 's':
+               unescaped = ' ';
+               break;
+       default:
+               unescaped = escaped;
+       }
+       return unescaped;
+}
+
+
+/* Helper function used when separating strings to remove quotes, leading /
+   trailing spaces, and to convert escaped characters. */
+static char *cleanup_separated_string(char *str, char delim)
+{
+       char *ptr;
+       char *dest;
+       char *start;
+       char *end = NULL;
+       int inside_quotes = 0;
+
+       /* Skip initial whitespace */
+       for (ptr = str; *ptr == ' '; ++ptr) {
+       }
+
+       for (start = dest = ptr; *ptr; ++ptr) {
+               char e;
+               int esc = 0;
+
+               if (*ptr == ESCAPE_META) {
+                       e = *(ptr + 1);
+                       if (e == '\'' || e == '"' || (delim && e == delim) || e == ESCAPE_META || (e = unescape_char(*(ptr + 1))) != *(ptr + 1)) {
+                               ++ptr;
+                               *dest++ = e;
+                               end = dest;
+                               esc++;
+                       }
+               }
+               if (!esc) {
+                       if (*ptr == '\'' && (inside_quotes || ((ptr+1) && strchr(ptr+1, '\'')))) {
+                               if ((inside_quotes = (1 - inside_quotes))) {
+                                       end = dest;
+                               }
+                       } else {
+                               *dest++ = *ptr;
+                               if (*ptr != ' ' || inside_quotes) {
+                                       end = dest;
+                               }
+                       }
+               }
+       }
+       if (end) {
+               *end = '\0';
+       }
+
+       return start;
+}
+
+KS_DECLARE(unsigned int) ks_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen)
 {
        unsigned int count = 0;
        char *d;
@@ -273,3 +355,129 @@ KS_DECLARE(char *) ks_copy_string(char *from_str, const char *to_str, ks_size_t
 
        return p;
 }
+
+
+/* Separate a string using a delimiter that is not a space */
+static unsigned int separate_string_char_delim(char *buf, char delim, char **array, unsigned int arraylen)
+{
+       enum tokenizer_state {
+               START,
+               FIND_DELIM
+       } state = START;
+
+       unsigned int count = 0;
+       char *ptr = buf;
+       int inside_quotes = 0;
+       unsigned int i;
+
+       while (*ptr && count < arraylen) {
+               switch (state) {
+               case START:
+                       array[count++] = ptr;
+                       state = FIND_DELIM;
+                       break;
+
+               case FIND_DELIM:
+                       /* escaped characters are copied verbatim to the destination string */
+                       if (*ptr == ESCAPE_META) {
+                               ++ptr;
+                       } else if (*ptr == '\'' && (inside_quotes || ((ptr+1) && strchr(ptr+1, '\'')))) {
+                               inside_quotes = (1 - inside_quotes);
+                       } else if (*ptr == delim && !inside_quotes) {
+                               *ptr = '\0';
+                               state = START;
+                       }
+                       ++ptr;
+                       break;
+               }
+       }
+       /* strip quotes, escaped chars and leading / trailing spaces */
+
+       for (i = 0; i < count; ++i) {
+               array[i] = cleanup_separated_string(array[i], delim);
+       }
+
+       return count;
+}
+
+/* Separate a string using a delimiter that is a space */
+static unsigned int separate_string_blank_delim(char *buf, char **array, unsigned int arraylen)
+{
+       enum tokenizer_state {
+               START,
+               SKIP_INITIAL_SPACE,
+               FIND_DELIM,
+               SKIP_ENDING_SPACE
+       } state = START;
+
+       unsigned int count = 0;
+       char *ptr = buf;
+       int inside_quotes = 0;
+       unsigned int i;
+
+       while (*ptr && count < arraylen) {
+               switch (state) {
+               case START:
+                       array[count++] = ptr;
+                       state = SKIP_INITIAL_SPACE;
+                       break;
+
+               case SKIP_INITIAL_SPACE:
+                       if (*ptr == ' ') {
+                               ++ptr;
+                       } else {
+                               state = FIND_DELIM;
+                       }
+                       break;
+
+               case FIND_DELIM:
+                       if (*ptr == ESCAPE_META) {
+                               ++ptr;
+                       } else if (*ptr == '\'') {
+                               inside_quotes = (1 - inside_quotes);
+                       } else if (*ptr == ' ' && !inside_quotes) {
+                               *ptr = '\0';
+                               state = SKIP_ENDING_SPACE;
+                       }
+                       ++ptr;
+                       break;
+
+               case SKIP_ENDING_SPACE:
+                       if (*ptr == ' ') {
+                               ++ptr;
+                       } else {
+                               state = START;
+                       }
+                       break;
+               }
+       }
+       /* strip quotes, escaped chars and leading / trailing spaces */
+
+       for (i = 0; i < count; ++i) {
+               array[i] = cleanup_separated_string(array[i], 0);
+       }
+       
+       return count;
+}
+
+KS_DECLARE(unsigned int) ks_separate_string(char *buf, char delim, char **array, unsigned int arraylen)
+{
+       if (!buf || !array || !arraylen) {
+               return 0;
+       }
+
+
+       if (*buf == '^' && *(buf+1) == '^') {
+               char *p = buf + 2;
+               
+               if (p && *p && *(p+1)) {
+                       buf = p;
+                       delim = *buf++;
+               }
+       }
+
+
+       memset(array, 0, arraylen * sizeof(*array));
+
+       return (delim == ' ' ? separate_string_blank_delim(buf, array, arraylen) : separate_string_char_delim(buf, delim, array, arraylen));
+}
index bd8ce48325aa54955fe76f3a03a905dcf10821f8..a974af0062649a1120808d0b681bf9d048e9d570 100644 (file)
@@ -14,6 +14,11 @@ testpools_SOURCES = testpools.c tap.c
 testpools_CFLAGS = $(AM_CFLAGS)
 testpools_LDADD = $(TEST_LDADD)
 
+check_PROGRAMS += testacl
+testacl_SOURCES = testacl.c tap.c
+testacl_CFLAGS = $(AM_CFLAGS)
+testacl_LDADD = $(TEST_LDADD)
+
 check_PROGRAMS += test_thread_pools
 test_thread_pools_SOURCES = test_thread_pools.c tap.c
 test_thread_pools_CFLAGS = $(AM_CFLAGS)
diff --git a/libs/libks/test/testacl.c b/libs/libks/test/testacl.c
new file mode 100644 (file)
index 0000000..090b62f
--- /dev/null
@@ -0,0 +1,70 @@
+#include "ks.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "tap.h"
+
+int main(int argc, char **argv)
+{
+       ks_pool_t *pool;
+       ks_network_list_t *list = NULL;
+       ks_bool_t match;
+
+       ks_init();
+
+       plan(8);
+
+       ks_pool_open(&pool);
+
+       ks_network_list_create(&list, "test", KS_FALSE, pool);
+
+       
+       ks_network_list_add_cidr(list, "10.0.0.0/8", KS_TRUE);
+       ks_network_list_add_cidr(list, "172.16.0.0/12", KS_TRUE);
+       ks_network_list_add_cidr(list, "192.168.0.0/16", KS_TRUE);
+       ks_network_list_add_cidr(list, "fe80::/10", KS_TRUE);
+
+
+       match = ks_check_network_list_ip("192.168.1.1", list);
+       ok(match);
+
+       match = ks_check_network_list_ip("208.34.128.7", list);
+       ok (!match);
+
+       match = ks_check_network_list_ip_cidr("192.168.1.1", "192.168.0.0/16");
+       ok(match);
+
+       match = ks_check_network_list_ip_cidr("208.34.128.7", "192.168.0.0/16");
+       ok (!match);
+
+
+       ks_pool_free(pool, &list);
+
+
+       ks_network_list_create(&list, "test", KS_TRUE, pool);
+
+       ks_network_list_add_cidr(list, "0.0.0.0/0", KS_FALSE);
+       ks_network_list_add_cidr(list, "fe80::/10", KS_FALSE);
+
+       
+       match = ks_check_network_list_ip("2637:f368:1281::10", list);
+       ok(match);
+
+       match = ks_check_network_list_ip("fe80::18b7:53b3:51d8:f5cf", list);
+       ok(!match);
+
+       match = ks_check_network_list_ip_cidr("fe80::18b7:53b3:51d8:f5cf", "fe80::/10");
+       ok(match);
+
+       match = ks_check_network_list_ip_cidr("2637:f368:1281::10", "fe80::/10");
+       ok(!match);
+
+       ks_pool_free(pool, &list);
+
+       ks_pool_close(&pool);
+
+       ks_shutdown();
+
+       done_testing();
+}