@@ -157,6 +157,9 @@ void dns_packet_answer(const char *name, int type, const uint8_t *rdata, uint16_
157157 pkt .h .flags |= cpu_to_be16 (0x8400 );
158158
159159 a = dns_packet_record_add (sizeof (* a ) + rdlength , name );
160+ if (!a )
161+ return ;
162+
160163 memset (a , 0 , sizeof (* a ));
161164 a -> type = cpu_to_be16 (type );
162165 a -> class = cpu_to_be16 (1 );
@@ -266,7 +269,7 @@ void dns_query(const char *name, uint16_t type)
266269}
267270
268271void
269- dns_reply_a (struct interface * iface , struct sockaddr * to , int ttl , const char * hostname )
272+ dns_reply_a (struct interface * iface , struct sockaddr * to , int ttl , const char * hostname , bool append )
270273{
271274 struct ifaddrs * ifap , * ifa ;
272275 struct sockaddr_in * sa ;
@@ -277,7 +280,9 @@ dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *h
277280
278281 getifaddrs (& ifap );
279282
280- dns_packet_init ();
283+ if (!append )
284+ dns_packet_init ();
285+
281286 for (ifa = ifap ; ifa ; ifa = ifa -> ifa_next ) {
282287 if (strcmp (ifa -> ifa_name , iface -> name ))
283288 continue ;
@@ -292,16 +297,17 @@ dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *h
292297 }
293298 freeifaddrs (ifap );
294299
295- dns_packet_send (iface , to , 0 , 0 );
300+ if (!append )
301+ dns_packet_send (iface , to , 0 , 0 );
296302}
297303
298304void
299- dns_reply_a_additional (struct interface * iface , struct sockaddr * to , int ttl )
305+ dns_reply_a_additional (struct interface * iface , struct sockaddr * to , int ttl , bool append )
300306{
301307 struct hostname * h ;
302308
303309 vlist_for_each_element (& hostnames , h , node )
304- dns_reply_a (iface , to , ttl , h -> hostname );
310+ dns_reply_a (iface , to , ttl , h -> hostname , append );
305311}
306312
307313static int
@@ -484,7 +490,8 @@ match_ip_addresses(char *reverse_ip, char *intf_ip)
484490}
485491
486492static void
487- dns_reply_reverse_ip6_mapping (struct interface * iface , struct sockaddr * to , int ttl , char * name , char * reverse_ip )
493+ dns_reply_reverse_ip6_mapping (struct interface * iface , struct sockaddr * to , int ttl , char * name , char * reverse_ip ,
494+ bool append )
488495{
489496 struct ifaddrs * ifap , * ifa ;
490497 struct sockaddr_in6 * sa6 ;
@@ -494,7 +501,10 @@ dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int
494501 int len ;
495502
496503 getifaddrs (& ifap );
497- dns_packet_init ();
504+
505+ if (!append )
506+ dns_packet_init ();
507+
498508 for (ifa = ifap ; ifa ; ifa = ifa -> ifa_next ) {
499509 if (strcmp (ifa -> ifa_name , iface -> name ))
500510 continue ;
@@ -513,13 +523,16 @@ dns_reply_reverse_ip6_mapping(struct interface *iface, struct sockaddr *to, int
513523 }
514524 }
515525 }
516- dns_packet_send (iface , to , 0 , 0 );
526+
527+ if (!append )
528+ dns_packet_send (iface , to , 0 , 0 );
517529
518530 freeifaddrs (ifap );
519531}
520532
521533static void
522- dns_reply_reverse_ip4_mapping (struct interface * iface , struct sockaddr * to , int ttl , char * name , char * reverse_ip )
534+ dns_reply_reverse_ip4_mapping (struct interface * iface , struct sockaddr * to , int ttl , char * name , char * reverse_ip ,
535+ bool append )
523536{
524537 struct ifaddrs * ifap , * ifa ;
525538 struct sockaddr_in * sa ;
@@ -529,7 +542,10 @@ dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int
529542 int len ;
530543
531544 getifaddrs (& ifap );
532- dns_packet_init ();
545+
546+ if (!append )
547+ dns_packet_init ();
548+
533549 for (ifa = ifap ; ifa ; ifa = ifa -> ifa_next ) {
534550 if (strcmp (ifa -> ifa_name , iface -> name ))
535551 continue ;
@@ -548,7 +564,8 @@ dns_reply_reverse_ip4_mapping(struct interface *iface, struct sockaddr *to, int
548564 }
549565 }
550566 }
551- dns_packet_send (iface , to , 0 , 0 );
567+ if (!append )
568+ dns_packet_send (iface , to , 0 , 0 );
552569
553570 freeifaddrs (ifap );
554571}
@@ -572,7 +589,7 @@ is_reverse_dns_query(const char *name, const char *suffix)
572589}
573590
574591static void
575- parse_question (struct interface * iface , struct sockaddr * from , char * name , struct dns_question * q )
592+ parse_question (struct interface * iface , struct sockaddr * from , char * name , struct dns_question * q , bool append )
576593{
577594 int is_unicast = (q -> class & CLASS_UNICAST ) != 0 ;
578595 struct sockaddr * to = NULL ;
@@ -581,19 +598,22 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
581598
582599 /* TODO: Multicast if more than one quarter of TTL has passed */
583600 if (is_unicast ) {
584- to = from ;
585- if (interface_multicast (iface ))
586- iface = interface_get (iface -> name , iface -> type | SOCKTYPE_BIT_UNICAST );
601+ /* if append is true we have already done this */
602+ if (!append ) {
603+ to = from ;
604+ if (interface_multicast (iface ))
605+ iface = interface_get (iface -> name , iface -> type | SOCKTYPE_BIT_UNICAST );
606+ }
587607 }
588608
589609 DBG (1 , "Q -> %s %s\n" , dns_type_string (q -> type ), name );
590610
591611 switch (q -> type ) {
592612 case TYPE_ANY :
593613 if (!strcasecmp (name , mdns_hostname_local )) {
594- dns_reply_a (iface , to , announce_ttl , NULL );
595- dns_reply_a_additional (iface , to , announce_ttl );
596- service_reply (iface , to , NULL , NULL , announce_ttl , is_unicast );
614+ dns_reply_a (iface , to , announce_ttl , NULL , append );
615+ dns_reply_a_additional (iface , to , announce_ttl , append );
616+ service_reply (iface , to , NULL , NULL , announce_ttl , is_unicast , append );
597617 }
598618 break ;
599619
@@ -603,7 +623,7 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
603623 char name_buf [256 ];
604624 strcpy (name_buf , name );
605625 * host = '\0' ;
606- dns_reply_reverse_ip4_mapping (iface , to , announce_ttl , name_buf , name );
626+ dns_reply_reverse_ip4_mapping (iface , to , announce_ttl , name_buf , name , append );
607627 break ;
608628 }
609629
@@ -612,22 +632,22 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
612632 char name_buf6 [256 ];
613633 strcpy (name_buf6 , name );
614634 * host6 = '\0' ;
615- dns_reply_reverse_ip6_mapping (iface , to , announce_ttl , name_buf6 , name );
635+ dns_reply_reverse_ip6_mapping (iface , to , announce_ttl , name_buf6 , name , append );
616636 break ;
617637 }
618638
619639 if (!strcasecmp (name , C_DNS_SD )) {
620- service_announce_services (iface , to , announce_ttl );
640+ service_announce_services (iface , to , announce_ttl , append );
621641 } else {
622642 if (name [0 ] == '_' ) {
623- service_reply (iface , to , NULL , name , announce_ttl , is_unicast );
643+ service_reply (iface , to , NULL , name , announce_ttl , is_unicast , append );
624644 } else {
625645 /* First dot separates instance name from the rest */
626646 char * dot = strchr (name , '.' );
627647
628648 if (dot ) {
629649 * dot = '\0' ;
630- service_reply (iface , to , name , dot + 1 , announce_ttl , is_unicast );
650+ service_reply (iface , to , name , dot + 1 , announce_ttl , is_unicast , append );
631651 * dot = '.' ;
632652 }
633653 }
@@ -640,34 +660,81 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
640660 if (host )
641661 * host = '\0' ;
642662 if (!strcasecmp (umdns_host_label , name )) {
643- dns_reply_a (iface , to , announce_ttl , NULL );
663+ dns_reply_a (iface , to , announce_ttl , NULL , append );
644664 } else {
645665 if (host )
646666 * host = '.' ;
647667 vlist_for_each_element (& hostnames , h , node )
648668 if (!strcasecmp (h -> hostname , name ))
649- dns_reply_a (iface , to , announce_ttl , h -> hostname );
669+ dns_reply_a (iface , to , announce_ttl , h -> hostname , append );
650670 }
651671 break ;
652672 };
653673}
654674
675+ static void
676+ dns_append_questions (uint8_t * orig_buffer , int orig_len )
677+ {
678+ /* Construct original question section */
679+ const struct dns_header * orig_h ;
680+ uint8_t * ptr = orig_buffer ;
681+ int len = orig_len ;
682+
683+ orig_h = dns_consume_header (& ptr , & len );
684+ if (orig_h ) {
685+ pkt .h .id = cpu_to_be16 (orig_h -> id );
686+
687+ uint16_t q_count = be16_to_cpu (orig_h -> questions );
688+ while (q_count -- > 0 && len > 0 ) {
689+ char * qname = dns_consume_name (orig_buffer , orig_len , & ptr , & len );
690+ if (!qname || len < (int )sizeof (struct dns_question ))
691+ break ;
692+
693+ struct dns_question * q = dns_consume_question (& ptr , & len );
694+ if (!q )
695+ break ;
696+
697+ dns_packet_question (qname , q -> type );
698+ }
699+ }
700+ }
701+
655702void
656703dns_handle_packet (struct interface * iface , struct sockaddr * from , uint16_t port , uint8_t * buffer , int len )
657704{
658705 struct dns_header * h ;
659706 uint8_t * b = buffer ;
660707 int rlen = len ;
708+ uint8_t orig_buffer [len ];
709+ struct sockaddr * to = NULL ;
710+ bool append = false;
711+
712+ /* make a copy of the original buffer since it might be needed to construct the answer
713+ * in case the query is received from a one-shot multicast dns querier */
714+ memcpy (orig_buffer , buffer , len );
661715
662716 h = dns_consume_header (& b , & rlen );
663717 if (!h ) {
664718 fprintf (stderr , "dropping: bad header\n" );
665719 return ;
666720 }
667721
668- if (h -> questions && !interface_multicast (iface ) && port != MCAST_PORT )
669- /* silently drop unicast questions that dont originate from port 5353 */
670- return ;
722+ /* legacy querier */
723+ if (port != MCAST_PORT ) {
724+ /* aggregate answers and send, instead of sending separately */
725+ append = true;
726+
727+ /* packet construction starts here */
728+ dns_packet_init ();
729+
730+ /* add original questions, as required by unicast DNS RFC */
731+ dns_append_questions (orig_buffer , len );
732+
733+ /* to return a unicast response */
734+ to = from ;
735+ if (interface_multicast (iface ))
736+ iface = interface_get (iface -> name , iface -> type | SOCKTYPE_BIT_UNICAST );
737+ }
671738
672739 while (h -> questions -- > 0 ) {
673740 char * name = dns_consume_name (buffer , len , & b , & rlen );
@@ -685,9 +752,13 @@ dns_handle_packet(struct interface *iface, struct sockaddr *from, uint16_t port,
685752 }
686753
687754 if (!(h -> flags & FLAG_RESPONSE ))
688- parse_question (iface , from , name , q );
755+ parse_question (iface , from , name , q , append );
689756 }
690757
758+ /* if append is true, then answers have only been appended to the packet, not sent, so we do that here */
759+ if (append && pkt .h .answers > 0 )
760+ dns_packet_send (iface , to , 0 , 0 );
761+
691762 if (!(h -> flags & FLAG_RESPONSE ))
692763 return ;
693764
0 commit comments