diff --git a/ReadMe.md b/ReadMe.md index 9b464bf1c4..5b8d58c7df 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -79,6 +79,9 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms 1. **多 DNS 上游服务器** 支持配置多个上游 DNS 服务器,并同时进行查询,即使其中有 DNS 服务器异常,也不会影响查询。 +1. **支持每个客户端独立控制** + 支持基于MAC,IP地址控制客户端使用不同查询规则,可实现家长控制等功能。 + 1. **返回最快 IP 地址** 支持从域名所属 IP 地址列表中查找到访问速度最快的 IP 地址,并返回给客户端,提高网络访问速度。 diff --git a/ReadMe_en.md b/ReadMe_en.md index d5fb25cd87..6f99c69793 100644 --- a/ReadMe_en.md +++ b/ReadMe_en.md @@ -78,6 +78,9 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co 1. **Multiple upstream DNS servers** Support configuring multiple upstream DNS servers and query at the same time.the query will not be affected, Even if there is a DNS server exception. +1. **Support per-client query control** + Support controlling clients using different query rules based on MAC and IP addresses, enabling features such as parental control. + 1. **Return the fastest IP address** Supports finding the fastest access IP address from the IP address list of the domain name and returning it to the client to avoid DNS pollution and improve network access speed. diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index f9c8a8b02a..f446c035d8 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -385,10 +385,10 @@ log-level info # ip-alias ip-set:ip-list ip-set:ip-map-list # set client rules -# client-rules ip-cidr [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection] +# client-rules [ip-cidr|mac|ip-set] [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection] # client-rules option is same as bind option, please see bind option for detail. # set group rules # group-begin [group-name] -# group-match [-g|group group-name] [-domain domain] [-client-ip client] +# group-match [-g|group group-name] [-domain domain] [-client-ip [ip-cidr|mac|ip-set]] # group-end diff --git a/src/dns_conf.c b/src/dns_conf.c index d2e8595f82..64b32fa8a3 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -3329,6 +3329,51 @@ static int _config_client_rules_free(struct dns_client_rules *client_rules) return 0; } +static struct client_roue_group_mac *_config_client_rule_group_mac_new(uint8_t mac[6]) +{ + struct client_roue_group_mac *group_mac = NULL; + uint32_t key; + + group_mac = malloc(sizeof(*group_mac)); + if (group_mac == NULL) { + return NULL; + } + memset(group_mac, 0, sizeof(*group_mac)); + memcpy(group_mac->mac, mac, 6); + + key = jhash(mac, 6, 0); + hash_add(dns_conf_client_rule.mac, &group_mac->node, key); + dns_conf_client_rule.mac_num++; + + return group_mac; +} + +struct client_roue_group_mac *dns_server_rule_group_mac_get(const uint8_t mac[6]) +{ + struct client_roue_group_mac *group_mac = NULL; + uint32_t key; + + key = jhash(mac, 6, 0); + hash_for_each_possible(dns_conf_client_rule.mac, group_mac, node, key) + { + if (memcmp(group_mac->mac, mac, 6) == 0) { + return group_mac; + } + } + + return NULL; +} + +static struct client_roue_group_mac *_config_client_rule_group_mac_get_or_add(uint8_t mac[6]) +{ + struct client_roue_group_mac *group_mac = dns_server_rule_group_mac_get(mac); + if (group_mac == NULL) { + group_mac = _config_client_rule_group_mac_new(mac); + } + + return group_mac; +} + static int _config_client_rule_flag_callback(const char *ip_cidr, void *priv) { struct dns_set_rule_flags_callback_args *args = (struct dns_set_rule_flags_callback_args *)priv; @@ -3340,23 +3385,38 @@ static int _config_client_rule_flag_set(const char *ip_cidr, unsigned int flag, struct dns_client_rules *client_rules = NULL; struct dns_client_rules *add_client_rules = NULL; struct client_rule_flags *client_rule_flags = NULL; + struct client_roue_group_mac *group_mac = NULL; radix_node_t *node = NULL; + uint8_t mac[6]; + int is_mac_address = 0; + + is_mac_address = parser_mac_address(ip_cidr, mac); + if (is_mac_address == 0) { + group_mac = _config_client_rule_group_mac_get_or_add(mac); + if (group_mac == NULL) { + tlog(TLOG_ERROR, "get or add mac %s failed", ip_cidr); + goto errout; + } - if (strncmp(ip_cidr, "ip-set:", sizeof("ip-set:") - 1) == 0) { - struct dns_set_rule_flags_callback_args args; - args.flags = flag; - args.is_clear_flag = is_clear; - return _config_ip_rule_set_each(ip_cidr + sizeof("ip-set:") - 1, _config_client_rule_flag_callback, &args); - } + client_rules = group_mac->rules; + } else { + if (strncmp(ip_cidr, "ip-set:", sizeof("ip-set:") - 1) == 0) { + struct dns_set_rule_flags_callback_args args; + args.flags = flag; + args.is_clear_flag = is_clear; + return _config_ip_rule_set_each(ip_cidr + sizeof("ip-set:") - 1, _config_client_rule_flag_callback, &args); + } - /* Get existing or create domain rule */ - node = _create_client_rules_node(ip_cidr); - if (node == NULL) { - tlog(TLOG_ERROR, "create addr node failed."); - goto errout; + /* Get existing or create domain rule */ + node = _create_client_rules_node(ip_cidr); + if (node == NULL) { + tlog(TLOG_ERROR, "create addr node failed."); + goto errout; + } + + client_rules = node->data; } - client_rules = node->data; if (client_rules == NULL) { add_client_rules = malloc(sizeof(*add_client_rules)); if (add_client_rules == NULL) { @@ -3364,7 +3424,11 @@ static int _config_client_rule_flag_set(const char *ip_cidr, unsigned int flag, } memset(add_client_rules, 0, sizeof(*add_client_rules)); client_rules = add_client_rules; - node->data = client_rules; + if (is_mac_address == 0) { + group_mac->rules = client_rules; + } else { + node->data = client_rules; + } } /* add new rule to domain */ @@ -3390,7 +3454,7 @@ static int _config_client_rule_flag_set(const char *ip_cidr, unsigned int flag, tlog(TLOG_ERROR, "set ip %s flags failed", ip_cidr); - return 0; + return -1; } static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, void *rule); @@ -3404,6 +3468,7 @@ static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, v { struct dns_client_rules *client_rules = NULL; struct dns_client_rules *add_client_rules = NULL; + struct client_roue_group_mac *group_mac = NULL; radix_node_t *node = NULL; if (ip_cidr == NULL) { @@ -3414,21 +3479,36 @@ static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, v goto errout; } - if (strncmp(ip_cidr, "ip-set:", sizeof("ip-set:") - 1) == 0) { - struct dns_set_rule_add_callback_args args; - args.type = type; - args.rule = rule; - return _config_ip_rule_set_each(ip_cidr + sizeof("ip-set:") - 1, _config_client_rule_add_callback, &args); - } + uint8_t mac[6]; + int is_mac_address = 0; - /* Get existing or create domain rule */ - node = _create_client_rules_node(ip_cidr); - if (node == NULL) { - tlog(TLOG_ERROR, "create addr node failed."); - goto errout; + is_mac_address = parser_mac_address(ip_cidr, mac); + if (is_mac_address == 0) { + group_mac = _config_client_rule_group_mac_get_or_add(mac); + if (group_mac == NULL) { + tlog(TLOG_ERROR, "get or add mac %s failed", ip_cidr); + goto errout; + } + + client_rules = group_mac->rules; + } else { + if (strncmp(ip_cidr, "ip-set:", sizeof("ip-set:") - 1) == 0) { + struct dns_set_rule_add_callback_args args; + args.type = type; + args.rule = rule; + return _config_ip_rule_set_each(ip_cidr + sizeof("ip-set:") - 1, _config_client_rule_add_callback, &args); + } + + /* Get existing or create domain rule */ + node = _create_client_rules_node(ip_cidr); + if (node == NULL) { + tlog(TLOG_ERROR, "create addr node failed."); + goto errout; + } + + client_rules = node->data; } - client_rules = node->data; if (client_rules == NULL) { add_client_rules = malloc(sizeof(*add_client_rules)); if (add_client_rules == NULL) { @@ -3436,7 +3516,11 @@ static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, v } memset(add_client_rules, 0, sizeof(*add_client_rules)); client_rules = add_client_rules; - node->data = client_rules; + if (is_mac_address == 0) { + group_mac->rules = client_rules; + } else { + node->data = client_rules; + } } /* add new rule to domain */ @@ -5656,7 +5740,7 @@ static int _dns_server_load_conf_init(void) tlog(TLOG_WARN, "init client rule radix tree failed."); return -1; } - + hash_init(dns_conf_client_rule.mac); hash_init(dns_conf_rule.group); dns_conf_rule.default_conf = _config_rule_group_new(""); if (dns_conf_rule.default_conf == NULL) { @@ -5707,9 +5791,24 @@ static void dns_server_bind_destroy(void) dns_conf_bind_ip_num = 0; } +static void _config_client_rule_destroy_mac(void) +{ + struct hlist_node *tmp = NULL; + unsigned int i; + struct client_roue_group_mac *group_mac = NULL; + + hash_for_each_safe(dns_conf_client_rule.mac, i, tmp, group_mac, node) + { + hlist_del_init(&group_mac->node); + _config_client_rules_free(group_mac->rules); + free(group_mac); + } +} + static void _config_client_rule_destroy(void) { Destroy_Radix(dns_conf_client_rule.rule, _config_client_rule_iter_free_cb, NULL); + _config_client_rule_destroy_mac(); } void dns_server_load_exit(void) diff --git a/src/dns_conf.h b/src/dns_conf.h index 767e432afb..46db8088ec 100644 --- a/src/dns_conf.h +++ b/src/dns_conf.h @@ -458,8 +458,16 @@ struct dns_client_rules { struct dns_client_rule *rules[CLIENT_RULE_MAX]; }; +struct client_roue_group_mac { + struct hlist_node node; + uint8_t mac[6]; + struct dns_client_rules *rules; +}; + struct dns_conf_client_rule { radix_tree_t *rule; + DECLARE_HASHTABLE(mac, 6); + int mac_num; }; struct nftset_ipset_rules { @@ -690,6 +698,8 @@ struct dns_conf_group *dns_server_get_rule_group(const char *group_name); struct dns_conf_group *dns_server_get_default_rule_group(void); +struct client_roue_group_mac *dns_server_rule_group_mac_get(const uint8_t mac[6]); + extern int config_additional_file(void *data, int argc, char *argv[]); const char *dns_conf_get_cache_dir(void); diff --git a/src/dns_server.c b/src/dns_server.c index 0b8a64a398..cfa4404360 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -74,6 +74,9 @@ #define CACHE_AUTO_ENABLE_SIZE (1024 * 1024 * 128) #define EXPIRED_DOMAIN_PREFETCH_TIME (3600 * 8) #define DNS_MAX_DOMAIN_REFETCH_NUM 64 +#define DNS_SERVER_NEIGHBOR_CACHE_MAX_NUM 8192 +#define DNS_SERVER_NEIGHBOR_CACHE_TIMEOUT (3600 * 1) +#define DNS_SERVER_NEIGHBOR_CACHE_NOMAC_TIMEOUT 60 #define PREFETCH_FLAGS_NO_DUALSTACK (1 << 0) #define PREFETCH_FLAGS_EXPIRED (1 << 1) @@ -109,6 +112,29 @@ struct rule_walk_args { uint32_t key_len[DOMAIN_RULE_MAX]; }; +struct neighbor_enum_args { + uint8_t *netaddr; + int netaddr_len; + struct client_roue_group_mac *group_mac; +}; + +struct neighbor_cache_item { + struct hlist_node node; + struct list_head list; + unsigned char ip_addr[DNS_RR_AAAA_LEN]; + int ip_addr_len; + unsigned char mac[6]; + int has_mac; + time_t last_update_time; +}; + +struct neighbor_cache { + DECLARE_HASHTABLE(cache, 6); + atomic_t cache_num; + struct list_head list; + pthread_mutex_t lock; +}; + struct dns_conn_buf { char buf[DNS_CONN_BUFF_SIZE]; int buffsize; @@ -350,6 +376,8 @@ struct dns_server { DECLARE_HASHTABLE(request_pending, 4); pthread_mutex_t request_pending_lock; + + struct neighbor_cache neighbor_cache; }; static int is_server_init; @@ -3040,11 +3068,188 @@ static int _dns_server_check_speed(struct dns_request *request, char *ip) return -1; } +static void _dns_server_neighbor_cache_free_item(struct neighbor_cache_item *item) +{ + hash_del(&item->node); + list_del_init(&item->list); + free(item); + atomic_dec(&server.neighbor_cache.cache_num); +} + +static void _dns_server_neighbor_cache_free_last_used_item(void) +{ + struct neighbor_cache_item *item = NULL; + + if (atomic_read(&server.neighbor_cache.cache_num) < DNS_SERVER_NEIGHBOR_CACHE_MAX_NUM) { + return; + } + + item = list_last_entry(&server.neighbor_cache.list, struct neighbor_cache_item, list); + if (item == NULL) { + return; + } + + _dns_server_neighbor_cache_free_item(item); +} + +static struct neighbor_cache_item *_dns_server_neighbor_cache_get_item(const uint8_t *net_addr, int net_addr_len) +{ + struct neighbor_cache_item *item = NULL; + uint32_t key = 0; + + key = jhash(net_addr, net_addr_len, 0); + hash_for_each_possible(server.neighbor_cache.cache, item, node, key) + { + if (item->ip_addr_len != net_addr_len) { + continue; + } + + if (memcmp(item->ip_addr, net_addr, net_addr_len) == 0) { + break; + } + } + + return item; +} + +static int _dns_server_neighbor_cache_add(const uint8_t *net_addr, int net_addr_len, const uint8_t *mac) +{ + struct neighbor_cache_item *item = NULL; + uint32_t key = 0; + + if (net_addr_len > DNS_RR_AAAA_LEN) { + return -1; + } + + item = _dns_server_neighbor_cache_get_item(net_addr, net_addr_len); + if (item == NULL) { + item = malloc(sizeof(*item)); + memset(item, 0, sizeof(*item)); + if (item == NULL) { + return -1; + } + INIT_LIST_HEAD(&item->list); + INIT_HLIST_NODE(&item->node); + } + + memcpy(item->ip_addr, net_addr, net_addr_len); + item->ip_addr_len = net_addr_len; + item->last_update_time = time(NULL); + if (mac == NULL) { + item->has_mac = 0; + } else { + memcpy(item->mac, mac, 6); + item->has_mac = 1; + } + key = jhash(net_addr, net_addr_len, 0); + hash_del(&item->node); + hash_add(server.neighbor_cache.cache, &item->node, key); + list_del_init(&item->list); + list_add(&item->list, &server.neighbor_cache.list); + atomic_inc(&server.neighbor_cache.cache_num); + + _dns_server_neighbor_cache_free_last_used_item(); + + return 0; +} + +static int _dns_server_neighbors_callback(const uint8_t *net_addr, int net_addr_len, const uint8_t mac[6], void *arg) +{ + struct neighbor_enum_args *args = arg; + + _dns_server_neighbor_cache_add(net_addr, net_addr_len, mac); + + if (net_addr_len != args->netaddr_len) { + return 0; + } + + if (memcmp(net_addr, args->netaddr, net_addr_len) != 0) { + return 0; + } + + args->group_mac = dns_server_rule_group_mac_get(mac); + + return 1; +} + +static int _dns_server_neighbor_cache_is_valid(struct neighbor_cache_item *item) +{ + if (item == NULL) { + return -1; + } + + time_t now = time(NULL); + + if (item->last_update_time + DNS_SERVER_NEIGHBOR_CACHE_TIMEOUT < now) { + return -1; + } + + if (item->has_mac) { + return 0; + } + + if (item->last_update_time + DNS_SERVER_NEIGHBOR_CACHE_NOMAC_TIMEOUT < now) { + return -1; + } + + return 0; +} + +static struct dns_client_rules *_dns_server_get_client_rules_by_mac(uint8_t *netaddr, int netaddr_len) +{ + struct client_roue_group_mac *group_mac = NULL; + struct neighbor_cache_item *item = NULL; + int family = AF_UNSPEC; + int ret = 0; + struct neighbor_enum_args args; + + if (dns_conf_client_rule.mac_num == 0) { + return NULL; + } + + item = _dns_server_neighbor_cache_get_item(netaddr, netaddr_len); + if (_dns_server_neighbor_cache_is_valid(item) == 0) { + if (item->has_mac) { + return NULL; + } + group_mac = dns_server_rule_group_mac_get(item->mac); + if (group_mac != NULL) { + return group_mac->rules; + } + } + + if (netaddr_len == 4) { + family = AF_INET; + } else if (netaddr_len == 16) { + family = AF_INET6; + } + + args.group_mac = group_mac; + args.netaddr = netaddr; + args.netaddr_len = netaddr_len; + + ret = netlink_get_neighbors(family, _dns_server_neighbors_callback, &args); + if (ret < 0) { + goto add_cache; + } + + if (ret != 1 || args.group_mac == NULL) { + goto add_cache; + } + + return args.group_mac->rules; + +add_cache: + _dns_server_neighbor_cache_add(netaddr, netaddr_len, NULL); + return NULL; +} + static struct dns_client_rules *_dns_server_get_client_rules(struct sockaddr_storage *addr, socklen_t addr_len) { prefix_t prefix; radix_node_t *node = NULL; uint8_t *netaddr = NULL; + struct dns_client_rules *client_rules = NULL; int netaddr_len = 0; switch (addr->ss_family) { @@ -3070,6 +3275,11 @@ static struct dns_client_rules *_dns_server_get_client_rules(struct sockaddr_sto break; } + client_rules = _dns_server_get_client_rules_by_mac(netaddr, netaddr_len); + if (client_rules != NULL) { + return client_rules; + } + if (prefix_from_blob(netaddr, netaddr_len, netaddr_len * 8, &prefix) == NULL) { return NULL; } @@ -3079,7 +3289,9 @@ static struct dns_client_rules *_dns_server_get_client_rules(struct sockaddr_sto return NULL; } - return node->data; + client_rules = node->data; + + return client_rules; } static struct dns_ip_rules *_dns_server_ip_rule_get(struct dns_request *request, unsigned char *addr, int addr_len, @@ -8144,6 +8356,30 @@ static int _dns_server_audit_init(void) return 0; } +static void _dns_server_neighbor_cache_remove_all(void) +{ + struct neighbor_cache_item *item = NULL; + struct hlist_node *tmp = NULL; + unsigned long bucket = 0; + + hash_for_each_safe(server.neighbor_cache.cache, bucket, tmp, item, node) + { + _dns_server_neighbor_cache_free_item(item); + } + + pthread_mutex_destroy(&server.neighbor_cache.lock); +} + +static int _dns_server_neighbor_cache_init(void) +{ + hash_init(server.neighbor_cache.cache); + INIT_LIST_HEAD(&server.neighbor_cache.list); + atomic_set(&server.neighbor_cache.cache_num, 0); + pthread_mutex_init(&server.neighbor_cache.lock, NULL); + + return 0; +} + static int _dns_server_cache_init(void) { if (dns_cache_init(dns_conf_cachesize, _dns_server_cache_expired) != 0) { @@ -8279,6 +8515,11 @@ int dns_server_init(void) goto errout; } + if (_dns_server_neighbor_cache_init() != 0) { + tlog(TLOG_ERROR, "init neighbor cache failed."); + goto errout; + } + is_server_init = 1; return 0; errout: @@ -8317,6 +8558,7 @@ void dns_server_exit(void) } _dns_server_close_socket(); + _dns_server_neighbor_cache_remove_all(); _dns_server_cache_save(0); _dns_server_request_remove_all(); pthread_mutex_destroy(&server.request_list_lock); diff --git a/src/util.c b/src/util.c index 5ecaa5a820..539195cda6 100644 --- a/src/util.c +++ b/src/util.c @@ -117,6 +117,7 @@ struct daemon_msg { static int ipset_fd; static int pidfile_fd; static int daemon_fd; +static int netlink_neighbor_fd; unsigned long get_tick_count(void) { @@ -695,7 +696,7 @@ static int _ipset_socket_init(void) return 0; } - ipset_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + ipset_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_NETFILTER); if (ipset_fd < 0) { return -1; @@ -804,6 +805,103 @@ int ipset_del(const char *ipset_name, const unsigned char addr[], int addr_len) return _ipset_operate(ipset_name, addr, addr_len, 0, IPSET_DEL); } +int netlink_get_neighbors(int family, + int (*callback)(const uint8_t *net_addr, int net_addr_len, const uint8_t mac[6], void *arg), + void *arg) +{ + if (netlink_neighbor_fd <= 0) { + netlink_neighbor_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_ROUTE); + if (netlink_neighbor_fd < 0) { + return -1; + } + } + + struct nlmsghdr *nlh; + struct ndmsg *ndm; + char buf[1024 * 16]; + struct iovec iov = {buf, sizeof(buf)}; + struct sockaddr_nl sa; + struct msghdr msg = {&sa, sizeof(sa), &iov, 1, NULL, 0, 0}; + int len; + int ret = 0; + + nlh = (struct nlmsghdr *)buf; + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + nlh->nlmsg_type = RTM_GETNEIGH; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = time(NULL); + nlh->nlmsg_pid = getpid(); + + ndm = NLMSG_DATA(nlh); + ndm->ndm_family = family; + + if (send(netlink_neighbor_fd, buf, NLMSG_SPACE(sizeof(struct ndmsg)), 0) < 0) { + return -1; + } + + while ((len = recvmsg(netlink_neighbor_fd, &msg, 0)) > 0) { + if (ret != 0) { + continue; + } + + for (nlh = (struct nlmsghdr *)buf; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) { + ndm = NLMSG_DATA(nlh); + struct rtattr *rta = RTM_RTA(ndm); + int rtalen = RTM_PAYLOAD(nlh); + const uint8_t *mac = NULL; + const uint8_t *net_addr = NULL; + int net_addr_len = 0; + + for (; RTA_OK(rta, rtalen); rta = RTA_NEXT(rta, rtalen)) { + if (rta->rta_type == NDA_DST) { + if (ndm->ndm_family == AF_INET) { + struct in_addr *addr = RTA_DATA(rta); + if (IN_MULTICAST(ntohl(addr->s_addr))) { + continue; + } + + if (ntohl(addr->s_addr) == 0) { + continue; + } + + net_addr = (uint8_t *)&addr->s_addr; + net_addr_len = IPV4_ADDR_LEN; + } else if (ndm->ndm_family == AF_INET6) { + struct in6_addr *addr = RTA_DATA(rta); + if (IN6_IS_ADDR_MC_NODELOCAL(addr)) { + continue; + } + if (IN6_IS_ADDR_MC_LINKLOCAL(addr)) { + continue; + } + if (IN6_IS_ADDR_MC_SITELOCAL(addr)) { + continue; + } + + if (IN6_IS_ADDR_UNSPECIFIED(addr)) { + continue; + } + + net_addr = addr->s6_addr; + net_addr_len = IPV6_ADDR_LEN; + } + } else if (rta->rta_type == NDA_LLADDR) { + mac = RTA_DATA(rta); + } + } + + if (net_addr != NULL && mac != NULL) { + ret = callback(net_addr, net_addr_len, mac, arg); + if (ret != 0) { + break; + } + } + } + } + + return ret; +} + unsigned char *SSL_SHA256(const unsigned char *d, size_t n, unsigned char *md) { static unsigned char m[SHA256_DIGEST_LENGTH]; @@ -1819,6 +1917,23 @@ daemon_ret daemon_run(int *wstatus) return DAEMON_RET_ERR; } +int parser_mac_address(const char *in_mac, uint8_t mac[6]) +{ + int fileld_num = 0; + + if (in_mac == NULL) { + return -1; + } + + fileld_num = + sscanf(in_mac, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + if (fileld_num != 6) { + return -1; + } + + return 0; +} + #if defined(DEBUG) || defined(TEST) struct _dns_read_packet_info { int data_len; diff --git a/src/util.h b/src/util.h index eb205615c4..f133a9fe71 100644 --- a/src/util.h +++ b/src/util.h @@ -80,6 +80,8 @@ int check_is_ipv4(const char *ip); int check_is_ipv6(const char *ip); +int parser_mac_address(const char *in_mac, uint8_t mac[6]); + int parse_uri(const char *value, char *scheme, char *host, int *port, char *path); int parse_uri_ext(const char *value, char *scheme, char *user, char *password, char *host, int *port, char *path); @@ -98,6 +100,10 @@ int ipset_add(const char *ipset_name, const unsigned char addr[], int addr_len, int ipset_del(const char *ipset_name, const unsigned char addr[], int addr_len); +int netlink_get_neighbors(int family, + int (*callback)(const uint8_t *net_addr, int net_addr_len, const uint8_t mac[6], void *arg), + void *arg); + void SSL_CRYPTO_thread_setup(void); void SSL_CRYPTO_thread_cleanup(void);