loader/interface: attach bpf program directly using netlink
[project/qosify.git] / map.c
diff --git a/map.c b/map.c
index 078dc457a3970d07d65e0d1197d7adbe0c50885b..f88848e4db38266b1bbf4836955f91fb196c9935 100644 (file)
--- a/map.c
+++ b/map.c
@@ -31,6 +31,7 @@ int qosify_map_timeout;
 int qosify_active_timeout;
 struct qosify_config config;
 struct qosify_flow_config flow_config;
+static uint32_t map_dns_seq;
 
 struct qosify_map_file {
        struct list_head list;
@@ -72,7 +73,7 @@ static const struct {
        { "AF13", 14 },
        { "AF21", 18 },
        { "AF22", 20 },
-       { "AF22", 22 },
+       { "AF23", 22 },
        { "AF31", 26 },
        { "AF32", 28 },
        { "AF33", 30 },
@@ -284,7 +285,7 @@ __qosify_map_alloc_entry(struct qosify_map_data *data)
        return e;
 }
 
-static void __qosify_map_set_entry(struct qosify_map_data *data)
+void __qosify_map_set_entry(struct qosify_map_data *data)
 {
        int fd = qosify_map_fds[data->id];
        struct qosify_map_entry *e;
@@ -332,6 +333,9 @@ static void __qosify_map_set_entry(struct qosify_map_data *data)
                bpf_map_update_elem(fd, &data->addr, &val, BPF_ANY);
        }
 
+       if (data->id == CL_MAP_DNS)
+               e->data.addr.dns.seq = ++map_dns_seq;
+
        if (add) {
                if (qosify_map_timeout == ~0 || file) {
                        e->timeout = ~0;
@@ -402,6 +406,8 @@ int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str,
        switch (id) {
        case CL_MAP_DNS:
                data.addr.dns.pattern = str;
+               if (str[-2] == 'c')
+                       data.addr.dns.only_cname = 1;
                break;
        case CL_MAP_TCP_PORTS:
        case CL_MAP_UDP_PORTS:
@@ -521,6 +527,8 @@ qosify_map_parse_line(char *str)
 
        if (!strncmp(key, "dns:", 4))
                qosify_map_set_entry(CL_MAP_DNS, true, key + 4, dscp);
+       if (!strncmp(key, "dns_q:", 6) || !strncmp(key, "dns_c:", 6))
+               qosify_map_set_entry(CL_MAP_DNS, true, key + 6, dscp);
        if (!strncmp(key, "tcp:", 4))
                qosify_map_set_entry(CL_MAP_TCP_PORTS, true, key + 4, dscp);
        else if (!strncmp(key, "udp:", 4))
@@ -599,6 +607,7 @@ static void qosify_map_reset_file_entries(void)
 {
        struct qosify_map_entry *e;
 
+       map_dns_seq = 0;
        avl_for_each_element(&map_data, e, avl)
                e->data.file = false;
 }
@@ -710,31 +719,18 @@ void qosify_map_gc(void)
        uloop_timeout_set(&qosify_map_timer, timeout * 1000);
 }
 
-
-int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int ttl)
+int qosify_map_lookup_dns_entry(char *host, bool cname, uint8_t *dscp, uint32_t *seq)
 {
        struct qosify_map_data data = {
                .id = CL_MAP_DNS,
                .addr.dns.pattern = "",
        };
        struct qosify_map_entry *e;
-       int prev_timeout = qosify_map_timeout;
+       bool ret = -1;
        char *c;
 
        e = avl_find_ge_element(&map_data, &data, e, avl);
        if (!e)
-               return 0;
-
-       memset(&data, 0, sizeof(data));
-       data.user = true;
-       if (!strcmp(type, "A"))
-               data.id = CL_MAP_IPV4_ADDR;
-       else if (!strcmp(type, "AAAA"))
-               data.id = CL_MAP_IPV6_ADDR;
-       else
-               return 0;
-
-       if (qosify_map_fill_ip(&data, addr))
                return -1;
 
        for (c = host; *c; c++)
@@ -744,7 +740,10 @@ int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int
                regex_t *regex = &e->data.addr.dns.regex;
 
                if (e->data.id != CL_MAP_DNS)
-                       return 0;
+                       break;
+
+               if (!cname && e->data.addr.dns.only_cname)
+                       continue;
 
                if (e->data.addr.dns.pattern[0] == '/') {
                        if (regexec(regex, host, 0, NULL, 0) != 0)
@@ -754,13 +753,44 @@ int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int
                                continue;
                }
 
-               if (ttl)
-                       qosify_map_timeout = ttl;
-               data.dscp = e->data.dscp;
-               __qosify_map_set_entry(&data);
-               qosify_map_timeout = prev_timeout;
+               if (*dscp == 0xff || e->data.addr.dns.seq < *seq) {
+                       *dscp = e->data.dscp;
+                       *seq = e->data.addr.dns.seq;
+               }
+               ret = 0;
        }
 
+       return ret;
+}
+
+
+int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int ttl)
+{
+       struct qosify_map_data data = {
+               .dscp = 0xff
+       };
+       int prev_timeout = qosify_map_timeout;
+       uint32_t lookup_seq = 0;
+
+       if (qosify_map_lookup_dns_entry(host, false, &data.dscp, &lookup_seq))
+               return 0;
+
+       data.user = true;
+       if (!strcmp(type, "A"))
+               data.id = CL_MAP_IPV4_ADDR;
+       else if (!strcmp(type, "AAAA"))
+               data.id = CL_MAP_IPV6_ADDR;
+       else
+               return 0;
+
+       if (qosify_map_fill_ip(&data, addr))
+               return -1;
+
+       if (ttl)
+               qosify_map_timeout = ttl;
+       __qosify_map_set_entry(&data);
+       qosify_map_timeout = prev_timeout;
+
        return 0;
 }