1 /*
2 * Copyright (c) 2010 Christiano F. Haesbaert <haesbaert@haesbaert.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /*
18 * This file needs a refactoring, pkt_parse and serialize functions rely on
19 * pktcomp being always accurate, most of functions here are not re-entrant and
20 * depend on state that they shouldn't, like serialize_dname which must have the
21 * current packet buffer as input. Also, name compression uses a different
22 * logic when receiving/sending, they should be made equal.
23 * I'll rewrite all of it when I have the time.
24 */
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/queue.h>
28 #include <sys/uio.h>
29
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <netinet/udp.h>
34 #include <arpa/inet.h>
35 #include <arpa/nameser.h>
36
37 #include <net/if_dl.h>
38
39 #include <errno.h>
40 #include <event.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "mdnsd.h"
45 #include "log.h"
46
47 #define CACHEFLUSH_MSK 0x8000
48 #define CLASS_MSK ~0x8000
49 #define UNIRESP_MSK 0x8000
50 #define NAMECOMP_BYTE_MSK 0xc0 /* TODO unify this someday */
51 #define NAMECOMP_MSK 0xc000
52 #define NAMEADDR_MSK ~0xc000
53 #define MAXLABELS 128
54 #define MAXPACKET 10000
55 #define HDR_LEN 12
56 #define MINQRY_LEN 6 /* 4 (qtype + qclass) +1 (null) + 1 (label len) */
57 /* Defer truncated packets from 400ms-500ms */
58 #define RANDOM_DEFERTIME \
59 (arc4random_uniform((u_int32_t) 100000) \
60 + 400000)
61
62 int pkt_parse_header(u_int8_t **, u_int16_t *, struct pkt *);
63 ssize_t pkt_parse_dname(u_int8_t *, u_int16_t, char [MAXHOSTNAMELEN]);
64 int pkt_parse_rr(u_int8_t **, u_int16_t *, struct rr *);
65 int pkt_parse_question(u_int8_t **, u_int16_t *, struct pkt *);
66 int pkt_handle_qst(struct pkt *);
67 ssize_t serialize_rr(struct rr *, u_int8_t *, u_int16_t);
68 ssize_t serialize_qst(struct question *, u_int8_t *, u_int16_t);
69 ssize_t serialize_dname(u_int8_t *, u_int16_t, char [MAXHOSTNAMELEN], int);
70 ssize_t serialize_rdata(struct rr *, u_int8_t *, u_int16_t);
71 int rr_parse_dname(u_int8_t *, u_int16_t, char [MAXHOSTNAMELEN]);
72 ssize_t charstr(char [MAXCHARSTR], u_int8_t *, u_int16_t);
73 void header_htons(HEADER *);
74 void header_ntohs(HEADER *);
75 int pktcomp_add(char [MAXHOSTNAMELEN], u_int16_t);
76 struct namecomp *pktcomp_lookup(char [MAXHOSTNAMELEN]);
77
78 extern struct mdnsd_conf *conf;
79
80 /* Used in name compression */
81 struct namecomp {
82 LIST_ENTRY(namecomp) entry;
83 char dname[MAXHOSTNAMELEN];
84 u_int16_t offset;
85 };
86
87 struct {
88 LIST_HEAD(, namecomp) namecomp_list;
89 u_int8_t *start;
90 u_int16_t len;
91 } pktcomp;
92
93 /* Deferred packets, Known Answer Supression packets with TC bit */
94 TAILQ_HEAD(, pkt) deferred_queue;
95
96 void
packet_init(void)97 packet_init(void)
98 {
99 LIST_INIT(&pktcomp.namecomp_list);
100 TAILQ_INIT(&deferred_queue);
101 }
102
103 /* Send and receive packets */
104 int
send_packet(struct iface * iface,void * pkt,size_t len,struct sockaddr_in * dst)105 send_packet(struct iface *iface, void *pkt, size_t len, struct sockaddr_in *dst)
106 {
107 /* set outgoing interface for multicast traffic */
108 if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr)))
109 if (if_set_mcast(iface) == -1) {
110 log_warn("send_packet: error setting multicast "
111 "interface, %s", iface->name);
112 return (-1);
113 }
114
115 if (sendto(iface->fd, pkt, len, 0,
116 (struct sockaddr *)dst, sizeof(*dst)) == -1) {
117 log_warn("send_packet: error sending packet on interface "
118 "%s, len %zd", iface->name, len);
119 return (-1);
120 }
121
122 return (0);
123 }
124
125 void
recv_packet(int fd,short event,void * bula)126 recv_packet(int fd, short event, void *bula)
127 {
128 union {
129 struct cmsghdr hdr;
130 char buf[CMSG_SPACE(sizeof(struct sockaddr_dl)) +
131 CMSG_SPACE(sizeof(struct in_addr))];
132 } cmsgbuf;
133 struct sockaddr_in ipsrc;
134 struct in_addr ipdst, mdns_addr;
135 struct iovec iov;
136 struct msghdr msg;
137 struct cmsghdr *cmsg;
138 struct sockaddr_dl *dst = NULL;
139 struct iface *iface;
140 static u_int8_t buf[MAXPACKET];
141 struct rr *rr;
142 struct pkt *pkt;
143 struct timeval tv;
144 u_int8_t *pbuf;
145 u_int16_t i, len;
146 ssize_t r;
147
148 if (event != EV_READ)
149 return;
150
151 inet_aton(ALL_MDNS_DEVICES, &mdns_addr);
152 bzero(&msg, sizeof(msg));
153 bzero(buf, sizeof(buf));
154 bzero(&ipdst, sizeof(ipdst));
155 pbuf = buf;
156
157 iov.iov_base = buf;
158 iov.iov_len = MAXPACKET;
159 msg.msg_name = &ipsrc;
160 msg.msg_namelen = sizeof(ipsrc);
161 msg.msg_iov = &iov;
162 msg.msg_iovlen = 1;
163 msg.msg_control = &cmsgbuf.buf;
164 msg.msg_controllen = sizeof(cmsgbuf.buf);
165
166 if ((r = recvmsg(fd, &msg, 0)) == -1) {
167 if (errno != EINTR && errno != EAGAIN)
168 log_warn("recv_packet: read error: %s",
169 strerror(errno));
170 return;
171 }
172
173 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
174 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
175 if (cmsg->cmsg_level == IPPROTO_IP &&
176 cmsg->cmsg_type == IP_RECVIF) {
177 dst = (struct sockaddr_dl *)CMSG_DATA(cmsg);
178 continue;
179 }
180 if (cmsg->cmsg_level == IPPROTO_IP &&
181 cmsg->cmsg_type == IP_RECVDSTADDR) {
182 ipdst = *(struct in_addr *)CMSG_DATA(cmsg);
183 continue;
184 }
185
186 }
187 /*
188 * We need a valid dst to lookup receiving interface, see below.
189 * Ipdst must be filled so we can check for unicast answers, see below.
190 */
191 if (dst == NULL || ipdst.s_addr == 0)
192 return;
193
194 len = (u_int16_t)r;
195
196 /* Check the packet is not from one of the local interfaces */
197 LIST_FOREACH(iface, &conf->iface_list, entry)
198 if (iface->addr.s_addr == ipsrc.sin_addr.s_addr)
199 return;
200
201 if ((pkt = calloc(1, sizeof(*pkt))) == NULL)
202 fatal("calloc");
203 pkt_init(pkt);
204 pktcomp_reset(0, buf, len);
205 pkt->ipsrc = ipsrc;
206 /*
207 * Parse header, we'll use the HEADER structure in nameser.h
208 */
209 if (pkt_parse_header(&pbuf, &len, pkt) == -1) {
210 pkt_cleanup(pkt);
211 free(pkt);
212 return;
213 }
214
215 /*
216 * Multicastdns draft 4. Source Address check.
217 * If a response packet was sent to an unicast address, check if the
218 * source ip address in the packet matches one of our subnets, if not,
219 * drop it.
220 */
221 if (pkt->h.qr == MDNS_RESPONSE && ipdst.s_addr != mdns_addr.s_addr) {
222 /* if_find_iface will try to match source address */
223 if ((iface = if_find_iface(dst->sdl_index,
224 pkt->ipsrc.sin_addr)) == NULL) {
225 log_warn("recv_packet: "
226 "cannot find a matching interface (1)");
227 pkt_cleanup(pkt);
228 free(pkt);
229 return;
230 }
231 }
232 else /* Disregard source ip address, just find a matching iface */
233 if ((iface = if_find_index(dst->sdl_index)) == NULL) {
234 log_warn("recv_packet: "
235 "cannot find a matching interface (2)");
236 pkt_cleanup(pkt);
237 free(pkt);
238 return;
239 }
240 /* Save the received interface */
241 pkt->iface = iface;
242
243 /* Check if this is a legacy dns packet */
244 if (ntohs(pkt->ipsrc.sin_port) != MDNS_PORT)
245 pkt->flags |= PKT_FLAG_LEGACY;
246
247 /* Parse question section */
248 if (pkt->h.qr == MDNS_QUERY)
249 for (i = 0; i < pkt->h.qdcount; i++)
250 if (pkt_parse_question(&pbuf, &len, pkt) == -1) {
251 pkt_cleanup(pkt);
252 free(pkt);
253 return;
254 }
255 /* Parse RR sections */
256 for (i = 0; i < pkt->h.ancount; i++) {
257 if ((rr = calloc(1, sizeof(*rr))) == NULL)
258 fatal("calloc");
259 if (pkt_parse_rr(&pbuf, &len, rr) == -1) {
260 log_warnx("Can't parse AN RR");
261 free(rr);
262 pkt_cleanup(pkt);
263 free(pkt);
264 return;
265 }
266 LIST_INSERT_HEAD(&pkt->anlist, rr, pentry);
267 }
268 for (i = 0; i < pkt->h.nscount; i++) {
269 if ((rr = calloc(1, sizeof(*rr))) == NULL)
270 fatal("calloc");
271 if (pkt_parse_rr(&pbuf, &len, rr) == -1) {
272 log_warnx("Can't parse NS RR");
273 free(rr);
274 pkt_cleanup(pkt);
275 free(pkt);
276 return;
277 }
278 LIST_INSERT_HEAD(&pkt->nslist, rr, pentry);
279 }
280 for (i = 0; i < pkt->h.arcount; i++) {
281 if ((rr = calloc(1, sizeof(*rr))) == NULL)
282 fatal("calloc");
283 if (pkt_parse_rr(&pbuf, &len, rr) == -1) {
284 log_warnx("Can't parse AR RR");
285 free(rr);
286 pkt_cleanup(pkt);
287 free(pkt);
288 return;
289 }
290
291 LIST_INSERT_HEAD(&pkt->arlist, rr, pentry);
292 }
293
294 /* XXX: If we droped an RR our packet counts may be wrong. */
295
296 if (len != 0) {
297 log_warnx("Couldn't read all packet, %u bytes left", len);
298 log_warnx("ancount %d, nscount %d, arcount %d",
299 pkt->h.ancount, pkt->h.nscount, pkt->h.arcount);
300 pkt_cleanup(pkt);
301 free(pkt);
302 return;
303 }
304
305 /*
306 * Packet parsing done, our pkt structure is complete.
307 */
308
309 /*
310 * Check if the packet is the continuation of a previous truncated
311 * packet, see below. A query packet with no questions and with answers
312 * in is a continuation. Merge this answer with the previous packet.
313 */
314 evtimer_set(&pkt->timer, pkt_process, pkt);
315 if (pkt->h.qr == MDNS_QUERY &&
316 pkt->h.qdcount == 0 && pkt->h.arcount == 0 &&
317 pkt->h.nscount == 0 && pkt->h.ancount > 0) {
318 struct pkt *dpkt, *match = NULL;
319
320 TAILQ_FOREACH(dpkt, &deferred_queue, entry) {
321 /* XXX: Should we compare source port as well ? */
322 if (dpkt->ipsrc.sin_addr.s_addr !=
323 pkt->ipsrc.sin_addr.s_addr)
324 continue;
325 /* Found a match */
326 match = dpkt;
327 break;
328 }
329 if (match != NULL) {
330 if (evtimer_pending(&match->timer, NULL))
331 evtimer_del(&match->timer);
332 TAILQ_REMOVE(&deferred_queue, match, entry);
333 /* Merge pkt into match */
334 while ((rr = LIST_FIRST(&pkt->anlist)) != NULL) {
335 LIST_REMOVE(rr, pentry);
336 pkt->h.ancount--;
337 pkt_add_anrr(match, rr);
338 }
339 pkt_cleanup(pkt);
340 free(pkt);
341 pkt = match;
342 }
343 else
344 log_warnx("Got a continuation packet from %s:%s "
345 "but no match", inet_ntoa(pkt->ipsrc.sin_addr),
346 ntohs(pkt->ipsrc.sin_port));
347 }
348
349 /*
350 * Mdns Draft 7.2 Multi-Packet Known Answer Supression
351 * A Multicast DNS Responder seeing a Multicast DNS Query with the TC
352 * bit set defers its response for a time period randomly selected in
353 * the interval 400-500ms. This gives the Multicast DNS Querier time to
354 * send additional Known Answer packets before the Responder responds.
355 * If the Responder sees any of its answers listed in the Known Answer
356 * lists of subsequent packets from the querying host, it SHOULD delete
357 * that answer from the list of answers it is planning to give, provided
358 * that no other host on the network is also waiting to receive the same
359 * answer record. Check if this packet was truncated, due to too many
360 * Known Answer Supression entries, if so, defer processing
361 */
362
363 if (pkt->h.qr == MDNS_QUERY && pkt->h.tc) {
364 TAILQ_INSERT_TAIL(&deferred_queue, pkt, entry);
365 timerclear(&tv);
366 tv.tv_usec = RANDOM_DEFERTIME;
367 evtimer_add(&pkt->timer, &tv);
368 return;
369 }
370
371 /* Use 0 as event as our processing wasn't deferred */
372 pkt_process(-1, 0, pkt);
373 }
374
375 void
pkt_process(int unused,short event,void * v_pkt)376 pkt_process(int unused, short event, void *v_pkt)
377 {
378 struct pkt *pkt = v_pkt;
379 struct rr *rr, *rraux;
380
381 if (event == EV_TIMEOUT) {
382 log_debug("pkt deferred from %s:%u",
383 inet_ntoa(pkt->ipsrc.sin_addr), ntohs(pkt->ipsrc.sin_port));
384 TAILQ_REMOVE(&deferred_queue, pkt, entry);
385 }
386
387 /* Process all answers */
388 /*
389 * The answer section for query packets is not authoritative,
390 * it's used in known answer supression, so, if it's a query,
391 * discard all answers.
392 */
393 switch (pkt->h.qr) {
394 case MDNS_QUERY:
395 if (pkt_handle_qst(pkt) == -1) {
396 log_warnx("pkt_handle_qst error");
397 goto bad;
398 }
399 /* Clear all answer section (KNA) */
400 while((rr = LIST_FIRST(&pkt->anlist)) != NULL) {
401 LIST_REMOVE(rr, pentry);
402 free(rr);
403 }
404 /* Clear up ESDN0/T_opt packets */
405 LIST_FOREACH_SAFE(rr, &pkt->arlist, pentry, rraux) {
406 if (rr->rrs.type == T_OPT) {
407 LIST_REMOVE(rr, pentry);
408 free(rr);
409 }
410 }
411
412 break;
413 case MDNS_RESPONSE:
414 /* Process answer section */
415 while ((rr = LIST_FIRST(&pkt->anlist)) != NULL) {
416 LIST_REMOVE(rr, pentry);
417 cache_process(rr);
418 }
419 /* Process additional section */
420 while ((rr = LIST_FIRST(&pkt->arlist)) != NULL) {
421 LIST_REMOVE(rr, pentry);
422 cache_process(rr);
423 }
424 break;
425 }
426
427 /* Clear all authority section */
428 while((rr = LIST_FIRST(&pkt->nslist)) != NULL) {
429 LIST_REMOVE(rr, pentry);
430 free(rr);
431 }
432
433 /* Sanity check, every section must be empty. */
434 if (!LIST_EMPTY(&pkt->qlist))
435 log_warnx("Unprocessed question in Question Section");
436 if (!LIST_EMPTY(&pkt->anlist))
437 log_warnx("Unprocessed rr in Answer Section");
438 if (!LIST_EMPTY(&pkt->nslist))
439 log_warnx("Unprocessed rr in Authority Section");
440 if (!LIST_EMPTY(&pkt->arlist))
441 log_warnx("Unprocessed rr in Additional Section");
442 bad:
443 pkt_cleanup(pkt);
444 free(pkt);
445
446 }
447
448 int
pkt_sendto(struct pkt * pkt,struct iface * iface,struct sockaddr_in * pdst)449 pkt_sendto(struct pkt *pkt, struct iface *iface, struct sockaddr_in *pdst)
450 {
451 struct sockaddr_in all_mdns;
452 static u_int8_t buf[MAXPACKET];
453 struct question *qst;
454 struct rr *rr;
455 HEADER *h;
456 u_int8_t *pbuf;
457 ssize_t n, left;
458 int inaddrany;
459
460 inet_aton(ALL_MDNS_DEVICES, &all_mdns.sin_addr);
461 all_mdns.sin_port = htons(MDNS_PORT);
462 all_mdns.sin_family = AF_INET;
463 all_mdns.sin_len = sizeof(struct sockaddr_in);
464
465 /* If dst not specified, send to mcast addr */
466 if (pdst == NULL)
467 pdst = &all_mdns;
468 if (iface->mtu > MAXPACKET) {
469 log_warnx("pkt_sendto: insane mtu");
470 return (-1);
471 }
472 bzero(buf, sizeof(buf));
473 left = iface->mtu - 28;
474 h = (HEADER *) buf;
475 pbuf = buf;
476 pktcomp_reset(0, buf, left);
477 /*
478 * Every packet must have a header, we assume pkt_sendto will only be
479 * called for full packets, that is, packets that require a header.
480 */
481 if (left < HDR_LEN) {
482 log_warnx("pkt_sendto: left < HDR_LEN");
483 return (-1);
484 }
485 /* Copy header, field by field as we do our own calculations in
486 * qdcount, ancount and etc... */
487 if (pkt->flags & PKT_FLAG_LEGACY) {
488 h->id = pkt->h.id;
489 h->aa = 1;
490 }
491 h->qr = pkt->h.qr;
492 left -= HDR_LEN;
493 pbuf += HDR_LEN;
494 /* Append all questions, they must fit a single packet. */
495 LIST_FOREACH(qst, &pkt->qlist, entry) {
496 n = serialize_qst(qst, pbuf, left);
497 if (n == -1 || n > left) {
498 log_warnx("pkt_sendto: "
499 "can't serialize question section");
500 return (-1);
501 }
502 h->qdcount++;
503 pbuf += n;
504 left -= n;
505 }
506 /*
507 * This is where the shit happens, if we are querying and our known
508 * answers section won't fit in a single packet, we fragment. The
509 * following could be a recursive call, passing a flag telling us if
510 * we're in a "fragmented" state or not, but if so, we would need to
511 * make buf non-static, allocating MAX_PACKET for each fragmenting
512 * packet. This might seem like premature optimization but it's also
513 * easier to maintain.
514 */
515 LIST_FOREACH(rr, &pkt->anlist, pentry) {
516 int in_retry;
517
518 in_retry = 0;
519 retry:
520 /*
521 * Have to patch T_A if INADDR_ANY with the correct interface
522 * address.
523 */
524 inaddrany = RR_INADDRANY(rr);
525 if (inaddrany)
526 rr->rdata.A.s_addr = iface->addr.s_addr;
527 n = serialize_rr(rr, pbuf, left);
528 if (inaddrany)
529 rr->rdata.A.s_addr = INADDR_ANY;
530 /* Unexpected n */
531 if (n > left) {
532 log_warnx("No space left on packet for an section.");
533 return (-1);
534 }
535 /*
536 * Fragmentation only for queries, on answer is an
537 * error, actually only for queries with known answer
538 * supression.
539 */
540 if (n == -1 && h->qr == MDNS_RESPONSE) {
541 log_warnx("Can't fragment for response packets");
542 return (-1);
543 }
544 /*
545 * Won't fit, send what we have, restart the ball.
546 */
547 if (n == -1) {
548 /* Set truncation bit and close packet */
549 h->tc = 1;
550 header_htons(h);
551 if (send_packet(iface, buf, pbuf - buf, pdst) == -1)
552 return (-1);
553 /* Reset states */
554 bzero(buf, sizeof(buf));
555 left = iface->mtu;
556 pbuf = buf;
557 /* XXX: alignment bug? */
558 h = (HEADER *) buf;
559 n = 0;
560 pktcomp_reset(0, buf, left);
561 /* Copy header */
562 if (pkt->flags & PKT_FLAG_LEGACY)
563 h->id = pkt->h.id;
564 h->qr = pkt->h.qr;
565 left -= HDR_LEN;
566 pbuf += HDR_LEN;
567 /* Avoid a possible stupid infinite loop */
568 if (in_retry) {
569 log_warnx("pkt_sendto: failing on retry");
570 return (-1);
571 }
572 in_retry = 1;
573 goto retry;
574 }
575 h->ancount++;
576 pbuf += n;
577 left -= n;
578 }
579
580 /* Append all authorities, they must fit a single packet. */
581 LIST_FOREACH(rr, &pkt->nslist, pentry) {
582 inaddrany = RR_INADDRANY(rr);
583 if (inaddrany)
584 rr->rdata.A.s_addr = iface->addr.s_addr;
585 n = serialize_rr(rr, pbuf, left);
586 if (inaddrany)
587 rr->rdata.A.s_addr = INADDR_ANY;
588 if (n == -1 || n > left) {
589 return (-1);
590 }
591 h->nscount++;
592 pbuf += n;
593 left -= n;
594 }
595
596 /* Append all additionals, they must fit a single packet. */
597 LIST_FOREACH(rr, &pkt->arlist, pentry) {
598 inaddrany = RR_INADDRANY(rr);
599 if (inaddrany)
600 rr->rdata.A.s_addr = iface->addr.s_addr;
601 n = serialize_rr(rr, pbuf, left);
602 if (inaddrany)
603 rr->rdata.A.s_addr = INADDR_ANY;
604 if (n == -1 || n > left) {
605 return (-1);
606 }
607 h->arcount++;
608 pbuf += n;
609 left -= n;
610 }
611
612 /* Close packet and send. */
613 header_htons(h);
614 if (send_packet(iface, buf, pbuf - buf, pdst) == -1)
615 return (-1);
616 return (0);
617 }
618
619 int
pkt_send(struct pkt * pkt,struct iface * iface)620 pkt_send(struct pkt *pkt, struct iface *iface)
621 {
622 struct iface *iface2;
623 int succ = 0;
624
625 if (iface != ALL_IFACE)
626 return (pkt_sendto(pkt, iface, NULL));
627
628 LIST_FOREACH(iface2, &conf->iface_list, entry) {
629 if (iface2->state != IF_STA_ACTIVE)
630 continue;
631 if (pkt_sendto(pkt, iface2, NULL) == -1)
632 log_warnx("Can't send packet through %s", iface2->name);
633 else
634 succ++;
635 }
636 /* If we couldn't send to a single iface, consider an error */
637 if (succ == 0)
638 return (-1);
639
640 return (0);
641 }
642
643 void
pkt_init(struct pkt * pkt)644 pkt_init(struct pkt *pkt)
645 {
646 bzero(pkt, sizeof(*pkt));
647 LIST_INIT(&pkt->qlist);
648 LIST_INIT(&pkt->anlist);
649 LIST_INIT(&pkt->nslist);
650 LIST_INIT(&pkt->arlist);
651 }
652
653 void
pkt_cleanup(struct pkt * pkt)654 pkt_cleanup(struct pkt *pkt)
655 {
656 struct rr *rr;
657 struct question *qst;
658
659 while ((qst = LIST_FIRST(&pkt->qlist)) != NULL) {
660 LIST_REMOVE(qst, entry);
661 free(qst);
662 }
663 while ((rr = LIST_FIRST(&pkt->anlist)) != NULL) {
664 LIST_REMOVE(rr, pentry);
665 free(rr);
666 }
667 while ((rr = LIST_FIRST(&pkt->nslist)) != NULL) {
668 LIST_REMOVE(rr, pentry);
669 free(rr);
670 }
671 while ((rr = LIST_FIRST(&pkt->arlist)) != NULL) {
672 LIST_REMOVE(rr, pentry);
673 free(rr);
674 }
675 }
676
677 /* packet building */
678 void
pkt_add_question(struct pkt * pkt,struct question * qst)679 pkt_add_question(struct pkt *pkt, struct question *qst)
680 {
681 LIST_INSERT_HEAD(&pkt->qlist, qst, entry);
682 pkt->h.qdcount++;
683 }
684
685 void
pkt_add_anrr(struct pkt * pkt,struct rr * rr)686 pkt_add_anrr(struct pkt *pkt, struct rr *rr)
687 {
688 LIST_INSERT_HEAD(&pkt->anlist, rr, pentry);
689 pkt->h.ancount++;
690 }
691
692 void
pkt_add_nsrr(struct pkt * pkt,struct rr * rr)693 pkt_add_nsrr(struct pkt *pkt, struct rr *rr)
694 {
695 LIST_INSERT_HEAD(&pkt->nslist, rr, pentry);
696 pkt->h.nscount++;
697 }
698
699 void
pkt_add_arrr(struct pkt * pkt,struct rr * rr)700 pkt_add_arrr(struct pkt *pkt, struct rr *rr)
701 {
702 LIST_INSERT_HEAD(&pkt->arlist, rr, pentry);
703 pkt->h.arcount++;
704 }
705
706 int
rr_set(struct rr * rr,char dname[MAXHOSTNAMELEN],u_int16_t type,u_int16_t class,u_int32_t ttl,u_int flags,void * rdata,size_t rdlen)707 rr_set(struct rr *rr, char dname[MAXHOSTNAMELEN],
708 u_int16_t type, u_int16_t class, u_int32_t ttl,
709 u_int flags, void *rdata, size_t rdlen)
710 {
711 bzero(rr, sizeof(*rr));
712
713 rr->rrs.type = type;
714 rr->rrs.class = class;
715 rr->ttl = ttl;
716 rr->flags = flags;
717 strlcpy(rr->rrs.dname, dname, sizeof(rr->rrs.dname));
718
719 if (rdata != NULL) {
720 if (rdlen > sizeof(rr->rdata)) {
721 log_debug("rr_set: Invalid rdlen %zd", rdlen);
722 return (-1);
723 }
724 memcpy(&rr->rdata, rdata, rdlen);
725 }
726
727 return (0);
728 }
729
730 int
rr_rdata_cmp(struct rr * rra,struct rr * rrb)731 rr_rdata_cmp(struct rr *rra, struct rr *rrb)
732 {
733 struct iface *iface;
734
735 if (rra->rrs.type != rrb->rrs.type)
736 return (-1);
737 if (rra->rrs.class != rrb->rrs.class)
738 return (-1);
739
740 /*
741 * Special case, if this is a T_A record and the address is INADDR_ANY,
742 * we must compare agains all our interface addresses.
743 */
744 if (RR_INADDRANY(rra) || RR_INADDRANY(rrb)) {
745 LIST_FOREACH(iface, &conf->iface_list, entry) {
746 if (iface->addr.s_addr == rra->rdata.A.s_addr)
747 return (0);
748 if (iface->addr.s_addr == rrb->rdata.A.s_addr)
749 return (0);
750 }
751 }
752
753 return (memcmp(&rra->rdata, &rrb->rdata, sizeof(rra->rdata)));
754 }
755
756 u_int32_t
rr_ttl_left(struct rr * rr)757 rr_ttl_left(struct rr *rr)
758 {
759 struct timespec tnow;
760 struct timespec tr;
761
762 if (clock_gettime(CLOCK_MONOTONIC, &tnow))
763 fatal("clock_gettime");
764 timespecsub(&tnow, &rr->age, &tr);
765
766 return (rr->ttl - (u_int32_t)tr.tv_sec);
767 }
768
769 struct rr *
rr_dup(struct rr * rr)770 rr_dup(struct rr *rr)
771 {
772 struct rr *rdup;
773
774 if ((rdup = malloc(sizeof(*rdup))) == NULL)
775 fatal("malloc");
776 memcpy(rdup, rr, sizeof(*rdup));
777
778 return (rdup);
779 }
780
781 int
pkt_parse_header(u_int8_t ** pbuf,u_int16_t * len,struct pkt * pkt)782 pkt_parse_header(u_int8_t **pbuf, u_int16_t *len, struct pkt *pkt)
783 {
784 u_int8_t *buf = *pbuf;
785
786 /* MDNS header sanity check */
787 if (*len < HDR_LEN) {
788 log_debug("pkt_parse_header: bad packet size %u", len);
789 return (-1);
790 }
791 pkt->h = *((HEADER *) buf);
792 header_ntohs(&pkt->h);
793 *len -= HDR_LEN;
794 *pbuf += HDR_LEN;
795
796 return (0);
797 }
798
799 int
pkt_parse_question(u_int8_t ** pbuf,u_int16_t * len,struct pkt * pkt)800 pkt_parse_question(u_int8_t **pbuf, u_int16_t *len, struct pkt *pkt)
801 {
802 u_int16_t us;
803 struct question *qst;
804 ssize_t n;
805
806 /* MDNS question sanity check */
807 if (*len < MINQRY_LEN) {
808 log_debug("pkt_parse_question: bad query packet size %u", *len);
809 return (-1);
810 }
811
812 if ((qst = calloc(1, sizeof(*qst))) == NULL)
813 fatal("calloc");
814
815 n = pkt_parse_dname(*pbuf, *len, qst->rrs.dname);
816 if (n == -1) {
817 free(qst);
818 return (-1);
819 }
820
821 *pbuf += n;
822 *len -= n;
823
824 GETSHORT(qst->rrs.type, *pbuf);
825 *len -= INT16SZ;
826
827 GETSHORT(us, *pbuf);
828 *len -= INT16SZ;
829
830 /* Deal with legacy packets */
831 if (pkt->flags & PKT_FLAG_LEGACY) {
832 qst->flags |= QST_FLAG_UNIRESP;
833 qst->rrs.class = us;
834 } else { /* Normal MDNS packets */
835 if (us & UNIRESP_MSK)
836 qst->flags |= QST_FLAG_UNIRESP;
837 /* Get the class */
838 qst->rrs.class = us & CLASS_MSK;
839 }
840
841 /* This really sucks, we can't know if the class is valid prior to
842 * parsing the labels, I mean, we could but would be ugly */
843 if (qst->rrs.class != C_ANY && qst->rrs.class != C_IN) {
844 log_warnx("pkt_parse_question: Invalid packet qclass %u",
845 qst->rrs.class);
846 free(qst);
847 return (-1);
848 }
849
850 LIST_INSERT_HEAD(&pkt->qlist, qst, entry);
851
852 return (0);
853 }
854
855 ssize_t
pkt_parse_dname(u_int8_t * buf,u_int16_t len,char dname[MAXHOSTNAMELEN])856 pkt_parse_dname(u_int8_t *buf, u_int16_t len, char dname[MAXHOSTNAMELEN])
857 {
858 size_t i;
859 u_int8_t lablen;
860 int jumped = 0;
861 u_int16_t oldlen = len;
862 size_t slen;
863 char label[MAXLABELLEN];
864
865 /* be extra safe */
866 bzero(dname, MAXHOSTNAMELEN);
867
868 for (i = 0; i < MAXLABELS; i++) {
869 /* check if head is a pointer */
870 if (*buf & NAMECOMP_BYTE_MSK) {
871 u_int16_t us, ncoff;
872
873 GETSHORT(us, buf);
874 if (!jumped)
875 len -= INT16SZ;
876 ncoff = us & NAMEADDR_MSK;
877 /*
878 * Prevent the following:
879 * 1. Pointers should only point backward.
880 * 2. No pointer should point past buf.
881 */
882 if (ncoff > pktcomp.len - len) {
883 log_warnx("Invalid NC pointer");
884 return (-1);
885 }
886 buf = pktcomp.start + ncoff;
887 jumped = 1;
888 }
889
890 /*
891 * XXX No support for multiple pointers yet.
892 */
893 if (*buf & NAMECOMP_BYTE_MSK) {
894 log_warnx("I can't cope with multiple compression"
895 " pointers");
896 return (-1);
897 }
898
899 lablen = *buf++;
900
901 if (lablen > sizeof(label) ||
902 buf + lablen > pktcomp.start + pktcomp.len) {
903 log_warnx("Invalid lablen, too big");
904 return (-1);
905 }
906
907 if (!jumped)
908 len--;
909
910 if (lablen == 0) {
911 /* remove the trailling dot */
912 slen = strlen(dname);
913 if (slen > 0)
914 dname[slen - 1] = '\0';
915 break;
916 }
917
918 if (lablen > (MAXHOSTNAMELEN - strlen(dname)) ||
919 lablen > MAXLABELLEN - 1) {
920 log_warnx("label won't fit");
921 return (-1);
922 }
923 memcpy(label, buf, lablen);
924 label[lablen] = '\0';
925 /* strlcat needs a proper C string in src */
926 if (strlcat(dname, label, MAXHOSTNAMELEN) >= MAXHOSTNAMELEN) {
927 log_warnx("domain-name truncated");
928 return (-1);
929 }
930
931 /* should we leave the dot on the last tag ? */
932 if (strlcat(dname, ".", MAXHOSTNAMELEN) >= MAXHOSTNAMELEN) {
933 log_warnx("domain-name truncated");
934 return (-1);
935 }
936
937 buf += lablen;
938 if (!jumped)
939 len -= lablen;
940 }
941
942 if (i == MAXLABELS) {
943 log_warnx("max labels reached");
944 return (-1);
945 }
946
947 return (oldlen - len);
948 }
949
950
951 /*
952 * Fully parse a resource record ("RR").
953 * This adjusts "len" to be the number of bytes left in "pbuf", which is
954 * the packet buffer.
955 * (There may be multiple RR entries in a single request.)
956 * The "rr" field is filled in along the way.
957 * Returns -1 on failure, 0 on success.
958 */
959 int
pkt_parse_rr(u_int8_t ** pbuf,u_int16_t * len,struct rr * rr)960 pkt_parse_rr(u_int8_t **pbuf, u_int16_t *len, struct rr *rr)
961 {
962 u_int16_t us, rdlen = 0, tmplen, i, code, plen, erc, pl;
963 u_int32_t ul;
964 size_t j;
965 ssize_t n;
966 u_char *buf;
967
968 n = pkt_parse_dname(*pbuf, *len, rr->rrs.dname);
969 if (n == -1)
970 return (-1);
971 *pbuf += n;
972 *len -= n;
973 /* Make sure rr packet len is ok */
974 if (*len < 8) {
975 log_warnx("RR packet length too long");
976 return (-1);
977 }
978 GETSHORT(rr->rrs.type, *pbuf);
979 *len -= INT16SZ;
980
981 /*
982 * The T_OPT type is handled differently from other RR types, so
983 * we jump to the type handler before reading in values that the
984 * OPT doesn't define.
985 * See RFC 2671 for details.
986 */
987
988 if (T_OPT == rr->rrs.type)
989 goto handletype;
990
991 GETSHORT(us, *pbuf);
992 *len -= INT16SZ;
993 if (us & CACHEFLUSH_MSK)
994 rr->flags |= RR_FLAG_CACHEFLUSH;
995 rr->rrs.class = us & CLASS_MSK;
996 if (rr->rrs.class != C_ANY && rr->rrs.class != C_IN) {
997 log_debug("pkt_parse_rr: %s (%s) Invalid packet class %u",
998 rr_type_name(rr->rrs.type), rr->rrs.dname, rr->rrs.class);
999 return (-1);
1000 }
1001 GETLONG(rr->ttl, *pbuf);
1002 *len -= INT32SZ;
1003 GETSHORT(rdlen, *pbuf);
1004 *len -= INT16SZ;
1005 if (*len < rdlen) {
1006 log_debug("Invalid rr data length, *len = %u, rdlen = %u",
1007 *len, rdlen);
1008 return (-1);
1009 }
1010
1011 handletype:
1012 switch (rr->rrs.type) {
1013 case T_A:
1014 buf = *pbuf;
1015 if (rdlen != INT32SZ) {
1016 log_debug("Invalid A record rdlen %u", rdlen);
1017 return (-1);
1018 }
1019 GETLONG(ul, buf);
1020 rr->rdata.A.s_addr = htonl(ul);
1021 if (rr->rdata.A.s_addr == INADDR_ANY) {
1022 log_warnx("Invalid T_A record with ip address 0.0.0.0");
1023 return (-1);
1024 }
1025 break;
1026 case T_HINFO:
1027 if ((n = charstr(rr->rdata.HINFO.cpu, *pbuf, rdlen)) == -1)
1028 return (-1);
1029 if ((n = charstr(rr->rdata.HINFO.os, *pbuf + n,
1030 rdlen - n)) == -1)
1031 return (-1);
1032 break;
1033 case T_CNAME:
1034 if (rr_parse_dname(*pbuf, *len,
1035 rr->rdata.CNAME) == -1)
1036 return (-1);
1037 break;
1038 case T_PTR:
1039 if (rr_parse_dname(*pbuf, *len,
1040 rr->rdata.PTR) == -1)
1041 return (-1);
1042 break;
1043 case T_TXT:
1044 if ((n = charstr(rr->rdata.TXT, *pbuf, rdlen)) == -1)
1045 return (-1);
1046 break;
1047 case T_NS:
1048 if (rr_parse_dname(*pbuf, *len,
1049 rr->rdata.NS) == -1)
1050 return (-1);
1051 break;
1052 case T_SRV:
1053 buf = *pbuf;
1054 tmplen = *len;
1055 GETSHORT(rr->rdata.SRV.priority, buf);
1056 tmplen -= INT16SZ;
1057 GETSHORT(rr->rdata.SRV.weight, buf);
1058 tmplen -= INT16SZ;
1059 GETSHORT(rr->rdata.SRV.port, buf);
1060 tmplen -= INT16SZ;
1061 if (rr_parse_dname(buf, tmplen, rr->rdata.SRV.target) == -1)
1062 return (-1);
1063 break;
1064 case T_AAAA:
1065 case T_NSEC:
1066 break;
1067 case T_OPT:
1068 /*
1069 * We need 8 bytes for the OPT RR frame.
1070 * See RFC 2671, 4.3.
1071 */
1072 if (*len < 8) {
1073 log_warnx("Bad T_OPT length");
1074 return (-1);
1075 }
1076
1077 /* sender's UDP payload size */
1078 GETSHORT(pl, *pbuf);
1079 *len -= INT16SZ;
1080 /* extended RCODE and flags */
1081 GETLONG(erc, *pbuf);
1082 *len -= INT32SZ;
1083 /* describes RDATA */
1084 GETSHORT(us, *pbuf);
1085 *len -= INT16SZ;
1086 if (*len < us) {
1087 log_warnx("Bad T_OPT RDATA length");
1088 return (-1);
1089 }
1090
1091 /* Parse RDATA sections. */
1092
1093 for (j = 0, i = 0; i < us; j++) {
1094 GETSHORT(code, *pbuf);
1095 *len -= INT16SZ;
1096 i += INT16SZ;
1097 GETSHORT(plen, *pbuf);
1098 *len -= INT16SZ;
1099 i += INT16SZ;
1100 if (us - i < plen) {
1101 log_warnx("Bad T_OPT RDATA "
1102 "section %zu length", j);
1103 return (-1);
1104 }
1105
1106 if (4 == code)
1107 log_debug("pkt_parse_rr: "
1108 "edns0 \'owner-option\'");
1109 else
1110 log_warnx("Unknown T_OPT RDATA "
1111 "section %zu code %u",
1112 j, code);
1113
1114 *pbuf += plen;
1115 *len -= plen;
1116 i += plen;
1117 }
1118
1119 rr->flags = 0;
1120 rr->ttl = 0;
1121 break;
1122 default:
1123 log_debug("Unknown record type %u", rr->rrs.type);
1124 return (-1);
1125 break;
1126 }
1127
1128 *len -= rdlen;
1129 *pbuf += rdlen;
1130
1131 return (0);
1132 }
1133
1134 int
pkt_handle_qst(struct pkt * pkt)1135 pkt_handle_qst(struct pkt *pkt)
1136 {
1137 struct question *qst, *lqst;
1138 struct rr *rr, *rrcopy, *rr_aux;
1139 struct pkt sendpkt;
1140 struct sockaddr_in dst, *pdst;
1141 struct cache_node *cn;
1142 int probe;
1143
1144 /* TODO: Mdns draft 6.3 Duplicate Question Suppression */
1145
1146 pkt_init(&sendpkt);
1147 sendpkt.h.qr = MDNS_RESPONSE;
1148 sendpkt.iface = pkt->iface;
1149 bzero(&dst, sizeof(dst));
1150 pdst = NULL;
1151
1152 /* If legacy packet, we must copy id and answer as unicast dns */
1153 if (pkt->flags & PKT_FLAG_LEGACY) {
1154 sendpkt.flags = pkt->flags;
1155 sendpkt.h.id = pkt->h.id;
1156 dst = pkt->ipsrc;
1157 pdst = &dst;
1158 }
1159
1160 while ((qst = LIST_FIRST(&pkt->qlist)) != NULL) {
1161 /*
1162 * XXX: This assumes that every question came from the same
1163 * packet, hence, the same source. It also assumes QU questions
1164 * may not be mixed up with QM questions, maybe this flag should
1165 * be moved to pkt.
1166 */
1167 if (qst->flags & QST_FLAG_UNIRESP) {
1168 dst = pkt->ipsrc;
1169 pdst = &dst;
1170 }
1171
1172 /* Check if it's a probe */
1173 probe = 0;
1174 LIST_FOREACH(rr, &pkt->nslist, pentry) {
1175 if (ANSWERS(&qst->rrs, &rr->rrs))
1176 probe = 1;
1177 }
1178
1179 /*
1180 * CACHE_FOREACH_DNAME instead of CACHE_FOREACH_RRS so that in
1181 * future we can do conflict resolving. Which needs to answer a
1182 * T_ANY.
1183 */
1184 CACHE_FOREACH_DNAME(rr, cn, qst->rrs.dname) {
1185 /* Look only for authority records */
1186 if (!RR_AUTH(rr))
1187 continue;
1188 /* RR must answer question */
1189 if (!ANSWERS(&qst->rrs, &rr->rrs))
1190 continue;
1191 /* If not a probe, skip unpublished */
1192 if (!probe &&
1193 ((rr->flags & RR_FLAG_PUBLISHED) == 0))
1194 continue;
1195 /* Sanity check */
1196 if (probe && pkt->flags & PKT_FLAG_LEGACY) {
1197 log_warnx("Packet considered probe and legacy, "
1198 "dropping (%s)", rrs_str(&qst->rrs));
1199 return (-1);
1200 }
1201 /*
1202 * If this is a probe and we have a conflict record
1203 * which isn't published yet, do a conflict tie break.
1204 */
1205 if (probe && (rr->flags & RR_FLAG_PUBLISHED) == 0) {
1206 log_warnx("Conflict tie break for %s",
1207 rrs_str(&rr->rrs));
1208 ; /* TODO Tie break */
1209 return (-1);
1210 }
1211
1212 /*
1213 * So we have an answer, see if we're listed in the
1214 * known answer supression list
1215 */
1216 if (!probe) {
1217 LIST_FOREACH(rr_aux, &pkt->anlist, pentry) {
1218 if (rr_rdata_cmp(rr, rr_aux) == 0 &&
1219 rr_aux->ttl > (rr->ttl / 2)) {
1220 /* Supress this answer */
1221 goto supress;
1222 }
1223 }
1224 }
1225 /* If we got here we're commited to answering */
1226 if (probe)
1227 log_warnx("Simple conflict for %s",
1228 rrs_str(&rr->rrs));
1229
1230 /* Make a copy since we may modify if PKT_F_LEGACY */
1231 rrcopy = rr_dup(rr);
1232 /*
1233 * If this is a legacy question, get a copy rr, remove
1234 * the cacheflush bit and copy the qid from question.
1235 */
1236 if (pkt->flags & PKT_FLAG_LEGACY) {
1237 /* Include a copy of question */
1238 if ((lqst = calloc(1, sizeof(*lqst))) == NULL)
1239 fatal("calloc");
1240 /* No flags, since we don't want any bits set */
1241 lqst->flags = 0;
1242 lqst->rrs = qst->rrs;
1243 pkt_add_question(&sendpkt, lqst);
1244 rrcopy->flags &= ~RR_FLAG_CACHEFLUSH;
1245 /* Draft says up to 10 */
1246 rrcopy->ttl = 8;
1247 }
1248 /* Add to response packet */
1249 pkt_add_anrr(&sendpkt, rrcopy);
1250 supress: ;
1251 }
1252 LIST_REMOVE(qst, entry);
1253 free(qst);
1254 }
1255
1256 /*
1257 * If we have answers, send it.
1258 */
1259 if (sendpkt.h.ancount > 0)
1260 if (pkt_sendto(&sendpkt, sendpkt.iface, pdst) == -1)
1261 log_warnx("Can't send packet to"
1262 "%s", pkt->iface->name);
1263
1264 /* Cleanup our pkt since the RRs were dupped */
1265 pkt_cleanup(&sendpkt);
1266
1267 return (0);
1268 }
1269
1270 int
rr_parse_dname(u_int8_t * buf,u_int16_t len,char dname[MAXHOSTNAMELEN])1271 rr_parse_dname(u_int8_t *buf, u_int16_t len, char dname[MAXHOSTNAMELEN])
1272 {
1273 if (pkt_parse_dname(buf, len, dname) == -1) {
1274 log_warnx("rr_parse_dname: pkt_parse_dname error");
1275 return (-1);
1276 }
1277
1278 return (0);
1279 }
1280
1281 ssize_t
serialize_dname(u_int8_t * buf,u_int16_t len,char dname[MAXHOSTNAMELEN],int compress)1282 serialize_dname(u_int8_t *buf, u_int16_t len, char dname[MAXHOSTNAMELEN],
1283 int compress)
1284 {
1285 char *end;
1286 char *dbuf = dname;
1287 u_int8_t tlen;
1288 u_int8_t *pbuf = buf;
1289 struct namecomp *nc;
1290
1291 /* Try to compress this name */
1292
1293 if (compress &&
1294 (nc = pktcomp_lookup(dname)) != NULL) {
1295 PUTSHORT(nc->offset, pbuf);
1296 len -= INT16SZ;
1297 return (pbuf - buf);
1298 }
1299
1300 do {
1301 if ((end = strchr(dbuf, '.')) == NULL) {
1302 if ((end = strchr(dbuf, '\0')) == NULL)
1303 fatalx("serialize_dname: bad dname");
1304 }
1305
1306 tlen = end - dbuf;
1307 *pbuf++ = tlen;
1308 if (tlen > len)
1309 return (-1);
1310 memcpy(pbuf, dbuf, tlen);
1311 len -= tlen;
1312 pbuf += tlen;
1313 dbuf = end + 1;
1314 } while (*end != '\0');
1315
1316 if (len == 0)
1317 return (-1);
1318 *pbuf++ = '\0'; /* null terminate dname */
1319 len--;
1320
1321 /*
1322 * Add dname to name compression, buf - pktcomp->start, should give us
1323 * the correct offset in the current packet.
1324 */
1325 if (compress)
1326 if (pktcomp_add(dname, (u_int16_t) (buf - pktcomp.start))
1327 == -1)
1328 log_warnx("pktcomp_add error: %s", dname);
1329
1330 return (pbuf - buf);
1331 }
1332
1333 ssize_t
serialize_rdata(struct rr * rr,u_int8_t * buf,u_int16_t len)1334 serialize_rdata(struct rr *rr, u_int8_t *buf, u_int16_t len)
1335 {
1336 u_int8_t *prdlen, *pbuf = buf;
1337 ssize_t n;
1338 u_int16_t rdlen = 0;
1339 u_int8_t cpulen, oslen;
1340
1341 switch (rr->rrs.type) {
1342 case T_HINFO:
1343 cpulen = strlen(rr->rdata.HINFO.cpu);
1344 oslen = strlen(rr->rdata.HINFO.os);
1345 rdlen = cpulen + oslen + 2; /* 2 length octets */
1346 if (len < rdlen)
1347 return (-1);
1348 PUTSHORT(rdlen, pbuf);
1349 len -= 2;
1350 /* fill cpu */
1351 *pbuf++ = cpulen;
1352 len--;
1353 memcpy(pbuf, rr->rdata.HINFO.cpu, cpulen);
1354 pbuf += cpulen;
1355 len -= cpulen;
1356 /* fill os */
1357 *pbuf++ = oslen;
1358 len--;
1359 memcpy(pbuf, rr->rdata.HINFO.os, oslen);
1360 pbuf += oslen;
1361 len -= oslen;
1362 break;
1363 case T_PTR:
1364 case T_TXT:
1365 prdlen = pbuf;
1366 /* jump over rdlen */
1367 pbuf += INT16SZ;
1368 len -= INT16SZ;
1369 /* NOTE rr->rdata.PTR == rr->rdata.TXT */
1370 if ((n = serialize_dname(pbuf, len,
1371 rr->rdata.PTR, 1)) == -1)
1372 return (-1);
1373 rdlen = n;
1374 pbuf += rdlen;
1375 len -= rdlen;
1376 PUTSHORT(rdlen, prdlen);
1377 break;
1378 case T_A:
1379 rdlen = INT32SZ;
1380 if (len < (rdlen + INT16SZ)) /* INT16SZ is rdlen itself */
1381 return (-1);
1382 PUTSHORT(rdlen, pbuf);
1383 len -= 2;
1384 memcpy(pbuf, &rr->rdata, rdlen);
1385 pbuf += rdlen;
1386 len -= rdlen;
1387 break;
1388 case T_SRV:
1389 prdlen = pbuf;
1390 /* jump over rdlen */
1391 if (len < INT16SZ)
1392 return (-1);
1393 pbuf += INT16SZ;
1394 len -= INT16SZ;
1395 if (len < INT16SZ * 3)
1396 return (-1);
1397 PUTSHORT(rr->rdata.SRV.priority, pbuf);
1398 len -= INT16SZ;
1399 rdlen += INT16SZ;
1400 PUTSHORT(rr->rdata.SRV.weight, pbuf);
1401 len -= INT16SZ;
1402 rdlen += INT16SZ;
1403 PUTSHORT(rr->rdata.SRV.port, pbuf);
1404 len -= INT16SZ;
1405 rdlen += INT16SZ;
1406 if ((n = serialize_dname(pbuf, len,
1407 rr->rdata.SRV.target, 0)) == -1)
1408 return (-1);
1409 rdlen += n;
1410 pbuf += n;
1411 len -= n;
1412 PUTSHORT(rdlen, prdlen);
1413 break;
1414 default:
1415 log_warnx("serialize_rdata: Don't know how to serialize %s (%d)",
1416 rr_type_name(rr->rrs.type), rr->rrs.type);
1417 return (-1);
1418 break; /* NOTREACHED */
1419 }
1420 return (pbuf - buf);
1421 }
1422
1423 ssize_t
serialize_rr(struct rr * rr,u_int8_t * buf,u_int16_t len)1424 serialize_rr(struct rr *rr, u_int8_t *buf, u_int16_t len)
1425 {
1426 u_int8_t *pbuf = buf;
1427 u_int16_t us = 0;
1428 ssize_t n;
1429
1430 n = serialize_dname(pbuf, len, rr->rrs.dname, 1);
1431 if (n == -1 || n > len)
1432 return (-1);
1433 pbuf += n;
1434 len -= n;
1435 if (len == 0)
1436 return (-1);
1437
1438 if (len < 8) /* must fit type, class, ttl */
1439 return (-1);
1440 PUTSHORT(rr->rrs.type, pbuf);
1441 us = rr->rrs.class;
1442 if (rr->flags & RR_FLAG_CACHEFLUSH)
1443 us |= CACHEFLUSH_MSK;
1444 PUTSHORT(us, pbuf);
1445 PUTLONG(rr->ttl, pbuf);
1446 len -= 8;
1447
1448 n = serialize_rdata(rr, pbuf, len);
1449 if (n == -1 || n > len)
1450 return (-1);
1451 pbuf += n;
1452 len -= n;
1453
1454 return (pbuf - buf);
1455 }
1456
1457 ssize_t
serialize_qst(struct question * qst,u_int8_t * buf,u_int16_t len)1458 serialize_qst(struct question *qst, u_int8_t *buf, u_int16_t len)
1459 {
1460 u_int8_t *pbuf = buf;
1461 u_int16_t qclass;
1462 ssize_t n;
1463
1464 n = serialize_dname(pbuf, len, qst->rrs.dname, 1);
1465 if (n == -1 || n > len)
1466 return (-1);
1467 pbuf += n;
1468 len -= n;
1469 if (len == 0)
1470 return (-1);
1471
1472 if (len < 4) /* must fit type, class */
1473 return (-1);
1474 PUTSHORT(qst->rrs.type, pbuf);
1475
1476 qclass = qst->rrs.class;
1477 if (qst->flags & QST_FLAG_UNIRESP)
1478 qclass = qst->rrs.class | UNIRESP_MSK;
1479 PUTSHORT(qclass, pbuf);
1480
1481 return (pbuf - buf);
1482 }
1483
1484 void
header_htons(HEADER * h)1485 header_htons(HEADER *h)
1486 {
1487 h->qdcount = htons(h->qdcount);
1488 h->ancount = htons(h->ancount);
1489 h->nscount = htons(h->nscount);
1490 h->arcount = htons(h->arcount);
1491 }
1492
1493 void
header_ntohs(HEADER * h)1494 header_ntohs(HEADER *h)
1495 {
1496 h->qdcount = ntohs(h->qdcount);
1497 h->ancount = ntohs(h->ancount);
1498 h->nscount = ntohs(h->nscount);
1499 h->arcount = ntohs(h->arcount);
1500 }
1501
1502 /* Packet compression */
1503 void
pktcomp_reset(int first,u_int8_t * start,u_int16_t len)1504 pktcomp_reset(int first, u_int8_t *start, u_int16_t len)
1505 {
1506 struct namecomp *nc;
1507
1508 while ((nc = LIST_FIRST(&pktcomp.namecomp_list)) != NULL) {
1509 LIST_REMOVE(nc, entry);
1510 free(nc);
1511 }
1512 pktcomp.start = start;
1513 pktcomp.len = len;
1514 }
1515
1516 int
pktcomp_add(char dname[MAXHOSTNAMELEN],u_int16_t offset)1517 pktcomp_add(char dname[MAXHOSTNAMELEN], u_int16_t offset)
1518 {
1519 struct namecomp *nc;
1520
1521 if ((nc = calloc(1, sizeof(*nc))) == NULL)
1522 fatal("calloc");
1523 strlcpy(nc->dname, dname, sizeof(nc->dname));
1524 nc->offset = offset | NAMECOMP_MSK;
1525 LIST_INSERT_HEAD(&pktcomp.namecomp_list, nc, entry);
1526
1527 return (0);
1528 }
1529
1530 struct namecomp *
pktcomp_lookup(char dname[MAXHOSTNAMELEN])1531 pktcomp_lookup(char dname[MAXHOSTNAMELEN])
1532 {
1533 struct namecomp *nc;
1534
1535 LIST_FOREACH(nc, &pktcomp.namecomp_list, entry) {
1536 if (strcmp(nc->dname, dname) == 0)
1537 return (nc);
1538 }
1539
1540 return (NULL);
1541 }
1542
1543 /* Util */
1544 ssize_t
charstr(char dest[MAXCHARSTR],u_int8_t * buf,u_int16_t len)1545 charstr(char dest[MAXCHARSTR], u_int8_t *buf, u_int16_t len)
1546 {
1547 u_int8_t tocpy;
1548
1549 tocpy = *buf++;
1550
1551 if (tocpy > len) {
1552 log_debug("tocpy: %u > len: %u", tocpy, len);
1553 return (-1);
1554 }
1555
1556 /* This isn't a case for strlcpy */
1557 memcpy(dest, buf, tocpy);
1558 dest[tocpy] = '\0'; /* Assure null terminated */
1559
1560 return (tocpy + 1);
1561 }
1562