1 #include <netinet/if_ether.h>
2 #include <netinet/in.h>
3 #include <netinet/ip.h>
4 #include <netinet/ip6.h>
5 #include <netinet/udp.h>
6 #include <netpacket/packet.h>
8 #include <sys/socket.h>
13 #include <libubox/uloop.h>
14 #include <libubox/avl-cmp.h>
16 #define FLAG_RESPONSE 0x8000
17 #define FLAG_OPCODE 0x7800
18 #define FLAG_AUTHORATIVE 0x0400
19 #define FLAG_RCODE 0x000f
22 #define TYPE_CNAME 0x0005
23 #define TYPE_PTR 0x000c
24 #define TYPE_TXT 0x0010
25 #define TYPE_AAAA 0x001c
26 #define TYPE_SRV 0x0021
27 #define TYPE_ANY 0x00ff
29 #define IS_COMPRESSED(x) ((x & 0xc0) == 0xc0)
31 #define CLASS_FLUSH 0x8000
32 #define CLASS_UNICAST 0x8000
33 #define CLASS_IN 0x0001
35 #define MAX_NAME_LEN 256
36 #define MAX_DATA_LEN 8096
40 static struct uloop_fd ufd
;
41 static struct uloop_timeout cname_gc_timer
;
42 static AVL_TREE(cname_cache
, avl_strcmp
, false, NULL
);
81 static void *pkt_peek(struct packet
*pkt
, unsigned int len
)
90 static void *pkt_pull(struct packet
*pkt
, unsigned int len
)
92 void *ret
= pkt_peek(pkt
, len
);
103 static int pkt_pull_name(struct packet
*pkt
, const void *hdr
, char *dest
)
108 len
= dn_expand(hdr
, pkt
->buffer
+ pkt
->len
, pkt
->buffer
,
109 (void *)dest
, MAX_NAME_LEN
);
111 len
= dn_skipname(pkt
->buffer
, pkt
->buffer
+ pkt
->len
- 1);
113 if (len
< 0 || !pkt_pull(pkt
, len
))
120 proto_is_vlan(uint16_t proto
)
122 return proto
== ETH_P_8021Q
|| proto
== ETH_P_8021AD
;
126 cname_cache_set(const char *name
, uint8_t dscp
)
128 struct cname_entry
*e
;
130 e
= avl_find_element(&cname_cache
, name
, e
, node
);
134 e
= calloc_a(sizeof(*e
), &name_buf
, strlen(name
) + 1);
135 e
->node
.key
= strcpy(name_buf
, name
);
136 avl_insert(&cname_cache
, &e
->node
);
144 cname_cache_get(const char *name
, uint8_t *dscp
)
146 struct cname_entry
*e
;
148 e
= avl_find_element(&cname_cache
, name
, e
, node
);
157 dns_parse_question(struct packet
*pkt
, const void *hdr
, uint8_t *dscp
)
159 char qname
[MAX_NAME_LEN
];
161 if (pkt_pull_name(pkt
, hdr
, qname
) ||
162 !pkt_pull(pkt
, sizeof(struct dns_question
)))
165 cname_cache_get(qname
, dscp
);
166 qosify_map_lookup_dns_entry(qname
, dscp
);
172 dns_parse_answer(struct packet
*pkt
, void *hdr
, uint8_t *dscp
)
174 struct qosify_map_data data
= {};
175 char cname
[MAX_NAME_LEN
];
176 struct dns_answer
*a
;
181 if (pkt_pull_name(pkt
, hdr
, NULL
))
184 a
= pkt_pull(pkt
, sizeof(*a
));
188 len
= be16_to_cpu(a
->rdlength
);
189 rdata
= pkt_pull(pkt
, len
);
193 switch (be16_to_cpu(a
->type
)) {
195 if (dn_expand(hdr
, pkt
->buffer
+ pkt
->len
, rdata
,
196 cname
, sizeof(cname
)) < 0)
199 qosify_map_lookup_dns_entry(cname
, dscp
);
200 cname_cache_set(cname
, *dscp
);
204 data
.id
= CL_MAP_IPV4_ADDR
;
205 memcpy(&data
.addr
, rdata
, 4);
208 data
.id
= CL_MAP_IPV6_ADDR
;
209 memcpy(&data
.addr
, rdata
, 16);
218 prev_timeout
= qosify_map_timeout
;
219 qosify_map_timeout
= be32_to_cpu(a
->ttl
);
220 __qosify_map_set_entry(&data
);
221 qosify_map_timeout
= prev_timeout
;
227 qosify_dns_data_cb(struct packet
*pkt
)
229 struct dns_header
*h
;
233 h
= pkt_pull(pkt
, sizeof(*h
));
237 if ((h
->flags
& cpu_to_be16(FLAG_RESPONSE
| FLAG_OPCODE
| FLAG_RCODE
)) !=
238 cpu_to_be16(FLAG_RESPONSE
))
241 if (h
->questions
!= cpu_to_be16(1))
244 if (dns_parse_question(pkt
, h
, &dscp
))
247 for (i
= 0; i
< be16_to_cpu(h
->answers
); i
++)
248 if (dns_parse_answer(pkt
, h
, &dscp
))
253 qosify_dns_packet_cb(struct packet
*pkt
)
260 eth
= pkt_pull(pkt
, sizeof(*eth
));
264 proto
= be16_to_cpu(eth
->h_proto
);
265 if (proto_is_vlan(proto
)) {
266 struct vlan_hdr
*vlan
;
268 vlan
= pkt_pull(pkt
, sizeof(*vlan
));
277 ip
= pkt_peek(pkt
, sizeof(struct ip
));
281 if (!pkt_pull(pkt
, ip
->ip_hl
* 4))
287 ip6
= pkt_pull(pkt
, sizeof(*ip6
));
291 proto
= ip6
->ip6_nxt
;
297 if (proto
!= IPPROTO_UDP
)
300 if (!pkt_pull(pkt
, sizeof(struct udphdr
)))
303 qosify_dns_data_cb(pkt
);
307 qosify_dns_socket_cb(struct uloop_fd
*fd
, unsigned int events
)
309 static uint8_t buf
[8192];
310 struct packet pkt
= {
316 len
= recvfrom(fd
->fd
, buf
, sizeof(buf
), MSG_DONTWAIT
, NULL
, NULL
);
327 qosify_dns_packet_cb(&pkt
);
331 qosify_cname_cache_gc(struct uloop_timeout
*timeout
)
333 struct cname_entry
*e
, *tmp
;
335 avl_for_each_element_safe(&cname_cache
, e
, node
, tmp
) {
339 avl_delete(&cname_cache
, &e
->node
);
343 uloop_timeout_set(timeout
, 1000);
347 qosify_open_dns_socket(void)
349 struct sockaddr_ll sll
= {
350 .sll_family
= AF_PACKET
,
351 .sll_protocol
= htons(ETH_P_ALL
),
355 sock
= socket(PF_PACKET
, SOCK_RAW
, htons(ETH_P_ALL
));
357 ULOG_ERR("failed to create raw socket: %s\n", strerror(errno
));
361 sll
.sll_ifindex
= if_nametoindex(QOSIFY_DNS_IFNAME
);
362 if (bind(sock
, (struct sockaddr
*)&sll
, sizeof(sll
))) {
363 ULOG_ERR("failed to bind socket to "QOSIFY_DNS_IFNAME
": %s\n",
369 ufd
.cb
= qosify_dns_socket_cb
;
370 uloop_fd_add(&ufd
, ULOOP_READ
);
380 qosify_dns_del_ifb(void)
382 qosify_run_cmd("ip link del ifb-dns type ifb", true);
385 int qosify_dns_init(void)
387 cname_gc_timer
.cb
= qosify_cname_cache_gc
;
388 qosify_cname_cache_gc(&cname_gc_timer
);
390 qosify_dns_del_ifb();
392 if (qosify_run_cmd("ip link add ifb-dns type ifb", false) ||
393 qosify_run_cmd("ip link set dev ifb-dns up", false) ||
394 qosify_open_dns_socket())
400 void qosify_dns_stop(void)
402 struct cname_entry
*e
, *tmp
;
404 if (ufd
.registered
) {
405 uloop_fd_delete(&ufd
);
409 qosify_dns_del_ifb();
411 avl_remove_all_elements(&cname_cache
, e
, node
, tmp
)