diff --git a/libs/libks/Makefile.am b/libs/libks/Makefile.am index 44abb688e3..f49cb238d2 100644 --- a/libs/libks/Makefile.am +++ b/libs/libks/Makefile.am @@ -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 diff --git a/libs/libks/src/include/ks.h b/libs/libks/src/include/ks.h index 382780d407..b19f62e463 100644 --- a/libs/libks/src/include/ks.h +++ b/libs/libks/src/include/ks.h @@ -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 index 0000000000..c75612f77c --- /dev/null +++ b/libs/libks/src/include/ks_acl.h @@ -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: + */ + diff --git a/libs/libks/src/include/ks_pool.h b/libs/libks/src/include/ks_pool.h index 57dc5a725c..9d0ff0fadf 100644 --- a/libs/libks/src/include/ks_pool.h +++ b/libs/libks/src/include/ks_pool.h @@ -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 diff --git a/libs/libks/src/include/ks_types.h b/libs/libks/src/include/ks_types.h index 8c088bdd40..9e1cba61c0 100644 --- a/libs/libks/src/include/ks_types.h +++ b/libs/libks/src/include/ks_types.h @@ -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 index 0000000000..2dadec3939 --- /dev/null +++ b/libs/libks/src/ks_acl.c @@ -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 + + +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: + */ diff --git a/libs/libks/src/ks_pool.c b/libs/libks/src/ks_pool.c index a2a9503234..8b18ea0cbb 100644 --- a/libs/libks/src/ks_pool.c +++ b/libs/libks/src/ks_pool.c @@ -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 diff --git a/libs/libks/src/ks_string.c b/libs/libks/src/ks_string.c index 039398f8fe..8ac3054cc6 100644 --- a/libs/libks/src/ks_string.c +++ b/libs/libks/src/ks_string.c @@ -33,6 +33,8 @@ #include +#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)); +} diff --git a/libs/libks/test/Makefile.am b/libs/libks/test/Makefile.am index bd8ce48325..a974af0062 100644 --- a/libs/libks/test/Makefile.am +++ b/libs/libks/test/Makefile.am @@ -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 index 0000000000..090b62f0c6 --- /dev/null +++ b/libs/libks/test/testacl.c @@ -0,0 +1,70 @@ +#include "ks.h" + +#include +#include +#include +#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(); +}