diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index 3496533..8f117fd 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -4,12 +4,12 @@ # IPV4: :53 # IPV6 [::]:53 -bind [::]:535 +bind [::]:53 # dns cache size # cache-size [number] # 0: for no cache -cache-size 1024 +cache-size 512 # set log level # loglevel [level], level=error, warn, info, debug diff --git a/src/conf.c b/src/conf.c index d537dbb..0d55f64 100644 --- a/src/conf.c +++ b/src/conf.c @@ -97,6 +97,7 @@ int config_address(char *value) goto errout; } + memset(address, 0, sizeof(*address)); len = end - begin; memcpy(address->domain, begin, len); address->domain[len] = 0; diff --git a/src/dns_cache.c b/src/dns_cache.c index ef9c8cb..cf21bce 100644 --- a/src/dns_cache.c +++ b/src/dns_cache.c @@ -37,6 +37,7 @@ void _dns_cache_delete(struct dns_cache *dns_cache) { hash_del(&dns_cache->node); list_del_init(&dns_cache->list); + dns_cache_head.num--; free(dns_cache); } @@ -92,12 +93,12 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, unsigned char *add pthread_mutex_lock(&dns_cache_head.lock); hash_add(dns_cache_head.cache_hash, &dns_cache->node, key); - list_add(&dns_cache->list, &dns_cache_head.cache_list); + list_add_tail(&dns_cache->list, &dns_cache_head.cache_list); dns_cache_head.num++; if (dns_cache_head.num > dns_cache_head.size) { struct dns_cache *del_cache; - del_cache = _dns_cache_last(); + del_cache = _dns_cache_first(); dns_cache_release(del_cache); } pthread_mutex_unlock(&dns_cache_head.lock); @@ -181,8 +182,37 @@ void dns_cache_delete(struct dns_cache *dns_cache) void dns_cache_update(struct dns_cache *dns_cache) { pthread_mutex_lock(&dns_cache_head.lock); - list_del_init(&dns_cache->list); - list_add(&dns_cache->list, &dns_cache_head.cache_list); + if (!list_empty(&dns_cache->list)) { + list_del_init(&dns_cache->list); + list_add_tail(&dns_cache->list, &dns_cache_head.cache_list); + } + pthread_mutex_unlock(&dns_cache_head.lock); +} + +void dns_cache_invalidate(void) +{ + struct dns_cache *dns_cache = NULL; + struct dns_cache *tmp; + time_t now; + int ttl = 0; + + if (dns_cache_head.size <= 0) { + return; + } + + time(&now); + pthread_mutex_lock(&dns_cache_head.lock); + list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list) + { + ttl = dns_cache->insert_time + dns_cache->ttl - now; + if (ttl > 0) { + break; + } + + hash_del(&dns_cache->node); + list_del_init(&dns_cache->list); + dns_cache_release(dns_cache); + } pthread_mutex_unlock(&dns_cache_head.lock); } diff --git a/src/dns_cache.h b/src/dns_cache.h index 00d4980..c9ceb64 100644 --- a/src/dns_cache.h +++ b/src/dns_cache.h @@ -34,6 +34,8 @@ void dns_cache_release(struct dns_cache *dns_cache); void dns_cache_update(struct dns_cache *dns_cache); +void dns_cache_invalidate(void); + int dns_cache_get_ttl(struct dns_cache *dns_cache); void dns_cache_destroy(void); diff --git a/src/dns_server.c b/src/dns_server.c index a6b4d55..6080e70 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -680,28 +680,8 @@ errout: return -1; } -int _dns_server_art_iter_callback(void *data, const unsigned char *key, uint32_t key_len, void *value) -{ - struct dns_address **address; - address = data; - *address = value; - return 0; -} - -static int _dns_server_art_domain_cmp(const art_leaf *n, const unsigned char *prefix, int prefix_len) -{ - // Fail if the prefix length is too short - if (n->key_len > (uint32_t)prefix_len) { - return 1; - } - - // Compare the keys - return memcmp(n->key, prefix, n->key_len); -} - static struct dns_address *_dns_server_get_address_by_domain(char *domain, int qtype) { - struct dns_address *address = NULL; int domain_len; char domain_key[DNS_MAX_CNAME_LEN]; char type = '4'; @@ -721,11 +701,8 @@ static struct dns_address *_dns_server_get_address_by_domain(char *domain, int q reverse_string(domain_key + 1, domain, domain_len); domain_key[0] = type; domain_len++; - if (art_iter_cmp(&dns_conf_address, (unsigned char *)domain_key, domain_len, _dns_server_art_iter_callback, _dns_server_art_domain_cmp, &address) != 0) { - return NULL; - } - return address; + return art_substring(&dns_conf_address, (unsigned char *)domain_key, domain_len);; } static int _dns_server_process_address(struct dns_request *request, struct dns_packet *packet) @@ -796,6 +773,7 @@ static int _dns_server_process_cache(struct dns_request *request, struct dns_pac request->rcode = DNS_RC_NOERROR; _dns_reply(request); + dns_cache_update(dns_cache); dns_cache_release(dns_cache); return 0; @@ -972,11 +950,27 @@ void _dns_server_tcp_ping_check(struct dns_request *request) request->has_ping_tcp = 1; } +void _dns_server_period_run_second(void) +{ + static unsigned int sec = 0; + sec++; + + if (sec % 2 == 0) { + dns_cache_invalidate(); + } +} + void _dns_server_period_run(void) { struct dns_request *request, *tmp; + static unsigned int msec = 0; LIST_HEAD(check_list); + msec++; + if (msec % 10 == 0) { + _dns_server_period_run_second(); + } + unsigned long now = get_tick_count(); pthread_mutex_lock(&server.request_list_lock); @@ -1153,7 +1147,7 @@ int dns_server_init(void) return -1; } - if (dns_cache_init(1024) != 0) { + if (dns_cache_init(dns_conf_cachesize) != 0) { tlog(TLOG_ERROR, "init cache failed."); return -1; } @@ -1229,7 +1223,7 @@ void dns_server_exit(void) list_for_each_entry_safe(request, tmp, &remove_list, check_list) { - _dns_server_request_release(request); + _dns_server_request_remove(request); } pthread_mutex_destroy(&server.request_list_lock); diff --git a/src/include/art.h b/src/include/art.h index 376af20..8f40a70 100644 --- a/src/include/art.h +++ b/src/include/art.h @@ -185,6 +185,16 @@ void* art_delete(art_tree *t, const unsigned char *key, int key_len); */ void* art_search(const art_tree *t, const unsigned char *key, int key_len); +/** + * Searches substring for a value in the ART tree + * @arg t The tree + * @arg str The key + * @arg str_len The length of the key + * @return NULL if the item was not found, otherwise + * the value pointer is returned. + */ +void *art_substring(const art_tree *t, const unsigned char *str, int str_len); + /** * Returns the minimum valued leaf * @return The minimum leaf or NULL @@ -223,21 +233,6 @@ int art_iter(art_tree *t, art_callback cb, void *data); */ int art_iter_prefix(art_tree *t, const unsigned char *prefix, int prefix_len, art_callback cb, void *data); -/** - * Iterates through the entries pairs in the map, - * invoking a callback for each that matches a given prefix. - * The call back gets a key, value for each and returns an integer stop value. - * If the callback returns non-zero, then the iteration stops. - * @arg t The tree to iterate over - * @arg prefix The prefix of keys to read - * @arg prefix_len The length of the prefix - * @arg cb The callback function to invoke - * @arg data Opaque handle passed to the callback - * @return 0 on success, or the return of the callback. - */ -typedef int(*art_key_cmp_callback)(const art_leaf *n, const unsigned char *prefix, int prefix_len); -int art_iter_cmp(art_tree *t, const unsigned char *str, int str_len, art_callback cb, art_key_cmp_callback key_cmp, void *data); - #ifdef __cplusplus } #endif diff --git a/src/lib/art.c b/src/lib/art.c index 9a4684d..7ac67e2 100644 --- a/src/lib/art.c +++ b/src/lib/art.c @@ -912,17 +912,46 @@ int art_iter(art_tree *t, art_callback cb, void *data) { return recursive_iter(t->root, cb, data); } -int art_iter_cmp(art_tree *t, const unsigned char *key, int key_len, art_callback cb, art_key_cmp_callback key_cmp, void *data) -{ +/** + * Checks if a leaf prefix matches + * @return 0 on success. + */ +static int leaf_prefix_matches(const art_leaf *n, const unsigned char *prefix, int prefix_len) { + // Fail if the key length is too short + if (n->key_len < (uint32_t)prefix_len) return 1; + + // Compare the keys + return memcmp(n->key, prefix, prefix_len); +} + +/** + * Iterates through the entries pairs in the map, + * invoking a callback for each that matches a given prefix. + * The call back gets a key, value for each and returns an integer stop value. + * If the callback returns non-zero, then the iteration stops. + * @arg t The tree to iterate over + * @arg prefix The prefix of keys to read + * @arg prefix_len The length of the prefix + * @arg cb The callback function to invoke + * @arg data Opaque handle passed to the callback + * @return 0 on success, or the return of the callback. + */ +int art_iter_prefix(art_tree *t, const unsigned char *key, int key_len, art_callback cb, void *data) { art_node **child; art_node *n = t->root; int prefix_len, depth = 0; while (n) { + + if (IS_LEAF(n)) { + n = (art_node*)LEAF_RAW(n); + art_leaf *l = (art_leaf*)n; + printf("LEAF: %s\n", l->key); + } // Might be a leaf if (IS_LEAF(n)) { n = (art_node*)LEAF_RAW(n); // Check if the expanded path matches - if (!key_cmp((art_leaf*)n, key, key_len)) { + if (!leaf_prefix_matches((art_leaf*)n, key, key_len)) { art_leaf *l = (art_leaf*)n; return cb(data, (const unsigned char*)l->key, l->key_len, l->value); } @@ -932,7 +961,7 @@ int art_iter_cmp(art_tree *t, const unsigned char *key, int key_len, art_callbac // If the depth matches the prefix, we need to handle this node if (depth == key_len) { art_leaf *l = minimum(n); - if (!key_cmp(l, key, key_len)) + if (!leaf_prefix_matches(l, key, key_len)) return recursive_iter(n, cb, data); return 0; } @@ -967,30 +996,54 @@ int art_iter_cmp(art_tree *t, const unsigned char *key, int key_len, art_callbac return 0; } -/** - * Checks if a leaf prefix matches - * @return 0 on success. - */ -static int leaf_prefix_matches(const art_leaf *n, const unsigned char *prefix, int prefix_len) { +static int str_prefix_matches(const art_leaf *n, const unsigned char *str, int str_len) { // Fail if the key length is too short - if (n->key_len < (uint32_t)prefix_len) return 1; + if (n->key_len > (uint32_t)str_len) return 1; // Compare the keys - return memcmp(n->key, prefix, prefix_len); + return memcmp(str, n->key, n->key_len); } -/** - * Iterates through the entries pairs in the map, - * invoking a callback for each that matches a given prefix. - * The call back gets a key, value for each and returns an integer stop value. - * If the callback returns non-zero, then the iteration stops. - * @arg t The tree to iterate over - * @arg prefix The prefix of keys to read - * @arg prefix_len The length of the prefix - * @arg cb The callback function to invoke - * @arg data Opaque handle passed to the callback - * @return 0 on success, or the return of the callback. - */ -int art_iter_prefix(art_tree *t, const unsigned char *key, int key_len, art_callback cb, void *data) { - return art_iter_cmp(t, key, key_len, cb, leaf_prefix_matches, data); +void *art_substring(const art_tree *t, const unsigned char *str, int str_len) +{ + art_node **child; + art_node *n = t->root; + art_leaf *found = NULL; + + int prefix_len, depth = 0; + while (n) { + // Might be a leaf + if (IS_LEAF(n)) { + n = (art_node*)LEAF_RAW(n); + // Check if the expanded path matches + if (!str_prefix_matches((art_leaf*)n, str, str_len)) { + found = (art_leaf*)n; + } + break; + } + + // Bail if the prefix does not match + if (n->partial_len) { + prefix_len = check_prefix(n, str, str_len, depth); + if (prefix_len != min(MAX_PREFIX_LEN, n->partial_len)) + break; + depth = depth + n->partial_len; + } + + art_leaf *l = maximum(n); + if (!str_prefix_matches(l, str, str_len)) { + found = l; + } + + // Recursively search + child = find_child(n, str[depth]); + n = (child) ? *child : NULL; + depth++; + } + + if (found == NULL) { + return NULL; + } + + return found->value; } \ No newline at end of file