2
0

dns.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  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>
  7. #include <net/if.h>
  8. #include <sys/socket.h>
  9. #include <sys/types.h>
  10. #include <errno.h>
  11. #include <resolv.h>
  12. #include <libubox/uloop.h>
  13. #include <libubox/avl-cmp.h>
  14. #define FLAG_RESPONSE 0x8000
  15. #define FLAG_OPCODE 0x7800
  16. #define FLAG_AUTHORATIVE 0x0400
  17. #define FLAG_RCODE 0x000f
  18. #define TYPE_A 0x0001
  19. #define TYPE_CNAME 0x0005
  20. #define TYPE_PTR 0x000c
  21. #define TYPE_TXT 0x0010
  22. #define TYPE_AAAA 0x001c
  23. #define TYPE_SRV 0x0021
  24. #define TYPE_ANY 0x00ff
  25. #define IS_COMPRESSED(x) ((x & 0xc0) == 0xc0)
  26. #define CLASS_FLUSH 0x8000
  27. #define CLASS_UNICAST 0x8000
  28. #define CLASS_IN 0x0001
  29. #define MAX_NAME_LEN 256
  30. #define MAX_DATA_LEN 8096
  31. #include "qosify.h"
  32. static struct uloop_fd ufd;
  33. static struct uloop_timeout cname_gc_timer;
  34. static AVL_TREE(cname_cache, avl_strcmp, false, NULL);
  35. struct vlan_hdr {
  36. uint16_t tci;
  37. uint16_t proto;
  38. };
  39. struct packet {
  40. void *buffer;
  41. unsigned int len;
  42. };
  43. struct dns_header {
  44. uint16_t id;
  45. uint16_t flags;
  46. uint16_t questions;
  47. uint16_t answers;
  48. uint16_t authority;
  49. uint16_t additional;
  50. } __packed;
  51. struct dns_question {
  52. uint16_t type;
  53. uint16_t class;
  54. } __packed;
  55. struct dns_answer {
  56. uint16_t type;
  57. uint16_t class;
  58. uint32_t ttl;
  59. uint16_t rdlength;
  60. } __packed;
  61. struct cname_entry {
  62. struct avl_node node;
  63. uint32_t seq;
  64. uint8_t dscp;
  65. uint8_t age;
  66. };
  67. static void *pkt_peek(struct packet *pkt, unsigned int len)
  68. {
  69. if (len > pkt->len)
  70. return NULL;
  71. return pkt->buffer;
  72. }
  73. static void *pkt_pull(struct packet *pkt, unsigned int len)
  74. {
  75. void *ret = pkt_peek(pkt, len);
  76. if (!ret)
  77. return NULL;
  78. pkt->buffer += len;
  79. pkt->len -= len;
  80. return ret;
  81. }
  82. static int pkt_pull_name(struct packet *pkt, const void *hdr, char *dest)
  83. {
  84. int len;
  85. if (dest)
  86. len = dn_expand(hdr, pkt->buffer + pkt->len, pkt->buffer,
  87. (void *)dest, MAX_NAME_LEN);
  88. else
  89. len = dn_skipname(pkt->buffer, pkt->buffer + pkt->len - 1);
  90. if (len < 0 || !pkt_pull(pkt, len))
  91. return -1;
  92. return 0;
  93. }
  94. static bool
  95. proto_is_vlan(uint16_t proto)
  96. {
  97. return proto == ETH_P_8021Q || proto == ETH_P_8021AD;
  98. }
  99. static void
  100. cname_cache_set(const char *name, uint8_t dscp, uint32_t seq)
  101. {
  102. struct cname_entry *e;
  103. e = avl_find_element(&cname_cache, name, e, node);
  104. if (!e) {
  105. char *name_buf;
  106. e = calloc_a(sizeof(*e), &name_buf, strlen(name) + 1);
  107. e->node.key = strcpy(name_buf, name);
  108. avl_insert(&cname_cache, &e->node);
  109. }
  110. e->age = 0;
  111. e->dscp = dscp;
  112. e->seq = seq;
  113. }
  114. static int
  115. cname_cache_get(const char *name, uint8_t *dscp, uint32_t *seq)
  116. {
  117. struct cname_entry *e;
  118. e = avl_find_element(&cname_cache, name, e, node);
  119. if (!e)
  120. return -1;
  121. if (*dscp == 0xff || e->seq < *seq) {
  122. *dscp = e->dscp;
  123. *seq = e->seq;
  124. }
  125. return 0;
  126. }
  127. static int
  128. dns_parse_question(struct packet *pkt, const void *hdr, uint8_t *dscp, uint32_t *seq)
  129. {
  130. char qname[MAX_NAME_LEN];
  131. if (pkt_pull_name(pkt, hdr, qname) ||
  132. !pkt_pull(pkt, sizeof(struct dns_question)))
  133. return -1;
  134. cname_cache_get(qname, dscp, seq);
  135. qosify_map_lookup_dns_entry(qname, false, dscp, seq);
  136. return 0;
  137. }
  138. static int
  139. dns_parse_answer(struct packet *pkt, void *hdr, uint8_t *dscp, uint32_t *seq)
  140. {
  141. struct qosify_map_data data = {};
  142. char cname[MAX_NAME_LEN];
  143. struct dns_answer *a;
  144. int prev_timeout;
  145. void *rdata;
  146. int len;
  147. if (pkt_pull_name(pkt, hdr, NULL))
  148. return -1;
  149. a = pkt_pull(pkt, sizeof(*a));
  150. if (!a)
  151. return -1;
  152. len = be16_to_cpu(a->rdlength);
  153. rdata = pkt_pull(pkt, len);
  154. if (!rdata)
  155. return -1;
  156. switch (be16_to_cpu(a->type)) {
  157. case TYPE_CNAME:
  158. if (dn_expand(hdr, pkt->buffer + pkt->len, rdata,
  159. cname, sizeof(cname)) < 0)
  160. return -1;
  161. qosify_map_lookup_dns_entry(cname, true, dscp, seq);
  162. cname_cache_set(cname, *dscp, *seq);
  163. return 0;
  164. case TYPE_A:
  165. data.id = CL_MAP_IPV4_ADDR;
  166. memcpy(&data.addr, rdata, 4);
  167. break;
  168. case TYPE_AAAA:
  169. data.id = CL_MAP_IPV6_ADDR;
  170. memcpy(&data.addr, rdata, 16);
  171. break;
  172. default:
  173. return 0;
  174. }
  175. data.user = true;
  176. data.dscp = *dscp;
  177. prev_timeout = qosify_map_timeout;
  178. qosify_map_timeout = be32_to_cpu(a->ttl);
  179. __qosify_map_set_entry(&data);
  180. qosify_map_timeout = prev_timeout;
  181. return 0;
  182. }
  183. static void
  184. qosify_dns_data_cb(struct packet *pkt)
  185. {
  186. struct dns_header *h;
  187. uint32_t lookup_seq = 0;
  188. uint8_t dscp = 0xff;
  189. int i;
  190. h = pkt_pull(pkt, sizeof(*h));
  191. if (!h)
  192. return;
  193. if ((h->flags & cpu_to_be16(FLAG_RESPONSE | FLAG_OPCODE | FLAG_RCODE)) !=
  194. cpu_to_be16(FLAG_RESPONSE))
  195. return;
  196. if (h->questions != cpu_to_be16(1))
  197. return;
  198. if (dns_parse_question(pkt, h, &dscp, &lookup_seq))
  199. return;
  200. for (i = 0; i < be16_to_cpu(h->answers); i++)
  201. if (dns_parse_answer(pkt, h, &dscp, &lookup_seq))
  202. return;
  203. }
  204. static void
  205. qosify_dns_packet_cb(struct packet *pkt)
  206. {
  207. struct ethhdr *eth;
  208. struct ip6_hdr *ip6;
  209. struct ip *ip;
  210. uint16_t proto;
  211. eth = pkt_pull(pkt, sizeof(*eth));
  212. if (!eth)
  213. return;
  214. proto = be16_to_cpu(eth->h_proto);
  215. if (proto_is_vlan(proto)) {
  216. struct vlan_hdr *vlan;
  217. vlan = pkt_pull(pkt, sizeof(*vlan));
  218. if (!vlan)
  219. return;
  220. proto = be16_to_cpu(vlan->proto);
  221. }
  222. switch (proto) {
  223. case ETH_P_IP:
  224. ip = pkt_peek(pkt, sizeof(struct ip));
  225. if (!ip)
  226. return;
  227. if (!pkt_pull(pkt, ip->ip_hl * 4))
  228. return;
  229. proto = ip->ip_p;
  230. break;
  231. case ETH_P_IPV6:
  232. ip6 = pkt_pull(pkt, sizeof(*ip6));
  233. if (!ip6)
  234. return;
  235. proto = ip6->ip6_nxt;
  236. break;
  237. default:
  238. return;
  239. }
  240. if (proto != IPPROTO_UDP)
  241. return;
  242. if (!pkt_pull(pkt, sizeof(struct udphdr)))
  243. return;
  244. qosify_dns_data_cb(pkt);
  245. }
  246. static void
  247. qosify_dns_socket_cb(struct uloop_fd *fd, unsigned int events)
  248. {
  249. static uint8_t buf[8192];
  250. struct packet pkt = {
  251. .buffer = buf,
  252. };
  253. int len;
  254. retry:
  255. len = recvfrom(fd->fd, buf, sizeof(buf), MSG_DONTWAIT, NULL, NULL);
  256. if (len < 0) {
  257. if (errno == EINTR)
  258. goto retry;
  259. return;
  260. }
  261. if (!len)
  262. return;
  263. pkt.len = len;
  264. qosify_dns_packet_cb(&pkt);
  265. }
  266. static void
  267. qosify_cname_cache_gc(struct uloop_timeout *timeout)
  268. {
  269. struct cname_entry *e, *tmp;
  270. avl_for_each_element_safe(&cname_cache, e, node, tmp) {
  271. if (e->age++ < 5)
  272. continue;
  273. avl_delete(&cname_cache, &e->node);
  274. free(e);
  275. }
  276. uloop_timeout_set(timeout, 1000);
  277. }
  278. static int
  279. qosify_open_dns_socket(void)
  280. {
  281. struct sockaddr_ll sll = {
  282. .sll_family = AF_PACKET,
  283. .sll_protocol = htons(ETH_P_ALL),
  284. };
  285. int sock;
  286. sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  287. if (sock == -1) {
  288. ULOG_ERR("failed to create raw socket: %s\n", strerror(errno));
  289. return -1;
  290. }
  291. sll.sll_ifindex = if_nametoindex(QOSIFY_DNS_IFNAME);
  292. if (bind(sock, (struct sockaddr *)&sll, sizeof(sll))) {
  293. ULOG_ERR("failed to bind socket to "QOSIFY_DNS_IFNAME": %s\n",
  294. strerror(errno));
  295. goto error;
  296. }
  297. ufd.fd = sock;
  298. ufd.cb = qosify_dns_socket_cb;
  299. uloop_fd_add(&ufd, ULOOP_READ);
  300. return 0;
  301. error:
  302. close(sock);
  303. return -1;
  304. }
  305. static void
  306. qosify_dns_del_ifb(void)
  307. {
  308. qosify_run_cmd("ip link del ifb-dns type ifb", true);
  309. }
  310. int qosify_dns_init(void)
  311. {
  312. cname_gc_timer.cb = qosify_cname_cache_gc;
  313. qosify_cname_cache_gc(&cname_gc_timer);
  314. qosify_dns_del_ifb();
  315. if (qosify_run_cmd("ip link add ifb-dns type ifb", false) ||
  316. qosify_run_cmd("ip link set dev ifb-dns up", false) ||
  317. qosify_open_dns_socket())
  318. return -1;
  319. return 0;
  320. }
  321. void qosify_dns_stop(void)
  322. {
  323. struct cname_entry *e, *tmp;
  324. if (ufd.registered) {
  325. uloop_fd_delete(&ufd);
  326. close(ufd.fd);
  327. }
  328. qosify_dns_del_ifb();
  329. avl_remove_all_elements(&cname_cache, e, node, tmp)
  330. free(e);
  331. }