2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <sys/types.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <asm/byteorder.h>
26 #include <arpa/nameser.h>
31 #include <libubox/uloop.h>
32 #include <libubox/usock.h>
39 static char *name_buffer;
42 dns_type_string(uint16_t type)
68 dns_send_question(struct uloop_fd *u, char *question, int type)
70 unsigned char buffer[MAX_NAME_LEN];
71 struct dns_header h = { 0 };
72 struct dns_question q = { 0 };
73 struct msghdr m = { 0 };
74 struct iovec iov[3] = { {0}, {0}, {0} };
75 struct sockaddr_in a = { 0 };
78 a.sin_family = AF_INET;
79 a.sin_addr.s_addr = inet_addr(MCAST_ADDR);
80 a.sin_port = htons(MCAST_PORT);
82 h.questions = __cpu_to_be16(1);
83 q.type = __cpu_to_be16(type);
84 q.class = __cpu_to_be16(1);
86 len = dn_comp(question, buffer, MAX_NAME_LEN, NULL, NULL);
91 m.msg_namelen = sizeof(struct sockaddr_in);
96 iov[0].iov_len = sizeof(struct dns_header);
98 iov[1].iov_base = buffer;
101 iov[2].iov_base = &q;
102 iov[2].iov_len = sizeof(struct dns_question);
104 if (sendmsg(u->fd, &m, 0) < 0)
105 fprintf(stderr, "failed to send question\n");
107 DBG(1, "Q <- %s %s\n", dns_type_string(type), question);
120 static struct dns_reply dns_reply[1 + (MAX_ANSWER * 3)];
121 static int dns_answer_cnt;
124 dns_init_answer(void)
130 dns_add_answer(int type, uint8_t *rdata, uint16_t rdlength)
132 struct dns_reply *a = &dns_reply[dns_answer_cnt];
133 if (dns_answer_cnt == MAX_ANSWER)
135 a->rdata = memdup(rdata, rdlength);
137 a->rdlength = rdlength;
142 dns_send_answer(struct uloop_fd *u, char *answer)
145 struct dns_header h = { 0 };
146 struct msghdr m = { 0 };
148 struct sockaddr_in in = { 0 };
154 in.sin_family = AF_INET;
155 in.sin_addr.s_addr = inet_addr(MCAST_ADDR);
156 in.sin_port = htons(MCAST_PORT);
158 h.answers = __cpu_to_be16(dns_answer_cnt);
159 h.flags = __cpu_to_be16(0x8400);
161 iov = malloc(sizeof(struct iovec) * ((dns_answer_cnt * 3) + 1));
166 m.msg_namelen = sizeof(struct sockaddr_in);
168 m.msg_iovlen = (dns_answer_cnt * 3) + 1;
170 iov[0].iov_base = &h;
171 iov[0].iov_len = sizeof(struct dns_header);
173 for (i = 0; i < dns_answer_cnt; i++) {
174 struct dns_answer *a = &dns_reply[i].a;
175 int id = (i * 3) + 1;
177 memset(a, 0, sizeof(*a));
178 a->type = __cpu_to_be16(dns_reply[i].type);
179 a->class = __cpu_to_be16(1);
180 a->ttl = __cpu_to_be32(announce_ttl);
181 a->rdlength = __cpu_to_be16(dns_reply[i].rdlength);
183 len = dn_comp(answer, buffer, sizeof(buffer), NULL, NULL);
187 dns_reply[i].buffer = iov[id].iov_base = memdup(buffer, len);
188 iov[id].iov_len = len;
190 iov[id + 1].iov_base = a;
191 iov[id + 1].iov_len = sizeof(struct dns_answer);
193 iov[id + 2].iov_base = dns_reply[i].rdata;
194 iov[id + 2].iov_len = dns_reply[i].rdlength;
196 DBG(1, "A <- %s %s\n", dns_type_string(dns_reply[i].type), answer);
199 if (sendmsg(u->fd, &m, 0) < 0)
200 fprintf(stderr, "failed to send question\n");
202 for (i = 0; i < dns_answer_cnt; i++) {
203 free(dns_reply[i].buffer);
204 free(dns_reply[i].rdata);
210 scan_name(uint8_t *buffer, int len)
214 while (len && (*buffer != '\0')) {
217 if (IS_COMPRESSED(l))
225 if (!len || !offset || (*buffer != '\0'))
232 dns_consume_header(uint8_t **data, int *len)
234 struct dns_header *h = (struct dns_header *) *data;
235 uint16_t *swap = (uint16_t *) h;
238 if (*len < sizeof(struct dns_header))
241 while (endianess--) {
242 *swap = __be16_to_cpu(*swap);
246 *len -= sizeof(struct dns_header);
247 *data += sizeof(struct dns_header);
253 dns_consume_question(uint8_t **data, int *len)
255 struct dns_question *q = (struct dns_question *) *data;
256 uint16_t *swap = (uint16_t *) q;
259 if (*len < sizeof(struct dns_question))
262 while (endianess--) {
263 *swap = __be16_to_cpu(*swap);
267 *len -= sizeof(struct dns_question);
268 *data += sizeof(struct dns_question);
274 dns_consume_answer(uint8_t **data, int *len)
276 struct dns_answer *a = (struct dns_answer *) *data;
278 if (*len < sizeof(struct dns_answer))
281 a->type = __be16_to_cpu(a->type);
282 a->class = __be16_to_cpu(a->class);
283 a->ttl = __be32_to_cpu(a->ttl);
284 a->rdlength = __be16_to_cpu(a->rdlength);
286 *len -= sizeof(struct dns_answer);
287 *data += sizeof(struct dns_answer);
293 dns_consume_name(uint8_t *base, int blen, uint8_t **data, int *len)
295 int nlen = scan_name(*data, *len);
300 if (dn_expand(base, base + blen, *data, name_buffer, MAX_NAME_LEN) < 0) {
301 perror("dns_consume_name/dn_expand");
314 name_buffer = malloc(MAX_NAME_LEN + 1);
315 rdata_buffer = malloc(MAX_DATA_LEN + 1);
317 if (!name_buffer || !rdata_buffer)
320 memset(name_buffer, 0, MAX_NAME_LEN + 1);
321 memset(rdata_buffer, 0, MAX_NAME_LEN + 1);