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