1 /* dnssd-proxy.c
2  *
3  * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * This is a Discovery Proxy module for the SRP gateway.
18  *
19  * The motivation here is that it makes sense to co-locate the SRP relay and the Discovery Proxy because
20  * these functions are likely to co-exist on the same node, listening on the same port.  For homenet-style
21  * name resolution, we need a DNS proxy that implements DNSSD Discovery Proxy for local queries, but
22  * forwards other queries to an ISP resolver.  The SRP gateway is already expecting to do this.
23  * This module implements the functions required to allow the SRP gateway to also do Discovery Relay.
24  *
25  * The Discovery Proxy relies on Apple's DNS-SD library and the mDNSResponder DNSSD server, which is included
26  * in Apple's open source mDNSResponder package, available here:
27  *
28  *            https://opensource.apple.com/tarballs/mDNSResponder/
29  */
30 
31 #define __APPLE_USE_RFC_3542
32 
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <fcntl.h>
42 #include <sys/time.h>
43 #include <ctype.h>
44 #include <sys/types.h>
45 #include <ifaddrs.h>
46 #include <net/if.h>
47 #include <stdarg.h>
48 
49 #include "dns_sd.h"
50 #include "srp.h"
51 #include "dns-msg.h"
52 #include "srp-crypto.h"
53 #define DNSMessageHeader dns_wire_t
54 #include "dso.h"
55 #include "ioloop.h"
56 #include "srp-tls.h"
57 #include "config-parse.h"
58 
59 // Enumerate the list of interfaces, map them to interface indexes, give each one a name
60 // Have a tree of subdomains for matching
61 
62 // Configuration file settings
63 uint16_t udp_port;
64 uint16_t tcp_port;
65 uint16_t tls_port;
66 char *my_name = "discoveryproxy.home.arpa.";
67 #define MAX_ADDRS 10
68 char *listen_addrs[MAX_ADDRS];
69 int num_listen_addrs = 0;
70 char *publish_addrs[MAX_ADDRS];
71 int num_publish_addrs = 0;
72 char *tls_cacert_filename = NULL;
73 char *tls_cert_filename = "/etc/dnssd-proxy/server.crt";
74 char *tls_key_filename = "/etc/dnssd-proxy/server.key";
75 comm_t *listener[4 + MAX_ADDRS];
76 int num_listeners = 0;
77 
78 typedef struct hardwired hardwired_t;
79 struct hardwired {
80     hardwired_t *next;
81     uint16_t type;
82     char *name;
83     char *fullname;
84     uint8_t *rdata;
85     uint16_t rdlen;
86 };
87 
88 typedef struct interface_addr interface_addr_t;
89 struct interface_addr {
90     interface_addr_t *next;
91     addr_t addr, mask;
92 };
93 
94 typedef struct interface interface_t;
95 struct interface {
96     int ifindex;                        // The interface index (for use with sendmsg() and recvmsg().
97     bool no_push;                       // If true, don't set up DNS Push for this domain
98     char *name;                         // The name of the interface
99     interface_addr_t *addresses;        // Addresses on this interface.
100 };
101 
102 typedef struct served_domain served_domain_t;
103 struct served_domain {
104     served_domain_t *next;              // Active configurations, used for identifying a domain that matches
105     char *domain;                       // The domain name of the interface, represented as a text string.
106     char *domain_ld;                    // The same name, with a leading dot (if_domain_lp == if_domain + 1)
107     dns_name_t *domain_name;            // The domain name, parsed into labels.
108     hardwired_t *hardwired_responses;   // Hardwired responses for this interface
109     struct interface *interface;        // Interface to which this domain applies (may be NULL).
110 } *served_domains;
111 
112 typedef struct dnssd_query {
113     dnssd_txn_t *txn;
114     wakeup_t *wakeup;
115     char *name;                     // The name we are looking up.
116     served_domain_t *served_domain; // If this query matches an enclosing domain, the domain that matched.
117 
118                                     // If we've already copied out the enclosing domain once in a DNS message.
119     dns_name_pointer_t enclosing_domain_pointer;
120 
121     message_t *question;
122     comm_t *connection;
123     dso_activity_t *activity;
124     int serviceFlags;               // Service flags to use with this query.
125     bool is_dns_push;
126     bool is_edns0;
127     uint16_t type, qclass;          // Original query type and class.
128     dns_towire_state_t towire;
129     uint8_t *p_dso_length;          // Where to store the DSO length just before we write out a push notification.
130     dns_wire_t *response;
131     size_t data_size;		        // Size of the data payload of the response
132 } dnssd_query_t;
133 
134 const char push_subscription_activity_type[] = "push subscription";
135 
136 const char local_suffix[] = ".local.";
137 
138 #define TOWIRE_CHECK(note, towire, func) { func; if ((towire)->error != 0 && failnote == NULL) failnote = (note); }
139 
140 // Forward references
141 static served_domain_t *NULLABLE new_served_domain(interface_t *NULLABLE interface, char *NONNULL domain);
142 
143 // Code
144 
dso_transport_idle(void * context,int64_t now,int64_t next_event)145 int64_t dso_transport_idle(void *context, int64_t now, int64_t next_event)
146 {
147     return next_event;
148 }
149 
dnssd_query_cancel(dnssd_query_t * query)150 void dnssd_query_cancel(dnssd_query_t *query)
151 {
152     if (query->txn != NULL) {
153         ioloop_dnssd_txn_cancel(query->txn);
154         ioloop_dnssd_txn_release(query->txn);
155         query->txn = NULL;
156     }
157     query->connection = NULL;
158 }
159 
dnssd_query_close_callback(void * context,int status)160 void dnssd_query_close_callback(void *context, int status)
161 {
162     dnssd_query_t *query = context;
163 
164     ERROR("DNSServiceProcessResult on %s%s returned %d",
165           query->name, (query->served_domain != NULL
166                       ? (query->served_domain->interface != NULL ? ".local" : query->served_domain->domain_ld)
167                       : ""), status);
168     if (query->activity != NULL && query->connection != NULL) {
169         dso_drop_activity(query->connection->dso, query->activity);
170     } else {
171         dnssd_query_cancel(query);
172     }
173 }
174 
175 void
dns_push_finalize(dso_activity_t * activity)176 dns_push_finalize(dso_activity_t *activity)
177 {
178     dnssd_query_t *query = (dnssd_query_t *)activity->context;
179     INFO("dnssd_push_finalize: " PUB_S_SRP, activity->name);
180     dnssd_query_cancel(query);
181 }
182 
183 void
dnssd_query_finalize_callback(void * context)184 dnssd_query_finalize_callback(void *context)
185 {
186     dnssd_query_t *query = context;
187     INFO("dnssd_query_finalize on " PRI_S_SRP PUB_S_SRP,
188          query->name, (query->served_domain
189                        ? (query->served_domain->interface ? ".local" : query->served_domain->domain_ld)
190                        : ""));
191     if (query->txn) {
192         ioloop_dnssd_txn_cancel(query->txn);
193         ioloop_dnssd_txn_release(query->txn);
194         query->txn = NULL;
195     }
196     if (query->question) {
197         message_free(query->question);
198     }
199     free(query->name);
200     free(query);
201 }
202 
203 void
dp_simple_response(comm_t * comm,int rcode)204 dp_simple_response(comm_t *comm, int rcode)
205 {
206     if (comm->send_response) {
207         struct iovec iov;
208         dns_wire_t response;
209         memset(&response, 0, DNS_HEADER_SIZE);
210 
211         // We take the ID and the opcode from the incoming message, because if the
212         // header has been mangled, we (a) wouldn't have gotten here and (b) don't
213         // have any better choice anyway.
214         response.id = comm->message->wire.id;
215         dns_qr_set(&response, dns_qr_response);
216         dns_opcode_set(&response, dns_opcode_get(&comm->message->wire));
217         dns_rcode_set(&response, rcode);
218         iov.iov_base = &response;
219         iov.iov_len = DNS_HEADER_SIZE; // No RRs
220         comm->send_response(comm, comm->message, &iov, 1);
221     }
222 }
223 
224 bool
dso_send_formerr(dso_state_t * dso,const dns_wire_t * header)225 dso_send_formerr(dso_state_t *dso, const dns_wire_t *header)
226 {
227     comm_t *transport = dso->transport;
228     (void)header;
229     dp_simple_response(transport, dns_rcode_formerr);
230     return true;
231 }
232 
233 served_domain_t *
dp_served(dns_name_t * name,char * buf,size_t bufsize)234 dp_served(dns_name_t *name, char *buf, size_t bufsize)
235 {
236     served_domain_t *sdt;
237     dns_label_t *lim;
238 
239     for (sdt = served_domains; sdt; sdt = sdt->next) {
240         if ((lim = dns_name_subdomain_of(name, sdt->domain_name))) {
241             dns_name_print_to_limit(name, lim, buf, bufsize);
242             return sdt;
243         }
244     }
245     return NULL;
246 }
247 
248 // Utility function to find "local" on the end of a string of labels.
249 bool
truncate_local(dns_name_t * name)250 truncate_local(dns_name_t *name)
251 {
252     dns_label_t *lp, *prev, *prevprev;
253 
254     prevprev = prev = NULL;
255     // Find the root label.
256     for (lp = name; lp && lp->len; lp = lp->next) {
257         prevprev = prev;
258         prev = lp;
259     }
260     if (lp && prev && prevprev) {
261         if (prev->len == 5 && dns_labels_equal(prev->data, "local", 5)) {
262             dns_name_free(prev);
263             prevprev->next = NULL;
264             return true;
265         }
266     }
267     return false;
268 }
269 
270 void
dp_query_add_data_to_response(dnssd_query_t * query,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,int32_t ttl)271 dp_query_add_data_to_response(dnssd_query_t *query, const char *fullname,
272                               uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, int32_t ttl)
273 {
274     dns_towire_state_t *towire = &query->towire;
275     const char *failnote = NULL;
276     const uint8_t *rd = rdata;
277     char pbuf[DNS_MAX_NAME_SIZE + 1];
278     char rbuf[DNS_MAX_NAME_SIZE + 1];
279     uint8_t *revert = query->towire.p; // Remember where we were in case there's no room.
280     bool local;
281 
282     if (rdlen == 0) {
283         INFO("Eliding zero-length response for " PRI_S_SRP " %d %d", fullname, rrtype, rrclass);
284         return;
285     }
286     // Don't send A records for 127.* nor AAAA records for ::1
287     if (rrtype == dns_rrtype_a && rdlen == 4) {
288         // Should use IN_LINKLOCAL and IN_LOOPBACK macros here, but for some reason they are not present on
289         // OpenWRT.
290         if (rd[0] == 127) {
291             IPv4_ADDR_GEN_SRP(rd, rd_buf);
292             INFO("Eliding localhost response for " PRI_S_SRP ": " PRI_IPv4_ADDR_SRP, fullname,
293                   IPv4_ADDR_PARAM_SRP(rd, rd_buf));
294             return;
295         }
296         if (rd[0] == 169 && rd[1] == 254) {
297             IPv4_ADDR_GEN_SRP(rd, rd_buf);
298             INFO("Eliding link-local response for " PRI_S_SRP ": " PRI_IPv4_ADDR_SRP, fullname,
299                  IPv4_ADDR_PARAM_SRP(rd, rd_buf));
300             return;
301         }
302     } else if (rrtype == dns_rrtype_aaaa && rdlen == 16) {
303         struct in6_addr addr = *(struct in6_addr *)rdata;
304         if (IN6_IS_ADDR_LOOPBACK(&addr)) {
305             SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, rdata_buf);
306             INFO("Eliding localhost response for " PRI_S_SRP ": " PRI_SEGMENTED_IPv6_ADDR_SRP,
307                  fullname, SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, rdata_buf));
308             return;
309         }
310         if (IN6_IS_ADDR_LINKLOCAL(&addr)) {
311             SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, rdata_buf);
312             INFO("Eliding link-local response for " PRI_S_SRP ": " PRI_SEGMENTED_IPv6_ADDR_SRP,
313                  fullname, SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, rdata_buf));
314             return;
315         }
316     }
317     INFO("dp_query_add_data_to_response: survived for rrtype %d rdlen %d", rrtype, rdlen);
318 
319     // Rewrite the domain if it's .local.
320     if (query->served_domain != NULL) {
321         TOWIRE_CHECK("concatenate_name_to_wire", towire,
322                      dns_concatenate_name_to_wire(towire, NULL, query->name, query->served_domain->domain));
323         INFO(PUB_S_SRP " answer:  type %02d class %02d " PRI_S_SRP "." PRI_S_SRP, query->is_dns_push ? "PUSH" : "DNS ",
324              rrtype, rrclass, query->name, query->served_domain->domain);
325     } else {
326         TOWIRE_CHECK("compress_name_to_wire", towire, dns_concatenate_name_to_wire(towire, NULL, NULL, query->name));
327         INFO(PUB_S_SRP " answer:  type %02d class %02d " PRI_S_SRP " (p)",
328              query->is_dns_push ? "push" : " dns", rrtype, rrclass, query->name);
329     }
330     TOWIRE_CHECK("rrtype", towire, dns_u16_to_wire(towire, rrtype));
331     TOWIRE_CHECK("rrclass", towire, dns_u16_to_wire(towire, rrclass));
332     TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, ttl));
333 
334     if (rdlen > 0) {
335         // If necessary, correct domain names inside of rrdata.
336         dns_rr_t answer;
337         dns_name_t *name;
338         unsigned offp = 0;
339 
340         answer.type = rrtype;
341         answer.qclass = rrclass;
342         if (dns_rdata_parse_data(&answer, rdata, &offp, rdlen, rdlen, 0)) {
343             switch(rrtype) {
344             case dns_rrtype_cname:
345             case dns_rrtype_ptr:
346             case dns_rrtype_ns:
347             case dns_rrtype_md:
348             case dns_rrtype_mf:
349             case dns_rrtype_mb:
350             case dns_rrtype_mg:
351             case dns_rrtype_mr:
352             case dns_rrtype_nsap_ptr:
353             case dns_rrtype_dname:
354                 name = answer.data.ptr.name;
355                 TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
356                 break;
357             case dns_rrtype_srv:
358                 name = answer.data.srv.name;
359                 TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
360                 TOWIRE_CHECK("answer.data.srv.priority", towire, dns_u16_to_wire(towire, answer.data.srv.priority));
361                 TOWIRE_CHECK("answer.data.srv.weight", towire, dns_u16_to_wire(towire, answer.data.srv.weight));
362                 TOWIRE_CHECK("answer.data.srv.port", towire, dns_u16_to_wire(towire, answer.data.srv.port));
363                 break;
364             default:
365                 INFO("record type %d not translated", rrtype);
366                 goto raw;
367             }
368 
369             dns_name_print(name, rbuf, sizeof rbuf);
370 
371             // If the name ends in .local, truncate it.
372             if ((local = truncate_local(name))) {
373                 dns_name_print(name, pbuf, sizeof pbuf);
374             }
375 
376             // If the name ended in .local, concatenate the interface domain name to the end.
377             if (local) {
378                 TOWIRE_CHECK("concatenate_name_to_wire 2", towire,
379                              dns_concatenate_name_to_wire(towire, name, NULL, query->served_domain->domain));
380                 INFO("translating " PRI_S_SRP " to " PRI_S_SRP " . " PRI_S_SRP, rbuf, pbuf,
381                      query->served_domain->domain);
382             } else {
383                 TOWIRE_CHECK("concatenate_name_to_wire 2", towire,
384                              dns_concatenate_name_to_wire(towire, name, NULL, NULL));
385                 INFO("compressing " PRI_S_SRP, rbuf);
386             }
387             dns_name_free(name);
388             dns_rdlength_end(towire);
389         } else {
390             ERROR("dp_query_add_data_to_response: rdata from mDNSResponder didn't parse!!");
391         raw:
392             TOWIRE_CHECK("rdlen", towire, dns_u16_to_wire(towire, rdlen));
393             TOWIRE_CHECK("rdata", towire, dns_rdata_raw_data_to_wire(towire, rdata, rdlen));
394         }
395     } else {
396         TOWIRE_CHECK("rdlen", towire, dns_u16_to_wire(towire, rdlen));
397     }
398     if (towire->truncated || failnote) {
399         ERROR("RR ADD FAIL: dp_query_add_data_to_response: " PUB_S_SRP, failnote);
400         query->towire.p = revert;
401     }
402 }
403 
404 void
dnssd_hardwired_add(served_domain_t * sdt,const char * name,const char * domain,size_t rdlen,uint8_t * rdata,uint16_t type)405 dnssd_hardwired_add(served_domain_t *sdt,
406                     const char *name, const char *domain, size_t rdlen, uint8_t *rdata, uint16_t type)
407 {
408     hardwired_t *hp, **hrp;
409     int namelen = strlen(name);
410     size_t total = sizeof *hp;
411     uint8_t *trailer;
412     total += rdlen; // Space for RDATA
413     total += namelen; // Space for name
414     total += 1; // NUL
415     total += namelen;// space for FQDN
416     total += strlen(domain);
417     total += 1; // NUL
418 
419     hp = calloc(1, total + 4);
420     if (hp == NULL) {
421         ERROR("no memory for %s %s", name, domain);
422         return;
423     }
424     trailer = ((uint8_t *)hp) + total;
425     memcpy(trailer, "abcd", 4);
426     hp->rdata = (uint8_t *)(hp + 1);
427     hp->rdlen = rdlen;
428     memcpy(hp->rdata, rdata, rdlen);
429     hp->name = (char *)hp->rdata + rdlen;
430     strcpy(hp->name, name);
431     hp->fullname = hp->name + namelen + 1;
432     if (namelen != 0) {
433         strcpy(hp->fullname, name);
434         strcpy(hp->fullname + namelen, domain);
435     } else {
436         strcpy(hp->fullname, domain);
437     }
438     if (hp->fullname + strlen(hp->fullname) + 1 != (char *)hp + total) {
439         ERROR("%p != %p", hp->fullname + strlen(hp->fullname) + 1, ((char *)hp) + total);
440         return;
441     }
442     if (memcmp(trailer, "abcd", 4)) {
443         ERROR("ran off the end.");
444         return;
445     }
446     hp->type = type;
447     hp->next = NULL;
448 
449     // Store this new hardwired_t at the end of the list unless a hardwired_t with the same name
450     // is already on the list.   If it is, splice it in.
451     for (hrp = &sdt->hardwired_responses; *hrp != NULL; hrp = &(*hrp)->next) {
452         hardwired_t *old = *hrp;
453         if (!strcmp(old->fullname, hp->name) && old->type == hp->type) {
454             INFO("hardwired_add: superseding " PRI_S_SRP " name " PRI_S_SRP " type %d rdlen %d", old->fullname,
455                  old->name, old->type, old->rdlen);
456             hp->next = old->next;
457             free(old);
458             break;
459         }
460     }
461     *hrp = hp;
462 
463     INFO("hardwired_add: fullname " PRI_S_SRP " name " PRI_S_SRP " type %d rdlen %d",
464          hp->fullname, hp->name, hp->type, hp->rdlen);
465 }
466 
dnssd_hardwired_lbdomains_setup(dns_towire_state_t * towire,dns_wire_t * wire)467 void dnssd_hardwired_lbdomains_setup(dns_towire_state_t *towire, dns_wire_t *wire)
468 {
469     served_domain_t *ip6 = NULL, *ipv4 = NULL, *addr_domain, *interface_domain;
470     char name[DNS_MAX_NAME_SIZE + 1];
471 
472 #define RESET \
473     memset(towire, 0, sizeof *towire); \
474     towire->message = wire; \
475     towire->p = wire->data; \
476     towire->lim = towire->p + sizeof wire->data
477 
478     for (addr_domain = served_domains; addr_domain; addr_domain = addr_domain->next) {
479         interface_t *interface = addr_domain->interface;
480         interface_addr_t *ifaddr;
481         if (interface == NULL) {
482             INFO("Domain " PRI_S_SRP " has no interface", addr_domain->domain);
483             continue;
484         }
485         INFO("Interface " PUB_S_SRP, interface->name);
486         // Add lb domain support for link domain
487         for (ifaddr = interface->addresses; ifaddr != NULL; ifaddr = ifaddr->next) {
488             if (ifaddr->addr.sa.sa_family == AF_INET) {
489                 uint8_t *address = (uint8_t *)&(ifaddr->addr.sin.sin_addr);
490                 uint8_t *mask = (uint8_t *)&(ifaddr->mask.sin.sin_addr);
491                 char *bp;
492                 int space = sizeof name;
493                 int i;
494 
495                 if (address[0] == 127) {
496                     INFO("Skipping IPv4 loopback address on " PRI_S_SRP " (" PUB_S_SRP ")",
497                           addr_domain->domain, interface->name);
498                     continue;
499                 }
500 
501                 if (address[0] == 169 && address[1] == 254) {
502                     INFO("Skipping IPv4 link local address on " PRI_S_SRP " (" PUB_S_SRP ")",
503                          addr_domain->domain, interface->name);
504                     continue;
505                 }
506 
507                 snprintf(name, space, "lb._dns-sd._udp");
508                 bp = name + strlen(name);
509                 for (i = 3; i >= 0; i--) {
510                     snprintf(bp, space - (bp - name), ".%d", address[i] & mask[i]);
511                     bp += strlen(bp);
512                 }
513                 if (ipv4 == NULL) {
514                     ipv4 = new_served_domain(NULL, "in-addr.arpa.");
515                     if (ipv4 == NULL) {
516                         ERROR("No space for in-addr.arpa.");
517                         return;
518                     }
519                 }
520 
521                 INFO("Adding PTRs for " PRI_S_SRP, name);
522                 for (interface_domain = served_domains; interface_domain != NULL;
523                      interface_domain = interface_domain->next) {
524                     if (interface_domain->interface == NULL || interface_domain->interface->ifindex == 0) {
525                         continue;
526                     }
527                     RESET;
528                     INFO("Adding PTR from " PRI_S_SRP " to " PRI_S_SRP, name, interface_domain->domain);
529                     dns_full_name_to_wire(NULL, towire, interface_domain->domain);
530                     dnssd_hardwired_add(ipv4, name, ipv4->domain_ld, towire->p - wire->data, wire->data,
531                                         dns_rrtype_ptr);
532                 }
533             } else if (ifaddr->addr.sa.sa_family == AF_INET6) {
534                 uint8_t *address = (uint8_t *)&(ifaddr->addr.sin6.sin6_addr);
535                 uint8_t *mask = (uint8_t *)&(ifaddr->mask.sin6.sin6_addr);
536                 char *bp;
537                 int space = sizeof name;
538                 int i, word, shift;
539 
540                 if (IN6_IS_ADDR_LOOPBACK(&ifaddr->addr.sin6.sin6_addr)) {
541                     INFO("Skipping IPv6 link local address on " PRI_S_SRP " (" PUB_S_SRP ")", addr_domain->domain,
542                          interface->name);
543                     continue;
544                 }
545                 if (IN6_IS_ADDR_LINKLOCAL(&ifaddr->addr.sin6.sin6_addr)) {
546                     INFO("Skipping IPv6 link local address on " PRI_S_SRP " (" PUB_S_SRP ")", addr_domain->domain,
547                          interface->name);
548                     continue;
549                 }
550                 snprintf(name, space, "lb._dns-sd._udp");
551                 bp = name + strlen(name);
552                 for (i = 16; i >= 0; i--) {
553                     word = i;
554                     for (shift = 0; shift < 8; shift += 4) {
555                         snprintf(bp, (sizeof name) - (bp - name), ".%x",
556                                 (address[word] >> shift) & (mask[word] >> shift) & 15);
557                         bp += strlen(bp);
558                     }
559                 }
560                 if (ip6 == NULL) {
561                     ip6 = new_served_domain(NULL, "ip6.arpa.");
562                     if (ip6 == NULL) {
563                         ERROR("No space for ip6.arpa.");
564                         return;
565                     }
566                 }
567                 INFO("Adding PTRs for " PRI_S_SRP, name);
568                 for (interface_domain = served_domains; interface_domain != NULL;
569                      interface_domain = interface_domain->next) {
570                     if (interface_domain->interface == NULL || interface_domain->interface->ifindex == 0) {
571                         continue;
572                     }
573                     INFO("Adding PTR from " PRI_S_SRP " to " PRI_S_SRP, name, interface_domain->domain);
574                     RESET;
575                     dns_full_name_to_wire(NULL, towire, interface_domain->domain);
576                     dnssd_hardwired_add(ip6, name, ip6->domain_ld, towire->p - wire->data, wire->data, dns_rrtype_ptr);
577                 }
578             } else {
579                 char buf[INET6_ADDRSTRLEN];
580                 IOLOOP_NTOP(&ifaddr->addr, buf);
581                 INFO("Skipping " PRI_S_SRP, buf);
582             }
583         }
584     }
585 #undef RESET
586 }
587 
588 void
dnssd_hardwired_setup(void)589 dnssd_hardwired_setup(void)
590 {
591     dns_wire_t wire;
592     dns_towire_state_t towire;
593     served_domain_t *sdt;
594     int i;
595     dns_name_t *my_name_parsed = my_name == NULL ? NULL : dns_pres_name_parse(my_name);
596     char namebuf[DNS_MAX_NAME_SIZE + 1];
597     const char *local_name = my_name;
598     addr_t addr;
599 
600 #define RESET \
601     memset(&towire, 0, sizeof towire); \
602     towire.message = &wire; \
603     towire.p = wire.data; \
604     towire.lim = towire.p + sizeof wire.data
605 
606     // For each interface, set up the hardwired names.
607     for (sdt = served_domains; sdt; sdt = sdt->next) {
608         if (sdt->interface == NULL) {
609             continue;
610         }
611 
612         // SRV
613         // _dns-llq._udp
614         // _dns-llq-tls._tcp
615         // _dns-update._udp
616         // _dns-update-tls._udp
617         // We deny the presence of support for LLQ, because we only support DNS Push
618         RESET;
619         dnssd_hardwired_add(sdt, "_dns-llq._udp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
620         dnssd_hardwired_add(sdt, "_dns-llq-tls._tcp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
621 
622         // We deny the presence of support for DNS Update, because a Discovery Proxy zone is stateless.
623         dnssd_hardwired_add(sdt, "_dns-update._udp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
624         dnssd_hardwired_add(sdt, "_dns-update-tls._tcp", sdt->domain_ld, towire.p - wire.data, wire.data,
625                             dns_rrtype_srv);
626 
627         // Until we set up the DNS Push listener, we deny its existence.   If TLS is ready to go, this will be
628         // overwritten immediately; otherwise it will be overwritten when the TLS key has been generated and signed.
629         dnssd_hardwired_add(sdt, "_dns-push-tls._tcp", sdt->domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
630 
631         // If my_name wasn't set, or if my_name is in this interface's domain, we need to answer
632         // for it when queried.
633         if (my_name == NULL || my_name_parsed != NULL) {
634             const char *local_domain = NULL;
635             if (my_name == NULL) {
636                 local_name = "ns";
637                 local_domain = sdt->domain_ld;
638             } else {
639                 dns_name_t *lim;
640                 local_name = NULL;
641 
642                 // See if my_name is a subdomain of this interface's domain
643                 if ((lim = dns_name_subdomain_of(my_name_parsed, sdt->domain_name)) != NULL) {
644                     dns_name_print_to_limit(my_name_parsed, lim, namebuf, sizeof namebuf);
645                     local_name = namebuf;
646                     dns_name_free(my_name_parsed);
647                     my_name_parsed = NULL;
648                     if (local_name[0] == '\0') {
649                         local_domain = sdt->domain;
650                     } else {
651                         local_domain = sdt->domain_ld;
652                     }
653                 }
654             }
655             if (local_name != NULL) {
656                 for (i = 0; i < num_publish_addrs; i++) {
657                     RESET;
658                     memset(&addr, 0, sizeof addr);
659                     getipaddr(&addr, publish_addrs[i]);
660                     if (addr.sa.sa_family == AF_INET) {
661                         // A
662                         // ns
663                         dns_rdata_raw_data_to_wire(&towire, &addr.sin.sin_addr, sizeof addr.sin.sin_addr);
664                         dnssd_hardwired_add(sdt, local_name, local_domain, towire.p - wire.data, wire.data,
665                                             dns_rrtype_a);
666                     } else {
667                         // AAAA
668                         RESET;
669                         dns_rdata_raw_data_to_wire(&towire, &addr.sin6.sin6_addr, sizeof addr.sin6.sin6_addr);
670                         dnssd_hardwired_add(sdt, local_name, local_domain, towire.p - wire.data, wire.data,
671                                             dns_rrtype_aaaa);
672                     }
673                 }
674             }
675         }
676 
677         // NS
678         RESET;
679         if (my_name != NULL) {
680             dns_full_name_to_wire(NULL, &towire, my_name);
681         } else {
682             dns_name_to_wire(NULL, &towire, "ns");
683             dns_full_name_to_wire(NULL, &towire, sdt->domain);
684         }
685         dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_ns);
686 
687         // SOA (piggybacking on what we already did for NS, which starts the same.
688         dns_name_to_wire(NULL, &towire, "postmaster");
689         dns_full_name_to_wire(NULL, &towire, sdt->domain);
690         dns_u32_to_wire(&towire, 0);     // serial
691         dns_ttl_to_wire(&towire, 7200);  // refresh
692         dns_ttl_to_wire(&towire, 3600);  // retry
693         dns_ttl_to_wire(&towire, 86400); // expire
694         dns_ttl_to_wire(&towire, 120);    // minimum
695         dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_soa);
696     }
697 
698     if (my_name_parsed != NULL) {
699         dns_name_free(my_name_parsed);
700         my_name_parsed = NULL;
701 
702         sdt = new_served_domain(NULL, my_name);
703         if (sdt == NULL) {
704             ERROR("Unable to allocate domain for %s", my_name);
705         } else {
706             for (i = 0; i < num_publish_addrs; i++) {
707                 // AAAA
708                 // A
709                 RESET;
710                 memset(&addr, 0, sizeof addr);
711                 getipaddr(&addr, publish_addrs[i]);
712                 if (addr.sa.sa_family == AF_INET) {
713                     dns_rdata_raw_data_to_wire(&towire, &addr.sin.sin_addr, sizeof addr.sin.sin_addr);
714                     dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_a);
715                 } else {
716                     dns_rdata_raw_data_to_wire(&towire, &addr.sin6.sin6_addr, sizeof addr.sin6.sin6_addr);
717                     dnssd_hardwired_add(sdt, "", sdt->domain, towire.p - wire.data, wire.data, dns_rrtype_aaaa);
718                 }
719             }
720         }
721     }
722     dnssd_hardwired_lbdomains_setup(&towire, &wire);
723 }
724 
725 void
dnssd_hardwired_push_setup(void)726 dnssd_hardwired_push_setup(void)
727 {
728     dns_wire_t wire;
729     dns_towire_state_t towire;
730     served_domain_t *sdt;
731 
732 #define RESET \
733     memset(&towire, 0, sizeof towire); \
734     towire.message = &wire; \
735     towire.p = wire.data; \
736     towire.lim = towire.p + sizeof wire.data
737 
738     // For each interface, set up the hardwired names.
739     for (sdt = served_domains; sdt; sdt = sdt->next) {
740         if (sdt->interface == NULL) {
741             continue;
742         }
743 
744         if (!sdt->interface->no_push) {
745             // SRV
746             // _dns-push-tls._tcp
747             RESET;
748             dns_u16_to_wire(&towire, 0); // priority
749             dns_u16_to_wire(&towire, 0); // weight
750             dns_u16_to_wire(&towire, 853); // port
751             // Define my_name in the config file to reference a name for this server in a different zone.
752             if (my_name == NULL) {
753                 dns_name_to_wire(NULL, &towire, "ns");
754                 dns_full_name_to_wire(NULL, &towire, sdt->domain);
755             } else {
756                 dns_full_name_to_wire(NULL, &towire, my_name);
757             }
758             dnssd_hardwired_add(sdt, "_dns-push-tls._tcp", sdt->domain_ld, towire.p - wire.data, wire.data,
759                                 dns_rrtype_srv);
760             // This will probably never be used, but existing open source mDNSResponder code can be
761             // configured to do DNS queries over TLS for specific domains, so we might as well support it,
762             // since we do have TLS support.
763             dnssd_hardwired_add(sdt, "_dns-query-tls._udp", sdt->domain_ld, towire.p - wire.data, wire.data,
764                                 dns_rrtype_srv);
765         }
766     }
767 }
768 
769 bool
embiggen(dnssd_query_t * query)770 embiggen(dnssd_query_t *query)
771 {
772     dns_wire_t *nr = malloc(query->data_size + sizeof *nr); // increments wire size by DNS_DATA_SIZE
773     if (nr == NULL) {
774         return false;
775     }
776     memcpy(nr, query->response, DNS_HEADER_SIZE + query->data_size);
777     query->data_size += DNS_DATA_SIZE;
778 #define RELOCATE(x) (x) = &nr->data[0] + ((x) - &query->response->data[0])
779     RELOCATE(query->towire.p);
780     query->towire.lim = &nr->data[0] + query->data_size;
781     query->towire.p_rdlength = NULL;
782     query->towire.p_opt = NULL;
783     query->towire.message = nr;
784     free(query->response);
785     query->response = nr;
786     return true;
787 }
788 
789 void
dp_query_send_dns_response(dnssd_query_t * query)790 dp_query_send_dns_response(dnssd_query_t *query)
791 {
792     struct iovec iov;
793     dns_towire_state_t *towire = &query->towire;
794     const char *failnote = NULL;
795     uint8_t *revert = towire->p;
796     uint16_t tc = towire->truncated ? dns_flags_tc : 0;
797     uint16_t bitfield = ntohs(query->response->bitfield);
798     uint16_t mask = 0;
799 
800     // Send an SOA record if it's a .local query.
801     if (query->served_domain != NULL && query->served_domain->interface != NULL && !towire->truncated) {
802     redo:
803         // DNSSD Hybrid, Section 6.1.
804         TOWIRE_CHECK("&query->enclosing_domain_pointer 1", towire,
805                      dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
806         TOWIRE_CHECK("dns_rrtype_soa", towire,
807                      dns_u16_to_wire(towire, dns_rrtype_soa));
808         TOWIRE_CHECK("dns_qclass_in", towire,
809                      dns_u16_to_wire(towire, dns_qclass_in));
810         TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, 3600));
811         TOWIRE_CHECK("rdlength_begin ", towire, dns_rdlength_begin(towire));
812         if (my_name != NULL) {
813             TOWIRE_CHECK(my_name, towire, dns_full_name_to_wire(NULL, towire, my_name));
814         } else {
815             TOWIRE_CHECK("\"ns\"", towire, dns_name_to_wire(NULL, towire, "ns"));
816             TOWIRE_CHECK("&query->enclosing_domain_pointer 2", towire,
817                          dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
818         }
819         TOWIRE_CHECK("\"postmaster\"", towire,
820                      dns_name_to_wire(NULL, towire, "postmaster"));
821         TOWIRE_CHECK("&query->enclosing_domain_pointer 3", towire,
822                      dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
823         TOWIRE_CHECK("serial", towire,dns_u32_to_wire(towire, 0));     // serial
824         TOWIRE_CHECK("refresh", towire, dns_ttl_to_wire(towire, 7200));  // refresh
825         TOWIRE_CHECK("retry", towire, dns_ttl_to_wire(towire, 3600));  // retry
826         TOWIRE_CHECK("expire", towire, dns_ttl_to_wire(towire, 86400)); // expire
827         TOWIRE_CHECK("minimum", towire, dns_ttl_to_wire(towire, 120));    // minimum
828         dns_rdlength_end(towire);
829         if (towire->truncated) {
830             query->towire.p = revert;
831             if (query->connection->tcp_stream) {
832                 if (embiggen(query)) {
833                     query->towire.error = 0;
834                     towire->truncated = false;
835                     goto redo;
836                 }
837             } else {
838                 tc = dns_flags_tc;
839             }
840         } else {
841             query->response->nscount = htons(1);
842         }
843 
844         // Response is authoritative and not recursive.
845         mask = ~dns_flags_ra;
846         bitfield = bitfield | dns_flags_aa | tc;
847         bitfield = bitfield & mask;
848     } else {
849         // Response is recursive and not authoritative.
850         mask = ~dns_flags_aa;
851         bitfield = bitfield | dns_flags_ra | tc;
852         bitfield = bitfield & mask;
853     }
854     // Not authentic, checking not disabled.
855     mask = ~(dns_flags_rd | dns_flags_ad | dns_flags_cd);
856     bitfield = bitfield & mask;
857     query->response->bitfield = htons(bitfield);
858 
859     // This is a response
860     dns_qr_set(query->response, dns_qr_response);
861 
862     // Send an OPT RR if we got one
863     // XXX reserve space so we can always send an OPT RR?
864     if (query->is_edns0) {
865     redo_edns0:
866         TOWIRE_CHECK("Root label", towire, dns_u8_to_wire(towire, 0));     // Root label
867         TOWIRE_CHECK("dns_rrtype_opt", towire, dns_u16_to_wire(towire, dns_rrtype_opt));
868         TOWIRE_CHECK("UDP Payload size", towire, dns_u16_to_wire(towire, 4096)); // UDP Payload size
869         TOWIRE_CHECK("extended-rcode", towire, dns_u8_to_wire(towire, 0));     // extended-rcode
870         TOWIRE_CHECK("EDNS version 0", towire, dns_u8_to_wire(towire, 0));     // EDNS version 0
871         TOWIRE_CHECK("No extended flags", towire, dns_u16_to_wire(towire, 0));    // No extended flags
872         TOWIRE_CHECK("No payload", towire, dns_u16_to_wire(towire, 0));    // No payload
873         if (towire->truncated) {
874             query->towire.p = revert;
875             if (query->connection->tcp_stream) {
876                 if (embiggen(query)) {
877                     query->towire.error = false;
878                     query->towire.truncated = false;
879                     goto redo_edns0;
880                 }
881             }
882         } else {
883             query->response->arcount = htons(1);
884         }
885     }
886 
887     if (towire->error) {
888         ERROR("dp_query_send_dns_response failed on %s", failnote);
889         if (tc == dns_flags_tc) {
890             dns_rcode_set(query->response, dns_rcode_noerror);
891         } else {
892             dns_rcode_set(query->response, dns_rcode_servfail);
893         }
894     } else {
895         // No error.
896         dns_rcode_set(query->response, dns_rcode_noerror);
897     }
898 
899     iov.iov_len = (query->towire.p - (uint8_t *)query->response);
900     iov.iov_base = query->response;
901     INFO("dp_query_send_dns_response: " PRI_S_SRP " (len %zd)", query->name, iov.iov_len);
902 
903     if (query->connection != NULL) {
904         query->connection->send_response(query->connection, query->question, &iov, 1);
905     }
906 
907     // Free up state
908     // Query will be freed automatically next time through the io loop.
909     dnssd_query_cancel(query);
910 }
911 
912 void
dp_query_towire_reset(dnssd_query_t * query)913 dp_query_towire_reset(dnssd_query_t *query)
914 {
915     query->towire.p = &query->response->data[0];  // We start storing RR data here.
916     query->towire.lim = &query->response->data[0] + query->data_size; // This is the limit to how much we can store.
917     query->towire.message = query->response;
918     query->towire.p_rdlength = NULL;
919     query->towire.p_opt = NULL;
920     query->p_dso_length = NULL;
921 }
922 
923 void
dns_push_start(dnssd_query_t * query)924 dns_push_start(dnssd_query_t *query)
925 {
926     const char *failnote = NULL;
927 
928     // If we don't have a dso header yet, start one.
929     if (query->p_dso_length == NULL) {
930         memset(query->response, 0, (sizeof *query->response) - DNS_DATA_SIZE);
931         dns_opcode_set(query->response, dns_opcode_dso);
932         // This is a unidirectional DSO message, which is marked as a query
933         dns_qr_set(query->response, dns_qr_query);
934         // No error cuz not a response.
935         dns_rcode_set(query->response, dns_rcode_noerror);
936 
937         TOWIRE_CHECK("kDSOType_DNSPushUpdate", &query->towire,
938                      dns_u16_to_wire(&query->towire, kDSOType_DNSPushUpdate));
939         if (query->towire.p + 2 > query->towire.lim) {
940             ERROR("No room for dso length in DNS Push notification message.");
941             dp_query_towire_reset(query);
942             return;
943         }
944         query->p_dso_length = query->towire.p;
945         query->towire.p += 2;
946     }
947     if (failnote != NULL) {
948         ERROR("dns_push_start: couldn't start update: %s", failnote);
949     }
950 }
951 
952 void
dp_push_response(dnssd_query_t * query)953 dp_push_response(dnssd_query_t *query)
954 {
955     struct iovec iov;
956 
957     if (query->p_dso_length != NULL) {
958         int16_t dso_length = query->towire.p - query->p_dso_length - 2;
959         iov.iov_len = (query->towire.p - (uint8_t *)query->response);
960         iov.iov_base = query->response;
961         INFO("dp_push_response: " PRI_S_SRP " (len %zd)", query->name, iov.iov_len);
962 
963         query->towire.p = query->p_dso_length;
964         dns_u16_to_wire(&query->towire, dso_length);
965         if (query->connection != NULL) {
966             query->connection->send_response(query->connection, query->question, &iov, 1);
967         }
968         dp_query_towire_reset(query);
969     }
970 }
971 
972 bool
dnssd_hardwired_response(dnssd_query_t * query,DNSServiceQueryRecordReply callback)973 dnssd_hardwired_response(dnssd_query_t *query, DNSServiceQueryRecordReply callback)
974 {
975     hardwired_t *hp;
976     bool got_response = false;
977 
978     for (hp = query->served_domain->hardwired_responses; hp; hp = hp->next) {
979         if ((query->type == hp->type || query->type == dns_rrtype_any) &&
980             query->qclass == dns_qclass_in && !strcasecmp(hp->name, query->name)) {
981             if (query->is_dns_push) {
982                 dns_push_start(query);
983                 dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in, hp->rdlen, hp->rdata, 3600);
984             } else {
985                 // Store the response
986                 if (!query->towire.truncated) {
987                     dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in, hp->rdlen, hp->rdata,
988                                                   3600);
989                     if (!query->towire.truncated) {
990                         query->response->ancount = htons(ntohs(query->response->ancount) + 1);
991                     }
992                 }
993             }
994             got_response = true;
995         }
996     }
997     if (got_response) {
998         if (query->is_dns_push) {
999             dp_push_response(query);
1000         } else {
1001             // Steal the question
1002             query->question = query->connection->message;
1003             query->connection->message = NULL;
1004             // Send the answer(s).
1005             dp_query_send_dns_response(query);
1006         }
1007         return true;
1008     }
1009     return false;
1010 }
1011 
1012 // This is the callback for dns query results.
1013 void
dns_query_callback(DNSServiceRef sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,void * context)1014 dns_query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
1015                    const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata,
1016                    uint32_t ttl, void *context)
1017 {
1018     dnssd_query_t *query = context;
1019 
1020     INFO(PRI_S_SRP " %d %d %x %d", fullname, rrtype, rrclass, rdlen, errorCode);
1021 
1022     if (errorCode == kDNSServiceErr_NoError) {
1023     re_add:
1024         dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata,
1025                                       ttl > 10 ? 10 : ttl); // Per dnssd-hybrid 5.5.1, limit ttl to 10 seconds
1026         if (query->towire.truncated) {
1027             if (query->connection->tcp_stream) {
1028                 if (embiggen(query)) {
1029                     query->towire.truncated = false;
1030                     query->towire.error = false;
1031                     goto re_add;
1032                 } else {
1033                     dns_rcode_set(query->response, dns_rcode_servfail);
1034                     dp_query_send_dns_response(query);
1035                     return;
1036                 }
1037             }
1038         } else {
1039             query->response->ancount = htons(ntohs(query->response->ancount) + 1);
1040         }
1041         // If there isn't more coming, send the response now
1042         if (!(flags & kDNSServiceFlagsMoreComing) || query->towire.truncated) {
1043             // When we get a CNAME response, we may not get the record it points to with the MoreComing
1044             // flag set, so don't respond yet.
1045             if (query->type != dns_rrtype_cname && rrtype == dns_rrtype_cname) {
1046             } else {
1047                 dp_query_send_dns_response(query);
1048             }
1049         }
1050     } else if (errorCode == kDNSServiceErr_NoSuchRecord) {
1051         // If we get "no such record," we can't really do much except return the answer.
1052         dp_query_send_dns_response(query);
1053     } else {
1054         dns_rcode_set(query->response, dns_rcode_servfail);
1055         dp_query_send_dns_response(query);
1056     }
1057 }
1058 
1059 void
dp_query_wakeup(void * context)1060 dp_query_wakeup(void *context)
1061 {
1062     dnssd_query_t *query = context;
1063     char name[DNS_MAX_NAME_SIZE + 1];
1064     int namelen = strlen(query->name);
1065 
1066     // Should never happen.
1067     if (namelen + (query->served_domain
1068                    ? (query->served_domain->interface != NULL
1069                       ? sizeof local_suffix
1070                       : strlen(query->served_domain->domain_ld))
1071                    : 0) > sizeof name) {
1072         ERROR("db_query_wakeup: no space to construct name.");
1073         dnssd_query_cancel(query);
1074     }
1075 
1076     strcpy(name, query->name);
1077     if (query->served_domain != NULL) {
1078         strcpy(name + namelen, local_suffix);
1079     }
1080     dp_query_send_dns_response(query);
1081 }
1082 
1083 bool
dp_query_start(comm_t * comm,dnssd_query_t * query,int * rcode,DNSServiceQueryRecordReply callback)1084 dp_query_start(comm_t *comm, dnssd_query_t *query, int *rcode, DNSServiceQueryRecordReply callback)
1085 {
1086     char name[DNS_MAX_NAME_SIZE + 1];
1087     char *np;
1088     bool local = false;
1089     int len;
1090     DNSServiceRef sdref;
1091 
1092     // If a query has a served domain, query->name is the subdomain of the served domain that is
1093     // being queried; otherwise query->name is the whole name.
1094     if (query->served_domain != NULL) {
1095         if (dnssd_hardwired_response(query, callback)) {
1096             *rcode = dns_rcode_noerror;
1097             return true;
1098         }
1099         len = strlen(query->name);
1100         if (query->served_domain->interface != NULL) {
1101             if (len + sizeof local_suffix > sizeof name) {
1102                 *rcode = dns_rcode_servfail;
1103                 free(query->name);
1104                 free(query);
1105                 ERROR("question name %s is too long for .local.", name);
1106                 return false;
1107             }
1108             memcpy(name, query->name, len);
1109             memcpy(&name[len], local_suffix, sizeof local_suffix);
1110         } else {
1111             int dlen = strlen(query->served_domain->domain_ld) + 1;
1112             if (len + dlen > sizeof name) {
1113                 *rcode = dns_rcode_servfail;
1114                 free(query->name);
1115                 free(query);
1116                 ERROR("question name %s is too long for %s.", name, query->served_domain->domain);
1117                 return false;
1118             }
1119             memcpy(name, query->name, len);
1120             memcpy(&name[len], query->served_domain->domain_ld, dlen);
1121         }
1122         np = name;
1123         local = true;
1124     } else {
1125         np = query->name;
1126     }
1127 
1128     // If we get an SOA query for record that's under a zone cut we're authoritative for, which
1129     // is the case of query->served_domain->interface != NULL, then answer with a negative response that includes
1130     // our authority records, rather than waiting for the query to time out.
1131     if (query->served_domain != NULL && query->served_domain->interface != NULL &&
1132         (query->type == dns_rrtype_soa ||
1133          query->type == dns_rrtype_ns ||
1134          query->type == dns_rrtype_ds) && query->qclass == dns_qclass_in && query->is_dns_push == false) {
1135         query->question = comm->message;
1136         comm->message = NULL;
1137         dp_query_send_dns_response(query);
1138         return true;
1139     }
1140 
1141     // Issue a DNSServiceQueryRecord call
1142     int err = DNSServiceQueryRecord(&sdref, query->serviceFlags,
1143                                     kDNSServiceInterfaceIndexAny, np, query->type,
1144                                     query->qclass, callback, query);
1145     if (err != kDNSServiceErr_NoError) {
1146         ERROR("dp_query_start: DNSServiceQueryRecord failed for '%s': %d", np, err);
1147         *rcode = dns_rcode_servfail;
1148         return false;
1149     } else {
1150         query->txn = ioloop_dnssd_txn_add(sdref, dnssd_query_finalize_callback, dnssd_query_close_callback);
1151         if (query->txn == NULL) {
1152             return false;
1153         }
1154         INFO("dp_query_start: DNSServiceQueryRecord started for '" PRI_S_SRP "': %d", np, err);
1155     }
1156 
1157     // If this isn't a DNS Push subscription, we need to respond quickly with as much data as we have.  It
1158     // turns out that dig gives us a second, but also that responses seem to come back in on the order of a
1159     // millisecond, so we'll wait 100ms.
1160     if (!query->is_dns_push && local) {
1161         // [mDNSDP 5.6 p. 25]
1162         if (query->wakeup == NULL) {
1163             query->wakeup = ioloop_wakeup_create();
1164             if (query->wakeup == NULL) {
1165                 *rcode = dns_rcode_servfail;
1166                 return false;
1167             }
1168         }
1169         ioloop_add_wake_event(query->wakeup, query, dp_query_wakeup, ioloop_timenow() + IOLOOP_SECOND * 6);
1170     }
1171     return true;
1172 }
1173 
1174 dnssd_query_t *
dp_query_generate(comm_t * comm,dns_rr_t * question,bool dns_push,int * rcode)1175 dp_query_generate(comm_t *comm, dns_rr_t *question, bool dns_push, int *rcode)
1176 {
1177     char name[DNS_MAX_NAME_SIZE + 1];
1178     served_domain_t *sdt = dp_served(question->name, name, sizeof name);
1179 
1180     // If it's a query for a name served by the local discovery proxy, do an mDNS lookup.
1181     if (sdt) {
1182         INFO(PUB_S_SRP " question: type %d class %d " PRI_S_SRP "." PRI_S_SRP " -> " PRI_S_SRP ".local",
1183              dns_push ? "push" : " dns", question->type, question->qclass, name, sdt->domain, name);
1184     } else {
1185         dns_name_print(question->name, name, sizeof name);
1186         INFO(PUB_S_SRP " question: type %d class %d " PRI_S_SRP,
1187              dns_push ? "push" : " dns", question->type, question->qclass, name);
1188     }
1189 
1190     dnssd_query_t *query = calloc(1,sizeof *query);
1191     if (query == NULL) {
1192     nomem:
1193         ERROR("Unable to allocate memory for query on %s", name);
1194         *rcode = dns_rcode_servfail;
1195         return NULL;
1196     }
1197     query->response = malloc(sizeof *query->response);
1198     if (query->response == NULL) {
1199         goto nomem;
1200     }
1201     query->data_size = DNS_DATA_SIZE;
1202 
1203     // Zero out the DNS header, but not the data.
1204     memset(query->response, 0, DNS_HEADER_SIZE);
1205 
1206     // Steal the data from the question.   If subdomain is not null, this is a local mDNS query; otherwise
1207     // we are recursing.
1208     INFO("name = " PRI_S_SRP, name);
1209     query->name = strdup(name);
1210     if (!query->name) {
1211         *rcode = dns_rcode_servfail;
1212         free(query);
1213         ERROR("unable to allocate memory for question name on %s", name);
1214         return NULL;
1215     }
1216     // It is safe to assume that enclosing domain will not be freed out from under us.
1217     query->served_domain = sdt;
1218     query->serviceFlags = 0;
1219 
1220     // If this is a local query, add ".local" to the end of the name and require multicast.
1221     if (sdt != NULL && sdt->interface) {
1222         query->serviceFlags |= kDNSServiceFlagsForceMulticast;
1223     } else {
1224         query->serviceFlags |= kDNSServiceFlagsReturnIntermediates;
1225     }
1226     // Name now contains the name we want mDNSResponder to look up.
1227 
1228     // XXX make sure finalize does the right thing.
1229     query->connection = comm;
1230 
1231     // Remember whether this is a long-lived query.
1232     query->is_dns_push = dns_push;
1233 
1234     // Start writing the response
1235     dp_query_towire_reset(query);
1236 
1237     query->type = question->type;
1238     query->qclass = question->qclass;
1239 
1240     *rcode = dns_rcode_noerror;
1241     return query;
1242 }
1243 
1244 // This is the callback for DNS push query results, as opposed to push updates.
1245 void
dns_push_query_callback(DNSServiceRef sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,void * context)1246 dns_push_query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
1247                         DNSServiceErrorType errorCode,const char *fullname, uint16_t rrtype, uint16_t rrclass,
1248                         uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
1249 {
1250     dnssd_query_t *query = context;
1251     uint8_t *revert = query->towire.p;
1252 
1253     // From DNSSD-Hybrid, for mDNS queries:
1254     // If we have cached answers, respond immediately, because we probably have all the answers.
1255     // If we don't have cached answers, respond as soon as we get an answer (presumably more-coming will be false).
1256 
1257     // The spec says to not query if we have cached answers.   We trust the DNSServiceQueryRecord call to handle this.
1258 
1259     // If we switch to using a single connection to mDNSResponder, we could have !more-coming trigger a flush of
1260     // all outstanding queries that aren't waiting on a time trigger.   This is because more-coming isn't
1261     // query-specific
1262 
1263     INFO("PUSH " PRI_S_SRP " %d %d %x %d", fullname, rrtype, rrclass, rdlen, errorCode);
1264 
1265     // query_state_waiting means that we're answering a regular DNS question
1266     if (errorCode == kDNSServiceErr_NoError) {
1267         dns_push_start(query);
1268 
1269         // If kDNSServiceFlagsAdd is set, it's an add, otherwise a delete.
1270         re_add:
1271         if (flags & kDNSServiceFlagsAdd) {
1272             dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata, ttl);
1273         } else {
1274 	    // There was a verion of the code that used different semantics, we use those semantics on non-tls
1275 	    // connections for now, but should delete this soon.
1276 	    if (query->connection->tls_context != NULL) {
1277                 // I think if this happens it means delete all RRs of this type.
1278                 if (rdlen == 0) {
1279                     dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_any, rdlen, rdata, -2);
1280                 } else {
1281                     if (rdlen == 0) {
1282 			dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_none, rdlen, rdata, -2);
1283 		    } else {
1284                         dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata, -1);
1285 		    }
1286                 }
1287             } else {
1288                 if (rdlen == 0) {
1289                     dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_any, rdlen, rdata, 0);
1290                 } else {
1291                     dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_none, rdlen, rdata, 0);
1292                 }
1293             }
1294         }
1295         if (query->towire.truncated) {
1296             query->towire.truncated = false;
1297             query->towire.p = revert;
1298             query->towire.error = 0;
1299             dp_push_response(query);
1300             dns_push_start(query);
1301             goto re_add;
1302         }
1303 
1304         // If there isn't more coming, send a DNS Push notification now.
1305         // XXX If enough comes to fill the response, send the message.
1306         if (!(flags & kDNSServiceFlagsMoreComing)) {
1307             dp_push_response(query);
1308         }
1309     } else {
1310         ERROR("dns_push_query_callback: unexpected error code %d", errorCode);
1311         if (query->connection != NULL) {
1312             dso_drop_activity(query->connection->dso, query->activity);
1313         }
1314     }
1315 }
1316 
1317 void
dns_push_subscribe(comm_t * comm,const dns_wire_t * header,dso_state_t * dso,dns_rr_t * question,const char * activity_name,const char * opcode_name)1318 dns_push_subscribe(comm_t *comm, const dns_wire_t *header, dso_state_t *dso, dns_rr_t *question,
1319                    const char *activity_name, const char *opcode_name)
1320 {
1321     int rcode;
1322     dnssd_query_t *query = dp_query_generate(comm, question, true, &rcode);
1323 
1324     if (!query) {
1325         dp_simple_response(comm, rcode);
1326         return;
1327     }
1328 
1329     dso_activity_t *activity = dso_add_activity(dso, activity_name, push_subscription_activity_type, query,
1330                                                 dns_push_finalize);
1331     query->activity = activity;
1332     if (!dp_query_start(comm, query, &rcode, dns_push_query_callback)) {
1333         dso_drop_activity(dso, activity);
1334         dp_simple_response(comm, rcode);
1335         return;
1336     }
1337     dp_simple_response(comm, dns_rcode_noerror);
1338 }
1339 
1340 void
dns_push_reconfirm(comm_t * comm,const dns_wire_t * header,dso_state_t * dso)1341 dns_push_reconfirm(comm_t *comm, const dns_wire_t *header, dso_state_t *dso)
1342 {
1343     dns_rr_t question;
1344     char name[DNS_MAX_NAME_SIZE + 1];
1345     uint16_t rdlen;
1346 
1347     // The TLV offset should always be pointing into the message.
1348     unsigned offp = dso->primary.payload - &header->data[0];
1349     int len = offp + dso->primary.length;
1350 
1351     // Parse the name, rrtype and class.   We say there's no rdata even though there is
1352     // because there's no ttl and also we want the raw rdata, not parsed rdata.
1353     if (!dns_rr_parse(&question, header->data, len, &offp, false) ||
1354         !dns_u16_parse(header->data, len, &offp, &rdlen)) {
1355         dp_simple_response(comm, dns_rcode_formerr);
1356         ERROR("dns_push_reconfirm: RR parse from %s failed", dso->remote_name);
1357         return;
1358     }
1359     if (rdlen + offp != len) {
1360         dp_simple_response(comm, dns_rcode_formerr);
1361         ERROR("dns_push_reconfirm: RRdata parse from %s failed: length mismatch (%d != %d)",
1362               dso->remote_name, rdlen + offp, len);
1363         return;
1364     }
1365 
1366     if ((dp_served(question.name, name, sizeof name))) {
1367         int len = strlen(name);
1368         if (len + sizeof local_suffix > sizeof name) {
1369             dp_simple_response(comm, dns_rcode_formerr);
1370             ERROR("dns_push_reconfirm: name is too long for .local suffix: %s", name);
1371             return;
1372         }
1373         memcpy(&name[len], local_suffix, sizeof local_suffix);
1374     } else {
1375         dns_name_print(question.name, &name[8], sizeof name - 8);
1376     }
1377     // transmogrify name.
1378     DNSServiceReconfirmRecord(0, kDNSServiceInterfaceIndexAny, name,
1379                               question.type, question.qclass, rdlen, &header->data[offp]);
1380     dp_simple_response(comm, dns_rcode_noerror);
1381 }
1382 
1383 void
dns_push_unsubscribe(comm_t * comm,const dns_wire_t * header,dso_state_t * dso,dns_rr_t * question,dso_activity_t * activity,const char * opcode_name)1384 dns_push_unsubscribe(comm_t *comm, const dns_wire_t *header, dso_state_t *dso, dns_rr_t *question,
1385                    dso_activity_t *activity, const char *opcode_name)
1386 {
1387     dso_drop_activity(dso, activity);
1388     // No response, unsubscribe is unidirectional.
1389 }
1390 
1391 void
dns_push_subscription_change(const char * opcode_name,comm_t * comm,const dns_wire_t * header,dso_state_t * dso)1392 dns_push_subscription_change(const char *opcode_name, comm_t *comm, const dns_wire_t *header, dso_state_t *dso)
1393 {
1394     // type-in-hex/class-in-hex/name-to-subscribe
1395     char activity_name[DNS_MAX_NAME_SIZE_ESCAPED + 3 + 4 + 4];
1396     dso_activity_t *activity;
1397 
1398     // The TLV offset should always be pointing into the message.
1399     unsigned offp = dso->primary.payload - &header->data[0];
1400     // Get the question
1401     dns_rr_t question;
1402 
1403     if (!dns_rr_parse(&question, header->data, offp + dso->primary.length, &offp, false)) {
1404         // Unsubscribes are unidirectional, so no response can be sent
1405         if (dso->primary.opcode != kDSOType_DNSPushUnsubscribe) {
1406             dp_simple_response(comm, dns_rcode_formerr);
1407         }
1408         ERROR("RR parse for %s from %s failed", dso->remote_name, opcode_name);
1409         return;
1410     }
1411 
1412     // Concoct an activity name.
1413     snprintf(activity_name, sizeof activity_name, "%04x%04x", question.type, question.qclass);
1414     if ((dp_served(question.name, &activity_name[8], (sizeof activity_name) - 8))) {
1415         int len = strlen(activity_name);
1416         if (len + sizeof local_suffix + 8 > sizeof (activity_name)) {
1417             ERROR("activity name overflow for %s", activity_name);
1418             return;
1419         }
1420         const int lslen = sizeof local_suffix;
1421         strncpy(&activity_name[len], local_suffix, lslen);
1422     } else {
1423         dns_name_print(question.name, &activity_name[8], (sizeof activity_name) - 8);
1424     }
1425 
1426     activity = dso_find_activity(dso, activity_name, push_subscription_activity_type, NULL);
1427     if (activity == NULL) {
1428         // Unsubscribe with no activity means no work to do; just return noerror.
1429         if (dso->primary.opcode != kDSOType_DNSPushSubscribe) {
1430             ERROR("dso_message: %s for %s when no subscription exists.", opcode_name, activity_name);
1431             if (dso->primary.opcode == kDSOType_DNSPushReconfirm) {
1432                 dp_simple_response(comm, dns_rcode_noerror);
1433             }
1434         } else {
1435             // In this case we have a push subscribe for which no subscription exists, which means we can do it.
1436             dns_push_subscribe(comm, header, dso, &question, activity_name, opcode_name);
1437         }
1438     } else {
1439         // Subscribe with a matching activity means no work to do; just return noerror.
1440         if (dso->primary.opcode == kDSOType_DNSPushSubscribe) {
1441             dp_simple_response(comm, dns_rcode_noerror);
1442         }
1443         // Otherwise cancel the subscription.
1444         else {
1445             dns_push_unsubscribe(comm, header, dso, &question, activity, opcode_name);
1446         }
1447     }
1448 }
1449 
dso_message(comm_t * comm,const dns_wire_t * header,dso_state_t * dso)1450 static void dso_message(comm_t *comm, const dns_wire_t *header, dso_state_t *dso)
1451 {
1452     switch(dso->primary.opcode) {
1453     case kDSOType_DNSPushSubscribe:
1454         dns_push_subscription_change("DNS Push Subscribe", comm, header, dso);
1455         break;
1456     case kDSOType_DNSPushUnsubscribe:
1457         dns_push_subscription_change("DNS Push Unsubscribe", comm, header, dso);
1458         break;
1459 
1460     case kDSOType_DNSPushReconfirm:
1461         dns_push_reconfirm(comm, header, dso);
1462         break;
1463 
1464     case kDSOType_DNSPushUpdate:
1465         INFO("dso_message: bogus push update message %d", dso->primary.opcode);
1466         dso_drop(dso);
1467         break;
1468 
1469     default:
1470         INFO("dso_message: unexpected primary TLV %d", dso->primary.opcode);
1471         dp_simple_response(comm, dns_rcode_dsotypeni);
1472         break;
1473     }
1474     // XXX free the message if we didn't consume it.
1475 }
1476 
dns_push_callback(void * context,const void * event_context,dso_state_t * dso,dso_event_type_t eventType)1477 static void dns_push_callback(void *context, const void *event_context,
1478                               dso_state_t *dso, dso_event_type_t eventType)
1479 {
1480     const dns_wire_t *message;
1481     switch(eventType)
1482     {
1483     case kDSOEventType_DNSMessage:
1484         // We shouldn't get here because we already handled any DNS messages
1485         message = event_context;
1486         INFO("dns_push_callback: DNS Message (opcode=%d) received from " PRI_S_SRP, dns_opcode_get(message),
1487              dso->remote_name);
1488         break;
1489     case kDSOEventType_DNSResponse:
1490         // We shouldn't get here because we already handled any DNS messages
1491         message = event_context;
1492         INFO("dns_push_callback: DNS Response (opcode=%d) received from " PRI_S_SRP, dns_opcode_get(message),
1493              dso->remote_name);
1494         break;
1495     case kDSOEventType_DSOMessage:
1496         INFO("dns_push_callback: DSO Message (Primary TLV=%d) received from " PRI_S_SRP,
1497                dso->primary.opcode, dso->remote_name);
1498         message = event_context;
1499         dso_message((comm_t *)context, message, dso);
1500         break;
1501     case kDSOEventType_DSOResponse:
1502         INFO("dns_push_callback: DSO Response (Primary TLV=%d) received from " PRI_S_SRP,
1503                dso->primary.opcode, dso->remote_name);
1504         break;
1505 
1506     case kDSOEventType_Finalize:
1507         INFO("dns_push_callback: Finalize");
1508         break;
1509 
1510     case kDSOEventType_Connected:
1511         INFO("dns_push_callback: Connected to " PRI_S_SRP, dso->remote_name);
1512         break;
1513 
1514     case kDSOEventType_ConnectFailed:
1515         INFO("dns_push_callback: Connection to " PRI_S_SRP " failed", dso->remote_name);
1516         break;
1517 
1518     case kDSOEventType_Disconnected:
1519         INFO("dns_push_callback: Connection to " PRI_S_SRP " disconnected", dso->remote_name);
1520         break;
1521     case kDSOEventType_ShouldReconnect:
1522         INFO("dns_push_callback: Connection to " PRI_S_SRP " should reconnect (not for a server)", dso->remote_name);
1523         break;
1524     case kDSOEventType_Inactive:
1525         INFO("dns_push_callback: Inactivity timer went off, closing connection.");
1526         break;
1527     case kDSOEventType_Keepalive:
1528         INFO("dns_push_callback: should send a keepalive now.");
1529         break;
1530     case kDSOEventType_KeepaliveRcvd:
1531         INFO("dns_push_callback: keepalive received.");
1532         break;
1533     case kDSOEventType_RetryDelay:
1534         INFO("dns_push_callback: keepalive received.");
1535         break;
1536     }
1537 }
1538 
1539 void
dp_dns_query(comm_t * comm,dns_rr_t * question)1540 dp_dns_query(comm_t *comm, dns_rr_t *question)
1541 {
1542     int rcode;
1543     dnssd_query_t *query = dp_query_generate(comm, question, false, &rcode);
1544     const char *failnote = NULL;
1545     if (!query) {
1546         dp_simple_response(comm, rcode);
1547         return;
1548     }
1549 
1550     // For regular DNS queries, copy the ID, etc.
1551     query->response->id = comm->message->wire.id;
1552     query->response->bitfield = comm->message->wire.bitfield;
1553     dns_rcode_set(query->response, dns_rcode_noerror);
1554 
1555     // For DNS queries, we need to return the question.
1556     query->response->qdcount = htons(1);
1557     if (query->served_domain != NULL) {
1558         TOWIRE_CHECK("name", &query->towire, dns_name_to_wire(NULL, &query->towire, query->name));
1559         TOWIRE_CHECK("enclosing_domain", &query->towire,
1560                      dns_full_name_to_wire(&query->enclosing_domain_pointer,
1561                                            &query->towire, query->served_domain->domain));
1562     } else {
1563         TOWIRE_CHECK("full name", &query->towire, dns_full_name_to_wire(NULL, &query->towire, query->name));
1564     }
1565     TOWIRE_CHECK("TYPE", &query->towire, dns_u16_to_wire(&query->towire, question->type));    // TYPE
1566     TOWIRE_CHECK("CLASS", &query->towire, dns_u16_to_wire(&query->towire, question->qclass));  // CLASS
1567     if (failnote != NULL) {
1568         ERROR("dp_dns_query: failure encoding question: %s", failnote);
1569         goto fail;
1570     }
1571 
1572     // We should check for OPT RR, but for now assume it's there.
1573     query->is_edns0 = true;
1574 
1575     if (!dp_query_start(comm, query, &rcode, dns_query_callback)) {
1576     fail:
1577         dp_simple_response(comm, rcode);
1578         free(query->name);
1579         free(query);
1580         return;
1581     }
1582 
1583     // XXX make sure that finalize frees this.
1584     if (comm->message) {
1585         query->question = comm->message;
1586         comm->message = NULL;
1587     }
1588 }
1589 
dso_transport_finalize(comm_t * comm)1590 void dso_transport_finalize(comm_t *comm)
1591 {
1592     dso_state_t *dso = comm->dso;
1593     INFO("dso_transport_finalize: " PRI_S_SRP, dso->remote_name);
1594     if (comm) {
1595         ioloop_close(&comm->io);
1596     }
1597     free(dso);
1598     comm->dso = NULL;
1599 }
1600 
dns_evaluate(comm_t * comm)1601 void dns_evaluate(comm_t *comm)
1602 {
1603     dns_rr_t question;
1604     unsigned offset = 0;
1605 
1606     // Drop incoming responses--we're a server, so we only accept queries.
1607     if (dns_qr_get(&comm->message->wire) == dns_qr_response) {
1608         return;
1609     }
1610 
1611     // If this is a DSO message, see if we have a session yet.
1612     switch(dns_opcode_get(&comm->message->wire)) {
1613     case dns_opcode_dso:
1614         if (!comm->tcp_stream) {
1615             ERROR("DSO message received on non-tcp socket %s", comm->name);
1616             dp_simple_response(comm, dns_rcode_notimp);
1617             return;
1618         }
1619 
1620         if (!comm->dso) {
1621             comm->dso = dso_create(true, 0, comm->name, dns_push_callback, comm, comm);
1622             if (!comm->dso) {
1623                 ERROR("Unable to create a dso context for %s", comm->name);
1624                 dp_simple_response(comm, dns_rcode_servfail);
1625                 ioloop_close(&comm->io);
1626                 return;
1627             }
1628             comm->dso->transport_finalize = dso_transport_finalize;
1629         }
1630         dso_message_received(comm->dso, (uint8_t *)&comm->message->wire, comm->message->length);
1631         break;
1632 
1633     case dns_opcode_query:
1634         // In theory this is permitted but it can't really be implemented because there's no way
1635         // to say "here's the answer for this, and here's why that failed.
1636         if (ntohs(comm->message->wire.qdcount) != 1) {
1637             dp_simple_response(comm, dns_rcode_formerr);
1638             return;
1639         }
1640         if (!dns_rr_parse(&question, comm->message->wire.data, comm->message->length, &offset, 0)) {
1641             dp_simple_response(comm, dns_rcode_formerr);
1642             return;
1643         }
1644         dp_dns_query(comm, &question);
1645         dns_rrdata_free(&question);
1646         break;
1647 
1648         // No support for other opcodes yet.
1649     default:
1650         dp_simple_response(comm, dns_rcode_notimp);
1651         break;
1652     }
1653 }
1654 
dns_input(comm_t * comm)1655 void dns_input(comm_t *comm)
1656 {
1657     dns_evaluate(comm);
1658     if (comm->message != NULL) {
1659         message_free(comm->message);
1660         comm->message = NULL;
1661     }
1662 }
1663 
1664 static int
usage(const char * progname)1665 usage(const char *progname)
1666 {
1667     ERROR("usage: %s", progname);
1668     ERROR("ex: dnssd-proxy");
1669     return 1;
1670 }
1671 
1672 // Called whenever we get a connection.
1673 void
connected(comm_t * comm)1674 connected(comm_t *comm)
1675 {
1676     INFO("connection from " PRI_S_SRP, comm->name);
1677     return;
1678 }
1679 
config_string_handler(char ** ret,const char * filename,const char * string,int lineno,bool tdot,bool ldot)1680 static bool config_string_handler(char **ret, const char *filename, const char *string, int lineno, bool tdot,
1681                                   bool ldot)
1682 {
1683     char *s;
1684     int add_trailing_dot = 0;
1685     int add_leading_dot = ldot ? 1 : 0;
1686     int len = strlen(string);
1687 
1688     // Space for NUL and leading dot.
1689     if (tdot && len > 0 && string[len - 1] != '.') {
1690         add_trailing_dot = 1;
1691     }
1692     s = malloc(strlen(string) + add_leading_dot + add_trailing_dot + 1);
1693     if (s == NULL) {
1694         ERROR("Unable to allocate domain name %s", string);
1695         return false;
1696     }
1697     *ret = s;
1698     if (ldot) {
1699         *s++ = '.';
1700     }
1701     strcpy(s, string);
1702     if (add_trailing_dot) {
1703         s[len] = '.';
1704         s[len + 1] = 0;
1705     }
1706     return true;
1707 }
1708 
1709 static served_domain_t *
new_served_domain(interface_t * interface,char * domain)1710 new_served_domain(interface_t *interface, char *domain)
1711 {
1712     served_domain_t *sdt = calloc(1, sizeof *sdt);
1713     if (sdt == NULL) {
1714         ERROR("Unable to allocate served domain %s", domain);
1715         return NULL;
1716     }
1717     sdt->domain_ld = malloc(strlen(domain) + 2);
1718     if (sdt->domain_ld == NULL) {
1719         ERROR("Unable to allocate served domain name %s", domain);
1720         free(sdt);
1721         return NULL;
1722     }
1723     sdt->domain_ld[0] = '.';
1724     sdt->domain = sdt->domain_ld + 1;
1725     strcpy(sdt->domain, domain);
1726     sdt->domain_name = dns_pres_name_parse(sdt->domain);
1727     sdt->interface = interface;
1728     if (sdt->domain_name == NULL) {
1729         if (interface != NULL) {
1730             ERROR("invalid domain name for interface %s: %s", interface->name, sdt->domain);
1731         } else {
1732             ERROR("invalid domain name: %s", sdt->domain);
1733         }
1734         free(sdt);
1735         return NULL;
1736     }
1737     sdt->next = served_domains;
1738     served_domains = sdt;
1739     return sdt;
1740 }
1741 
1742 // Dynamic interface detection...
1743 // This is called whenever a new interface address is encountered.  At present, this is only called
1744 // once for each interface address, on startup, but in principle it _could_ be called whenever an
1745 // interface is added or deleted, or is assigned or loses an address.
1746 void
ifaddr_callback(void * context,const char * name,const addr_t * address,const addr_t * mask,int ifindex,enum interface_address_change event_type)1747 ifaddr_callback(void *context, const char *name, const addr_t *address, const addr_t *mask,
1748                 int ifindex, enum interface_address_change event_type)
1749 {
1750     served_domain_t *sd;
1751 
1752     if (address->sa.sa_family == AF_INET) {
1753         IPv4_ADDR_GEN_SRP((const uint8_t *)&address->sin.sin_addr, addr_buf);
1754         IPv4_ADDR_GEN_SRP((const uint8_t *)&mask->sin.sin_addr, mask_buf);
1755         INFO("Interface " PUB_S_SRP " address " PRI_IPv4_ADDR_SRP " mask " PRI_IPv4_ADDR_SRP " index %d " PUB_S_SRP,
1756              name, IPv4_ADDR_PARAM_SRP((const uint8_t *)&address->sin.sin_addr, addr_buf),
1757              IPv4_ADDR_PARAM_SRP((const uint8_t *)&mask->sin.sin_addr, mask_buf), ifindex,
1758              event_type == interface_address_added ? "added" : "removed");
1759     } else if (address->sa.sa_family == AF_INET6) {
1760         IPv6_ADDR_GEN_SRP((const uint8_t *)&address->sin.sin_addr, addr_buf);
1761         IPv6_ADDR_GEN_SRP((const uint8_t *)&mask->sin.sin_addr, mask_buf);
1762         INFO("Interface " PUB_S_SRP " address " PRI_IPv6_ADDR_SRP " mask " PRI_IPv6_ADDR_SRP " index %d " PUB_S_SRP,
1763              name, IPv6_ADDR_PARAM_SRP((const uint8_t *)&address->sin.sin_addr, addr_buf),
1764              IPv6_ADDR_PARAM_SRP((const uint8_t *)&mask->sin.sin_addr, mask_buf), ifindex,
1765              event_type == interface_address_added ? "added" : "removed");
1766     } else {
1767         INFO("Interface " PUB_S_SRP " address type %d index %d " PUB_S_SRP, name, address->sa.sa_family, ifindex,
1768              event_type == interface_address_added ? "added" : "removed");
1769     }
1770 
1771     for (sd = *((served_domain_t **)context); sd; sd = sd->next) {
1772         if (sd->interface != NULL && !strcmp(sd->interface->name, name)) {
1773             interface_addr_t **app, *ifaddr;
1774             if (event_type == interface_address_added) {
1775                 for (app = &sd->interface->addresses; *app; app = &(*app)->next)
1776                     ;
1777                 ifaddr = calloc(1, sizeof *ifaddr);
1778                 sd->interface->ifindex = ifindex;
1779                 if (ifaddr != NULL) {
1780                     ifaddr->addr = *address;
1781                     ifaddr->mask = *mask;
1782                     *app = ifaddr;
1783                 }
1784             } else if (event_type == interface_address_deleted) {
1785                 for (app = &sd->interface->addresses; *app; ) {
1786                     ifaddr = *app;
1787                     if (ifaddr->addr.sa.sa_family == address->sa.sa_family &&
1788                         ((address->sa.sa_family == AF_INET &&
1789                           ifaddr->addr.sin.sin_addr.s_addr == address->sin.sin_addr.s_addr &&
1790                           ifaddr->mask.sin.sin_addr.s_addr == address->sin.sin_addr.s_addr) ||
1791                          (address->sa.sa_family == AF_INET6 &&
1792                           !memcmp(&ifaddr->addr.sin6.sin6_addr, &address->sin6.sin6_addr, sizeof address->sin6.sin6_addr) &&
1793                           !memcmp(&ifaddr->mask.sin6.sin6_addr, &mask->sin6.sin6_addr, sizeof mask->sin6.sin6_addr))))
1794                     {
1795                         *app = ifaddr->next;
1796                         free(ifaddr);
1797                     } else {
1798                         app = &ifaddr->next;
1799                     }
1800                 }
1801                 if (sd->interface->addresses == NULL) {
1802                     sd->interface->ifindex = 0;
1803                 }
1804             }
1805         }
1806     }
1807 }
1808 
1809 // Config file parsing...
1810 static bool
interface_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1811 interface_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1812 {
1813     interface_t *interface = calloc(1, sizeof *interface);
1814     if (interface == NULL) {
1815         ERROR("Unable to allocate interface %s", hunks[1]);
1816         return false;
1817     }
1818 
1819     interface->name = strdup(hunks[1]);
1820     if (interface->name == NULL) {
1821         ERROR("Unable to allocate interface name %s", hunks[1]);
1822         free(interface);
1823         return false;
1824     }
1825 
1826     if (!strcmp(hunks[0], "nopush")) {
1827         interface->no_push = true;
1828     }
1829 
1830     if (new_served_domain(interface, hunks[2]) == NULL) {
1831         free(interface->name);
1832         free(interface);
1833         return false;
1834     }
1835     return true;
1836 }
1837 
port_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1838 static bool port_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1839 {
1840     char *ep = NULL;
1841     long port = strtol(hunks[1], &ep, 10);
1842     if (port < 0 || port > 65535 || *ep != 0) {
1843         ERROR("Invalid port number: %s", hunks[1]);
1844         return false;
1845     }
1846     if (!strcmp(hunks[0], "udp-port")) {
1847         udp_port = port;
1848     } else if (!strcmp(hunks[0], "tcp-port")) {
1849         tcp_port = port;
1850     } else if (!strcmp(hunks[0], "tls-port")) {
1851         tls_port = port;
1852     }
1853     return true;
1854 }
1855 
my_name_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1856 static bool my_name_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1857 {
1858     return config_string_handler(&my_name, filename, hunks[1], lineno, true, false);
1859 }
1860 
listen_addr_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1861 static bool listen_addr_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1862 {
1863     if (num_listen_addrs == MAX_ADDRS) {
1864         ERROR("Only %d IPv4 listen addresses can be configured.", MAX_ADDRS);
1865         return false;
1866     }
1867     return config_string_handler(&listen_addrs[num_listen_addrs++], filename, hunks[1], lineno, false, false);
1868 }
1869 
publish_addr_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1870 static bool publish_addr_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1871 {
1872     if (num_publish_addrs == MAX_ADDRS) {
1873         ERROR("Only %d addresses can be published.", MAX_ADDRS);
1874         return false;
1875     }
1876     return config_string_handler(&publish_addrs[num_publish_addrs++], filename, hunks[1], lineno, false, false);
1877 }
1878 
tls_key_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1879 static bool tls_key_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1880 {
1881     return config_string_handler(&tls_key_filename, filename, hunks[1], lineno, false, false);
1882 }
1883 
tls_cert_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1884 static bool tls_cert_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1885 {
1886     return config_string_handler(&tls_cert_filename, filename, hunks[1], lineno, false, false);
1887 }
1888 
tls_cacert_handler(void * context,const char * filename,char ** hunks,int num_hunks,int lineno)1889 static bool tls_cacert_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
1890 {
1891     return config_string_handler(&tls_cacert_filename, filename, hunks[1], lineno, false, false);
1892 }
1893 
1894 config_file_verb_t dp_verbs[] = {
1895     { "interface",    3, 3, interface_handler },    // interface <name> <domain>
1896     { "nopush",       3, 3, interface_handler },    // nopush <name> <domain>
1897     { "udp-port",     2, 2, port_handler },         // udp-port <number>
1898     { "tcp-port",     2, 2, port_handler },         // tcp-port <number>
1899     { "tls-port",     2, 2, port_handler },         // tls-port <number>
1900     { "my-name",      2, 2, my_name_handler },      // my-name <domain name>
1901     { "tls-key",      2, 2, tls_key_handler },      // tls-key <filename>
1902     { "tls-cert",     2, 2, tls_cert_handler },     // tls-cert <filename>
1903     { "tls-cacert",   2, 2, tls_cacert_handler },   // tls-cacert <filename>
1904     { "listen-addr",  2, 2, listen_addr_handler },  // listen-addr <IP address>
1905     { "publish-addr", 2, 2, publish_addr_handler }  // publish-addr <IP address>
1906 };
1907 #define NUMCFVERBS ((sizeof dp_verbs) / sizeof (config_file_verb_t))
1908 
1909 void
dnssd_push_setup()1910 dnssd_push_setup()
1911 {
1912     listener[num_listeners] = ioloop_setup_listener(AF_INET, true, true, tls_port, NULL, NULL,
1913                                                     "IPv4 DNS Push Listener", dns_input, NULL, NULL, NULL, NULL, NULL);
1914     if (listener[num_listeners] == NULL) {
1915         ERROR("IPv4 DNS Push listener: fail.");
1916         return;
1917     }
1918     num_listeners++;
1919 
1920     listener[num_listeners] = ioloop_setup_listener(AF_INET6, true, true,
1921                                                     "IPv6 DNS Push Listener", dns_input, NULL, NULL, NULL, NULL, NULL);
1922     if (listener[num_listeners] == NULL) {
1923         ERROR("IPv6 DNS Push listener: fail.");
1924         return;
1925     }
1926     num_listeners++;
1927 
1928     dnssd_hardwired_push_setup();
1929 }
1930 
1931 // Start a key generation or cert signing program.   Arguments are key=value pairs.
1932 // Arguments that can be constant should be <"key=value", NULL>.   Arguments that
1933 // have a variable component should be <"key", value">.  References to arguments
1934 // will be held, except that if the rhs of the pair is variable, memory is allocated
1935 // to store the key=value pair, so the neither the key nor the value is retained.
1936 // The callback is called when the program exits.
1937 
1938 void
keyprogram_start(const char * program,subproc_callback_t callback,...)1939 keyprogram_start(const char *program, subproc_callback_t callback, ...)
1940 {
1941 #define MAX_SUBPROC_VARS 3
1942     size_t lens[MAX_SUBPROC_VARS];
1943     char *vars[MAX_SUBPROC_VARS];
1944     int num_vars = 0;
1945     char *argv[MAX_SUBPROC_ARGS + 1];
1946     int argc = 0;
1947     va_list vl;
1948     int i;
1949 
1950     va_start(vl, callback);
1951     while (true) {
1952         char *vname, *value;
1953         char *arg;
1954 
1955         vname = va_arg(vl, char *);
1956         if (vname == NULL) {
1957             break;
1958         }
1959         value = va_arg(vl, char *);
1960 
1961         if (argc >= MAX_SUBPROC_ARGS) {
1962             ERROR("keyprogram_start: too many arguments.");
1963         }
1964 
1965         if (value == NULL) {
1966             arg = vname;
1967         } else {
1968             if (num_vars >= MAX_SUBPROC_VARS) {
1969                 ERROR("Too many variable args: %s %s", vname, value);
1970                 goto out;
1971             }
1972             lens[num_vars] = strlen(vname) + strlen(value) + 2;
1973             vars[num_vars] = malloc(lens[num_vars]);
1974             if (vars[num_vars] == NULL) {
1975                 ERROR("No memory for variable key=value %s %s", vname, value);
1976                 goto out;
1977             }
1978             snprintf(vars[num_vars], lens[num_vars], "%s=%s", vname, value);
1979             arg = vars[num_vars];
1980             num_vars++;
1981         }
1982         argv[argc++] = arg;
1983     }
1984     argv[argc] = NULL;
1985     ioloop_subproc(program, argv, argc, callback);
1986 out:
1987     for (i = 0; i < num_vars; i++) {
1988         free(vars[i]);
1989     }
1990 }
1991 
1992 bool
finished_okay(const char * context,int status,const char * error)1993 finished_okay(const char *context, int status, const char *error)
1994 {
1995     // If we get an error, something failed before the program had been successfully started.
1996     if (error != NULL) {
1997         ERROR("%s failed on startup: %s", context, error);
1998     }
1999 
2000     // The key file generation process completed
2001     else if (WIFEXITED(status)) {
2002         if (WEXITSTATUS(status) != 0) {
2003             ERROR("%s program exited with status %d", context, status);
2004             // And that means we don't have DNS Push--sorry!
2005         } else {
2006             return true;
2007         }
2008     } else if (WIFSIGNALED(status)) {
2009         ERROR("%s program exited on signal %d", context, WTERMSIG(status));
2010         // And that means we don't have DNS Push--sorry!
2011     } else if (WIFSTOPPED(status)) {
2012         ERROR("%s program stopped on signal %d", context, WSTOPSIG(status));
2013         // And that means we don't have DNS Push--sorry!
2014     } else {
2015         ERROR("%s program exit status unknown: %d", context, status);
2016         // And that means we don't have DNS Push--sorry!
2017     }
2018     return false;
2019 }
2020 
2021 // Called after the cert has been generated.
2022 void
certfile_finished_callback(subproc_t * subproc,int status,const char * error)2023 certfile_finished_callback(subproc_t *subproc, int status, const char *error)
2024 {
2025     // If we were able to generate a cert, we can start DNS Push service and start advertising it.
2026     if (finished_okay("Certificate signing", status, error)) {
2027         int i = num_listeners;
2028 
2029         dnssd_push_setup();
2030 
2031         for (; i < num_listeners; i++) {
2032             INFO("Started " PUB_S_SRP, listener[i]->name);
2033         }
2034     }
2035 }
2036 
2037 // Called after the key has been generated.
2038 void
keyfile_finished_callback(subproc_t * subproc,int status,const char * error)2039 keyfile_finished_callback(subproc_t *subproc, int status, const char *error)
2040 {
2041     if (finished_okay("Keyfile generation", status, error)) {
2042             INFO("Keyfile generation completed.");
2043 
2044             // XXX dates need to not be constant!!!
2045             keyprogram_start(CERTWRITE_PROGRAM, certfile_finished_callback,
2046                              "selfsign=1", NULL, "issuer_key", tls_key_filename, "issuer_name=CN", my_name,
2047                              "not_before=20190226000000", NULL, "not_after=20211231235959", NULL, "is_ca=1", NULL,
2048                              "max_pathlen=0", NULL, "output_file", tls_cert_filename, NULL);
2049     }
2050 
2051 }
2052 
2053 int
main(int argc,char ** argv)2054 main(int argc, char **argv)
2055 {
2056     int i;
2057     bool tls_fail = false;
2058 
2059     udp_port = tcp_port = 53;
2060     tls_port = 853;
2061 
2062     // Parse command line arguments
2063     for (i = 1; i < argc; i++) {
2064         if (!strcmp(argv[i], "--tls-fail")) {
2065             tls_fail = true;
2066         } else {
2067             return usage(argv[0]);
2068         }
2069     }
2070 
2071     // Read the config file
2072     if (!config_parse(NULL, "/etc/dnssd-proxy.cf", dp_verbs, NUMCFVERBS)) {
2073         return 1;
2074     }
2075 
2076     // Insist that we have at least one address we're listening on.
2077     if (num_listen_addrs == 0 && num_publish_addrs == 0) {
2078         ERROR("Please configure at least one my-ipv4-addr and/or one my-ipv6-addr.");
2079         return 1;
2080     }
2081 
2082     ioloop_map_interface_addresses(&served_domains, ifaddr_callback);
2083 
2084     // Set up hardwired answers
2085     dnssd_hardwired_setup();
2086 
2087 #ifndef EXCLUDE_TLS
2088     if (!srp_tls_init()) {
2089         return 1;
2090     }
2091 
2092     // The tls_fail flag allows us to run the proxy in such a way that TLS connections will fail.
2093     // This is never what you want in production, but is useful for testing.
2094     if (!tls_fail) {
2095         if (access(tls_key_filename, R_OK) < 0) {
2096             keyprogram_start(GENKEY_PROGRAM, keyfile_finished_callback,
2097                              "type=rsa", NULL, "rsa_keysize=4096", NULL, "filename", tls_key_filename, NULL);
2098         } else if (access(tls_cert_filename, R_OK) < 0) {
2099             keyfile_finished_callback(NULL, 0, NULL);
2100         } else if (srp_tls_server_init(NULL, tls_cert_filename, tls_key_filename)) {
2101             // If we've been able to set up TLS, then we can do DNS push.
2102             dnssd_push_setup();
2103         }
2104     }
2105 #endif
2106 
2107     if (!ioloop_init()) {
2108         return 1;
2109     }
2110 
2111     for (i = 0; i < num_listen_addrs; i++) {
2112         listener[num_listeners] = ioloop_setup_listener(AF_UNSPEC, false, false, udp_port, listen_addrs[i], NULL,
2113                                                         "DNS UDP Listener", dns_input, NULL, NULL, NULL, NULL, NULL);
2114         if (listener[num_listeners] == NULL) {
2115             ERROR("UDP listener %s: fail.", listen_addrs[i]);
2116             return 1;
2117         }
2118         num_listeners++;
2119     }
2120 
2121     listener[num_listeners] = ioloop_setup_listener(AF_INET, true, false, tcp_port, NULL, NULL,
2122                                                     "IPv4 TCP DNS Listener", dns_input, NULL, NULL, NULL, NULL, NULL);
2123     if (listener[num_listeners] == NULL) {
2124         ERROR("TCPv4 listener: fail.");
2125         return 1;
2126     } else {
2127         num_listeners++;
2128     }
2129 
2130     listener[num_listeners] = ioloop_setup_listener(AF_INET6, true, false, tcp_port, NULL, NULL,
2131                                                     "IPv6 TCP DNS Listener", dns_input, NULL, NULL, NULL, NULL, NULL);
2132     if (listener[num_listeners] == NULL) {
2133         ERROR("TCPv6 listener: fail.");
2134         return 1;
2135     } else {
2136         num_listeners++;
2137     }
2138 
2139     // If we haven't been given any addresses to listen on, listen on an IPv4 address and an IPv6 address.
2140     if (num_listen_addrs == 0) {
2141         listener[num_listeners] = ioloop_setup_listener(AF_INET, IPPROTO_UDP, false, udp_port, NULL, NULL,
2142                                                         "IPv4 DNS UDP Listener", dns_input, NULL, NULL, NULL, NULL,
2143                                                         NULL);
2144         if (listener[num_listeners] == NULL) {
2145             ERROR("UDP4 listener: fail.");
2146             return 1;
2147         }
2148         num_listeners++;
2149 
2150         listener[num_listeners] = ioloop_setup_listener(AF_INET6, IPPROTO_UDP, false, udp_port, NULL, NULL,
2151                                                         "IPv6 DNS UDP Listener", dns_input, NULL, NULL, NULL, NULL,
2152                                                         NULL);
2153        if (listener[num_listeners] == NULL) {
2154             ERROR("UDP6 listener: fail.");
2155             return 1;
2156         }
2157         num_listeners++;
2158     }
2159 
2160     for (i = 0; i < num_listeners; i++) {
2161         INFO("Started " PUB_S_SRP, listener[i]->name);
2162     }
2163 
2164     ioloop();
2165 }
2166 
2167 // Local Variables:
2168 // mode: C
2169 // tab-width: 4
2170 // c-file-style: "bsd"
2171 // c-basic-offset: 4
2172 // fill-column: 108
2173 // indent-tabs-mode: nil
2174 // End:
2175