map: process dns patterns in the order in which they were defined
authorFelix Fietkau <nbd@nbd.name>
Sun, 6 Mar 2022 21:32:59 +0000 (22:32 +0100)
committerFelix Fietkau <nbd@nbd.name>
Sun, 6 Mar 2022 21:32:59 +0000 (22:32 +0100)
Signed-off-by: Felix Fietkau <nbd@nbd.name>
dns.c
map.c
qosify.h

diff --git a/dns.c b/dns.c
index 170623845a33abbcd133886f70b18415c47db46b..5d10c6ddf10ed19d13af28e8be2c15c57395a5cd 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -74,6 +74,7 @@ struct dns_answer {
 
 struct cname_entry {
        struct avl_node node;
+       uint32_t seq;
        uint8_t dscp;
        uint8_t age;
 };
@@ -123,7 +124,7 @@ proto_is_vlan(uint16_t proto)
 }
 
 static void
-cname_cache_set(const char *name, uint8_t dscp)
+cname_cache_set(const char *name, uint8_t dscp, uint32_t seq)
 {
        struct cname_entry *e;
 
@@ -138,10 +139,11 @@ cname_cache_set(const char *name, uint8_t dscp)
 
        e->age = 0;
        e->dscp = dscp;
+       e->seq = seq;
 }
 
 static int
-cname_cache_get(const char *name, uint8_t *dscp)
+cname_cache_get(const char *name, uint8_t *dscp, uint32_t *seq)
 {
        struct cname_entry *e;
 
@@ -149,12 +151,16 @@ cname_cache_get(const char *name, uint8_t *dscp)
        if (!e)
                return -1;
 
-       *dscp = e->dscp;
+       if (*dscp == 0xff || e->seq < *seq) {
+               *dscp = e->dscp;
+               *seq = e->seq;
+       }
+
        return 0;
 }
 
 static int
-dns_parse_question(struct packet *pkt, const void *hdr, uint8_t *dscp)
+dns_parse_question(struct packet *pkt, const void *hdr, uint8_t *dscp, uint32_t *seq)
 {
        char qname[MAX_NAME_LEN];
 
@@ -162,14 +168,14 @@ dns_parse_question(struct packet *pkt, const void *hdr, uint8_t *dscp)
            !pkt_pull(pkt, sizeof(struct dns_question)))
                return -1;
 
-       cname_cache_get(qname, dscp);
-       qosify_map_lookup_dns_entry(qname, dscp);
+       cname_cache_get(qname, dscp, seq);
+       qosify_map_lookup_dns_entry(qname, dscp, seq);
 
        return 0;
 }
 
 static int
-dns_parse_answer(struct packet *pkt, void *hdr, uint8_t *dscp)
+dns_parse_answer(struct packet *pkt, void *hdr, uint8_t *dscp, uint32_t *seq)
 {
        struct qosify_map_data data = {};
        char cname[MAX_NAME_LEN];
@@ -196,8 +202,8 @@ dns_parse_answer(struct packet *pkt, void *hdr, uint8_t *dscp)
                              cname, sizeof(cname)) < 0)
                        return -1;
 
-               qosify_map_lookup_dns_entry(cname, dscp);
-               cname_cache_set(cname, *dscp);
+               qosify_map_lookup_dns_entry(cname, dscp, seq);
+               cname_cache_set(cname, *dscp, *seq);
 
                return 0;
        case TYPE_A:
@@ -227,6 +233,7 @@ static void
 qosify_dns_data_cb(struct packet *pkt)
 {
        struct dns_header *h;
+       uint32_t lookup_seq = 0;
        uint8_t dscp = 0xff;
        int i;
 
@@ -241,11 +248,11 @@ qosify_dns_data_cb(struct packet *pkt)
        if (h->questions != cpu_to_be16(1))
                return;
 
-       if (dns_parse_question(pkt, h, &dscp))
+       if (dns_parse_question(pkt, h, &dscp, &lookup_seq))
                return;
 
        for (i = 0; i < be16_to_cpu(h->answers); i++)
-               if (dns_parse_answer(pkt, h, &dscp))
+               if (dns_parse_answer(pkt, h, &dscp, &lookup_seq))
                        return;
 }
 
diff --git a/map.c b/map.c
index 436de60ded8ace0aecc6004e4752dd6e0d48ea5c..e4130204b584d9bc260463aad53a0e71d1279aff 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;
@@ -332,6 +333,9 @@ 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;
@@ -599,6 +603,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,7 +715,7 @@ void qosify_map_gc(void)
        uloop_timeout_set(&qosify_map_timer, timeout * 1000);
 }
 
-int qosify_map_lookup_dns_entry(char *host, uint8_t *dscp)
+int qosify_map_lookup_dns_entry(char *host, uint8_t *dscp, uint32_t *seq)
 {
        struct qosify_map_data data = {
                .id = CL_MAP_DNS,
@@ -741,7 +746,10 @@ int qosify_map_lookup_dns_entry(char *host, uint8_t *dscp)
                                continue;
                }
 
-               *dscp = e->data.dscp;
+               if (*dscp == 0xff || e->data.addr.dns.seq < *seq) {
+                       *dscp = e->data.dscp;
+                       *seq = e->data.addr.dns.seq;
+               }
                ret = 0;
        }
 
@@ -753,8 +761,9 @@ int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int
 {
        struct qosify_map_data data = {};
        int prev_timeout = qosify_map_timeout;
+       uint32_t lookup_seq = 0;
 
-       if (qosify_map_lookup_dns_entry(host, &data.dscp))
+       if (qosify_map_lookup_dns_entry(host, &data.dscp, &lookup_seq))
                return 0;
 
        data.user = true;
index 46543852072e9dc3d0b7d958d591c6d199e15c89..7a598e3bebfc8edc1f48c9aa605f3afc699f61a2 100644 (file)
--- a/qosify.h
+++ b/qosify.h
@@ -51,6 +51,7 @@ struct qosify_map_data {
                struct in_addr ip;
                struct in6_addr ip6;
                struct {
+                       uint32_t seq;
                        const char *pattern;
                        regex_t regex;
                } dns;
@@ -89,7 +90,7 @@ void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val);
 void qosify_map_reset_config(void);
 void qosify_map_update_config(void);
 void qosify_map_set_classes(struct blob_attr *val);
-int qosify_map_lookup_dns_entry(char *host, uint8_t *dscp);
+int qosify_map_lookup_dns_entry(char *host, uint8_t *dscp, uint32_t *seq);
 int qosify_map_add_dns_host(char *host, const char *addr, const char *type, int ttl);
 int map_parse_flow_config(struct qosify_flow_config *cfg, struct blob_attr *attr,
                          bool reset);