3 * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * This is a Discovery Proxy module for the SRP gateway.
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.
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:
28 * https://opensource.apple.com/tarballs/mDNSResponder/
31 #define __APPLE_USE_RFC_3542
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
44 #include <sys/types.h>
52 #include "srp-crypto.h"
53 #define DNSMessageHeader dns_wire_t
57 #include "config-parse.h"
59 // Enumerate the list of interfaces, map them to interface indexes, give each one a name
60 // Have a tree of subdomains for matching
62 // Configuration file settings
66 char *my_name
= "discoveryproxy.home.arpa.";
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;
78 typedef struct hardwired hardwired_t
;
88 typedef struct interface_addr interface_addr_t
;
89 struct interface_addr
{
90 interface_addr_t
*next
;
94 typedef struct interface interface_t
;
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.
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).
112 typedef struct dnssd_query
{
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.
118 // If we've already copied out the enclosing domain once in a DNS message.
119 dns_name_pointer_t enclosing_domain_pointer
;
123 dso_activity_t
*activity
;
124 int serviceFlags
; // Service flags to use with this query.
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
134 const char push_subscription_activity_type
[] = "push subscription";
136 const char local_suffix
[] = ".local.";
138 #define TOWIRE_CHECK(note, towire, func) { func; if ((towire)->error != 0 && failnote == NULL) failnote = (note); }
140 // Forward references
141 static served_domain_t
*NULLABLE
new_served_domain(interface_t
*NULLABLE interface
, char *NONNULL domain
);
145 int64_t dso_transport_idle(void *context
, int64_t now
, int64_t next_event
)
150 void dnssd_query_cancel(dnssd_query_t
*query
)
152 if (query
->txn
!= NULL
) {
153 ioloop_dnssd_txn_cancel(query
->txn
);
154 ioloop_dnssd_txn_release(query
->txn
);
157 query
->connection
= NULL
;
160 void dnssd_query_close_callback(void *context
, int status
)
162 dnssd_query_t
*query
= context
;
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
)
168 if (query
->activity
!= NULL
&& query
->connection
!= NULL
) {
169 dso_drop_activity(query
->connection
->dso
, query
->activity
);
171 dnssd_query_cancel(query
);
176 dns_push_finalize(dso_activity_t
*activity
)
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
);
184 dnssd_query_finalize_callback(void *context
)
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
)
192 ioloop_dnssd_txn_cancel(query
->txn
);
193 ioloop_dnssd_txn_release(query
->txn
);
196 if (query
->question
) {
197 message_free(query
->question
);
204 dp_simple_response(comm_t
*comm
, int rcode
)
206 if (comm
->send_response
) {
209 memset(&response
, 0, DNS_HEADER_SIZE
);
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);
225 dso_send_formerr(dso_state_t
*dso
, const dns_wire_t
*header
)
227 comm_t
*transport
= dso
->transport
;
229 dp_simple_response(transport
, dns_rcode_formerr
);
234 dp_served(dns_name_t
*name
, char *buf
, size_t bufsize
)
236 served_domain_t
*sdt
;
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
);
248 // Utility function to find "local" on the end of a string of labels.
250 truncate_local(dns_name_t
*name
)
252 dns_label_t
*lp
, *prev
, *prevprev
;
254 prevprev
= prev
= NULL
;
255 // Find the root label.
256 for (lp
= name
; lp
&& lp
->len
; lp
= lp
->next
) {
260 if (lp
&& prev
&& prevprev
) {
261 if (prev
->len
== 5 && dns_labels_equal(prev
->data
, "local", 5)) {
263 prevprev
->next
= NULL
;
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
)
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.
283 INFO("Eliding zero-length response for " PRI_S_SRP
" %d %d", fullname
, rrtype
, rrclass
);
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
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
));
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
));
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
));
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
));
317 INFO("dp_query_add_data_to_response: survived for rrtype %d rdlen %d", rrtype
, rdlen
);
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
);
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
);
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
));
335 // If necessary, correct domain names inside of rrdata.
340 answer
.type
= rrtype
;
341 answer
.qclass
= rrclass
;
342 if (dns_rdata_parse_data(&answer
, rdata
, &offp
, rdlen
, rdlen
, 0)) {
344 case dns_rrtype_cname
:
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
));
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
));
365 INFO("record type %d not translated", rrtype
);
369 dns_name_print(name
, rbuf
, sizeof rbuf
);
371 // If the name ends in .local, truncate it.
372 if ((local
= truncate_local(name
))) {
373 dns_name_print(name
, pbuf
, sizeof pbuf
);
376 // If the name ended in .local, concatenate the interface domain name to the end.
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
);
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
);
388 dns_rdlength_end(towire
);
390 ERROR("dp_query_add_data_to_response: rdata from mDNSResponder didn't parse!!");
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
));
396 TOWIRE_CHECK("rdlen", towire
, dns_u16_to_wire(towire
, rdlen
));
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
;
405 dnssd_hardwired_add(served_domain_t
*sdt
,
406 const char *name
, const char *domain
, size_t rdlen
, uint8_t *rdata
, uint16_t type
)
408 hardwired_t
*hp
, **hrp
;
409 int namelen
= strlen(name
);
410 size_t total
= sizeof *hp
;
412 total
+= rdlen
; // Space for RDATA
413 total
+= namelen
; // Space for name
415 total
+= namelen
;// space for FQDN
416 total
+= strlen(domain
);
419 hp
= calloc(1, total
+ 4);
421 ERROR("no memory for %s %s", name
, domain
);
424 trailer
= ((uint8_t *)hp
) + total
;
425 memcpy(trailer
, "abcd", 4);
426 hp
->rdata
= (uint8_t *)(hp
+ 1);
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;
433 strcpy(hp
->fullname
, name
);
434 strcpy(hp
->fullname
+ namelen
, domain
);
436 strcpy(hp
->fullname
, domain
);
438 if (hp
->fullname
+ strlen(hp
->fullname
) + 1 != (char *)hp
+ total
) {
439 ERROR("%p != %p", hp
->fullname
+ strlen(hp
->fullname
) + 1, ((char *)hp
) + total
);
442 if (memcmp(trailer
, "abcd", 4)) {
443 ERROR("ran off the end.");
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
;
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
);
467 void dnssd_hardwired_lbdomains_setup(dns_towire_state_t
*towire
, dns_wire_t
*wire
)
469 served_domain_t
*ip6
= NULL
, *ipv4
= NULL
, *addr_domain
, *interface_domain
;
470 char name
[DNS_MAX_NAME_SIZE
+ 1];
473 memset(towire, 0, sizeof *towire); \
474 towire->message = wire; \
475 towire->p = wire->data; \
476 towire->lim = towire->p + sizeof wire->data
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
);
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
);
492 int space
= sizeof name
;
495 if (address
[0] == 127) {
496 INFO("Skipping IPv4 loopback address on " PRI_S_SRP
" (" PUB_S_SRP
")",
497 addr_domain
->domain
, interface
->name
);
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
);
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
]);
514 ipv4
= new_served_domain(NULL
, "in-addr.arpa.");
516 ERROR("No space for in-addr.arpa.");
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) {
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
,
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
);
537 int space
= sizeof name
;
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
,
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
,
550 snprintf(name
, space
, "lb._dns-sd._udp");
551 bp
= name
+ strlen(name
);
552 for (i
= 16; i
>= 0; 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);
561 ip6
= new_served_domain(NULL
, "ip6.arpa.");
563 ERROR("No space for ip6.arpa.");
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) {
573 INFO("Adding PTR from " PRI_S_SRP
" to " PRI_S_SRP
, name
, interface_domain
->domain
);
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
);
579 char buf
[INET6_ADDRSTRLEN
];
580 IOLOOP_NTOP(&ifaddr
->addr
, buf
);
581 INFO("Skipping " PRI_S_SRP
, buf
);
589 dnssd_hardwired_setup(void)
592 dns_towire_state_t towire
;
593 served_domain_t
*sdt
;
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
;
601 memset(&towire, 0, sizeof towire); \
602 towire.message = &wire; \
603 towire.p = wire.data; \
604 towire.lim = towire.p + sizeof wire.data
606 // For each interface, set up the hardwired names.
607 for (sdt
= served_domains
; sdt
; sdt
= sdt
->next
) {
608 if (sdt
->interface
== NULL
) {
616 // _dns-update-tls._udp
617 // We deny the presence of support for LLQ, because we only support DNS Push
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
);
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
,
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
);
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
) {
637 local_domain
= sdt
->domain_ld
;
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
;
651 local_domain
= sdt
->domain_ld
;
655 if (local_name
!= NULL
) {
656 for (i
= 0; i
< num_publish_addrs
; i
++) {
658 memset(&addr
, 0, sizeof addr
);
659 getipaddr(&addr
, publish_addrs
[i
]);
660 if (addr
.sa
.sa_family
== AF_INET
) {
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
,
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
,
679 if (my_name
!= NULL
) {
680 dns_full_name_to_wire(NULL
, &towire
, my_name
);
682 dns_name_to_wire(NULL
, &towire
, "ns");
683 dns_full_name_to_wire(NULL
, &towire
, sdt
->domain
);
685 dnssd_hardwired_add(sdt
, "", sdt
->domain
, towire
.p
- wire
.data
, wire
.data
, dns_rrtype_ns
);
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
);
698 if (my_name_parsed
!= NULL
) {
699 dns_name_free(my_name_parsed
);
700 my_name_parsed
= NULL
;
702 sdt
= new_served_domain(NULL
, my_name
);
704 ERROR("Unable to allocate domain for %s", my_name
);
706 for (i
= 0; i
< num_publish_addrs
; i
++) {
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
);
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
);
722 dnssd_hardwired_lbdomains_setup(&towire
, &wire
);
726 dnssd_hardwired_push_setup(void)
729 dns_towire_state_t towire
;
730 served_domain_t
*sdt
;
733 memset(&towire, 0, sizeof towire); \
734 towire.message = &wire; \
735 towire.p = wire.data; \
736 towire.lim = towire.p + sizeof wire.data
738 // For each interface, set up the hardwired names.
739 for (sdt
= served_domains
; sdt
; sdt
= sdt
->next
) {
740 if (sdt
->interface
== NULL
) {
744 if (!sdt
->interface
->no_push
) {
746 // _dns-push-tls._tcp
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
);
756 dns_full_name_to_wire(NULL
, &towire
, my_name
);
758 dnssd_hardwired_add(sdt
, "_dns-push-tls._tcp", sdt
->domain_ld
, towire
.p
- wire
.data
, wire
.data
,
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
,
770 embiggen(dnssd_query_t
*query
)
772 dns_wire_t
*nr
= malloc(query
->data_size
+ sizeof *nr
); // increments wire size by DNS_DATA_SIZE
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
;
790 dp_query_send_dns_response(dnssd_query_t
*query
)
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
);
800 // Send an SOA record if it's a .local query.
801 if (query
->served_domain
!= NULL
&& query
->served_domain
->interface
!= NULL
&& !towire
->truncated
) {
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
));
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
));
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;
841 query
->response
->nscount
= htons(1);
844 // Response is authoritative and not recursive.
845 mask
= ~dns_flags_ra
;
846 bitfield
= bitfield
| dns_flags_aa
| tc
;
847 bitfield
= bitfield
& mask
;
849 // Response is recursive and not authoritative.
850 mask
= ~dns_flags_aa
;
851 bitfield
= bitfield
| dns_flags_ra
| tc
;
852 bitfield
= bitfield
& mask
;
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
);
859 // This is a response
860 dns_qr_set(query
->response
, dns_qr_response
);
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
) {
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;
883 query
->response
->arcount
= htons(1);
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
);
892 dns_rcode_set(query
->response
, dns_rcode_servfail
);
896 dns_rcode_set(query
->response
, dns_rcode_noerror
);
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
);
903 if (query
->connection
!= NULL
) {
904 query
->connection
->send_response(query
->connection
, query
->question
, &iov
, 1);
908 // Query will be freed automatically next time through the io loop.
909 dnssd_query_cancel(query
);
913 dp_query_towire_reset(dnssd_query_t
*query
)
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
;
924 dns_push_start(dnssd_query_t
*query
)
926 const char *failnote
= NULL
;
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
);
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
);
944 query
->p_dso_length
= query
->towire
.p
;
945 query
->towire
.p
+= 2;
947 if (failnote
!= NULL
) {
948 ERROR("dns_push_start: couldn't start update: %s", failnote
);
953 dp_push_response(dnssd_query_t
*query
)
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
);
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);
968 dp_query_towire_reset(query
);
973 dnssd_hardwired_response(dnssd_query_t
*query
, DNSServiceQueryRecordReply callback
)
976 bool got_response
= false;
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);
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
,
989 if (!query
->towire
.truncated
) {
990 query
->response
->ancount
= htons(ntohs(query
->response
->ancount
) + 1);
998 if (query
->is_dns_push
) {
999 dp_push_response(query
);
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
);
1012 // This is the callback for dns query results.
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
)
1018 dnssd_query_t
*query
= context
;
1020 INFO(PRI_S_SRP
" %d %d %x %d", fullname
, rrtype
, rrclass
, rdlen
, errorCode
);
1022 if (errorCode
== kDNSServiceErr_NoError
) {
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;
1033 dns_rcode_set(query
->response
, dns_rcode_servfail
);
1034 dp_query_send_dns_response(query
);
1039 query
->response
->ancount
= htons(ntohs(query
->response
->ancount
) + 1);
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
) {
1047 dp_query_send_dns_response(query
);
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
);
1054 dns_rcode_set(query
->response
, dns_rcode_servfail
);
1055 dp_query_send_dns_response(query
);
1060 dp_query_wakeup(void *context
)
1062 dnssd_query_t
*query
= context
;
1063 char name
[DNS_MAX_NAME_SIZE
+ 1];
1064 int namelen
= strlen(query
->name
);
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
);
1076 strcpy(name
, query
->name
);
1077 if (query
->served_domain
!= NULL
) {
1078 strcpy(name
+ namelen
, local_suffix
);
1080 dp_query_send_dns_response(query
);
1084 dp_query_start(comm_t
*comm
, dnssd_query_t
*query
, int *rcode
, DNSServiceQueryRecordReply callback
)
1086 char name
[DNS_MAX_NAME_SIZE
+ 1];
1090 DNSServiceRef sdref
;
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
;
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
;
1105 ERROR("question name %s is too long for .local.", name
);
1108 memcpy(name
, query
->name
, len
);
1109 memcpy(&name
[len
], local_suffix
, sizeof local_suffix
);
1111 int dlen
= strlen(query
->served_domain
->domain_ld
) + 1;
1112 if (len
+ dlen
> sizeof name
) {
1113 *rcode
= dns_rcode_servfail
;
1116 ERROR("question name %s is too long for %s.", name
, query
->served_domain
->domain
);
1119 memcpy(name
, query
->name
, len
);
1120 memcpy(&name
[len
], query
->served_domain
->domain_ld
, dlen
);
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
);
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
;
1150 query
->txn
= ioloop_dnssd_txn_add(sdref
, dnssd_query_finalize_callback
, dnssd_query_close_callback
);
1151 if (query
->txn
== NULL
) {
1154 INFO("dp_query_start: DNSServiceQueryRecord started for '" PRI_S_SRP
"': %d", np
, err
);
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
;
1169 ioloop_add_wake_event(query
->wakeup
, query
, dp_query_wakeup
, ioloop_timenow() + IOLOOP_SECOND
* 6);
1175 dp_query_generate(comm_t
*comm
, dns_rr_t
*question
, bool dns_push
, int *rcode
)
1177 char name
[DNS_MAX_NAME_SIZE
+ 1];
1178 served_domain_t
*sdt
= dp_served(question
->name
, name
, sizeof name
);
1180 // If it's a query for a name served by the local discovery proxy, do an mDNS lookup.
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
);
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
);
1190 dnssd_query_t
*query
= calloc(1,sizeof *query
);
1191 if (query
== NULL
) {
1193 ERROR("Unable to allocate memory for query on %s", name
);
1194 *rcode
= dns_rcode_servfail
;
1197 query
->response
= malloc(sizeof *query
->response
);
1198 if (query
->response
== NULL
) {
1201 query
->data_size
= DNS_DATA_SIZE
;
1203 // Zero out the DNS header, but not the data.
1204 memset(query
->response
, 0, DNS_HEADER_SIZE
);
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
);
1211 *rcode
= dns_rcode_servfail
;
1213 ERROR("unable to allocate memory for question name on %s", name
);
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;
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
;
1224 query
->serviceFlags
|= kDNSServiceFlagsReturnIntermediates
;
1226 // Name now contains the name we want mDNSResponder to look up.
1228 // XXX make sure finalize does the right thing.
1229 query
->connection
= comm
;
1231 // Remember whether this is a long-lived query.
1232 query
->is_dns_push
= dns_push
;
1234 // Start writing the response
1235 dp_query_towire_reset(query
);
1237 query
->type
= question
->type
;
1238 query
->qclass
= question
->qclass
;
1240 *rcode
= dns_rcode_noerror
;
1244 // This is the callback for DNS push query results, as opposed to push updates.
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
)
1250 dnssd_query_t
*query
= context
;
1251 uint8_t *revert
= query
->towire
.p
;
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).
1257 // The spec says to not query if we have cached answers. We trust the DNSServiceQueryRecord call to handle this.
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
1263 INFO("PUSH " PRI_S_SRP
" %d %d %x %d", fullname
, rrtype
, rrclass
, rdlen
, errorCode
);
1265 // query_state_waiting means that we're answering a regular DNS question
1266 if (errorCode
== kDNSServiceErr_NoError
) {
1267 dns_push_start(query
);
1269 // If kDNSServiceFlagsAdd is set, it's an add, otherwise a delete.
1271 if (flags
& kDNSServiceFlagsAdd
) {
1272 dp_query_add_data_to_response(query
, fullname
, rrtype
, rrclass
, rdlen
, rdata
, ttl
);
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.
1279 dp_query_add_data_to_response(query
, fullname
, rrtype
, dns_qclass_any
, rdlen
, rdata
, -2);
1282 dp_query_add_data_to_response(query
, fullname
, rrtype
, dns_qclass_none
, rdlen
, rdata
, -2);
1284 dp_query_add_data_to_response(query
, fullname
, rrtype
, rrclass
, rdlen
, rdata
, -1);
1289 dp_query_add_data_to_response(query
, fullname
, rrtype
, dns_qclass_any
, rdlen
, rdata
, 0);
1291 dp_query_add_data_to_response(query
, fullname
, rrtype
, dns_qclass_none
, rdlen
, rdata
, 0);
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
);
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
);
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
);
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
)
1322 dnssd_query_t
*query
= dp_query_generate(comm
, question
, true, &rcode
);
1325 dp_simple_response(comm
, rcode
);
1329 dso_activity_t
*activity
= dso_add_activity(dso
, activity_name
, push_subscription_activity_type
, query
,
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
);
1337 dp_simple_response(comm
, dns_rcode_noerror
);
1341 dns_push_reconfirm(comm_t
*comm
, const dns_wire_t
*header
, dso_state_t
*dso
)
1344 char name
[DNS_MAX_NAME_SIZE
+ 1];
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
;
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
);
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
);
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
);
1373 memcpy(&name
[len
], local_suffix
, sizeof local_suffix
);
1375 dns_name_print(question
.name
, &name
[8], sizeof name
- 8);
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
);
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
)
1387 dso_drop_activity(dso
, activity
);
1388 // No response, unsubscribe is unidirectional.
1392 dns_push_subscription_change(const char *opcode_name
, comm_t
*comm
, const dns_wire_t
*header
, dso_state_t
*dso
)
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
;
1398 // The TLV offset should always be pointing into the message.
1399 unsigned offp
= dso
->primary
.payload
- &header
->data
[0];
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
);
1408 ERROR("RR parse for %s from %s failed", dso
->remote_name
, opcode_name
);
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
);
1420 const int lslen
= sizeof local_suffix
;
1421 strncpy(&activity_name
[len
], local_suffix
, lslen
);
1423 dns_name_print(question
.name
, &activity_name
[8], (sizeof activity_name
) - 8);
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
);
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
);
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
);
1443 // Otherwise cancel the subscription.
1445 dns_push_unsubscribe(comm
, header
, dso
, &question
, activity
, opcode_name
);
1450 static void dso_message(comm_t
*comm
, const dns_wire_t
*header
, dso_state_t
*dso
)
1452 switch(dso
->primary
.opcode
) {
1453 case kDSOType_DNSPushSubscribe
:
1454 dns_push_subscription_change("DNS Push Subscribe", comm
, header
, dso
);
1456 case kDSOType_DNSPushUnsubscribe
:
1457 dns_push_subscription_change("DNS Push Unsubscribe", comm
, header
, dso
);
1460 case kDSOType_DNSPushReconfirm
:
1461 dns_push_reconfirm(comm
, header
, dso
);
1464 case kDSOType_DNSPushUpdate
:
1465 INFO("dso_message: bogus push update message %d", dso
->primary
.opcode
);
1470 INFO("dso_message: unexpected primary TLV %d", dso
->primary
.opcode
);
1471 dp_simple_response(comm
, dns_rcode_dsotypeni
);
1474 // XXX free the message if we didn't consume it.
1477 static void dns_push_callback(void *context
, const void *event_context
,
1478 dso_state_t
*dso
, dso_event_type_t eventType
)
1480 const dns_wire_t
*message
;
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
),
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
),
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
);
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
);
1506 case kDSOEventType_Finalize
:
1507 INFO("dns_push_callback: Finalize");
1510 case kDSOEventType_Connected
:
1511 INFO("dns_push_callback: Connected to " PRI_S_SRP
, dso
->remote_name
);
1514 case kDSOEventType_ConnectFailed
:
1515 INFO("dns_push_callback: Connection to " PRI_S_SRP
" failed", dso
->remote_name
);
1518 case kDSOEventType_Disconnected
:
1519 INFO("dns_push_callback: Connection to " PRI_S_SRP
" disconnected", dso
->remote_name
);
1521 case kDSOEventType_ShouldReconnect
:
1522 INFO("dns_push_callback: Connection to " PRI_S_SRP
" should reconnect (not for a server)", dso
->remote_name
);
1524 case kDSOEventType_Inactive
:
1525 INFO("dns_push_callback: Inactivity timer went off, closing connection.");
1527 case kDSOEventType_Keepalive
:
1528 INFO("dns_push_callback: should send a keepalive now.");
1530 case kDSOEventType_KeepaliveRcvd
:
1531 INFO("dns_push_callback: keepalive received.");
1533 case kDSOEventType_RetryDelay
:
1534 INFO("dns_push_callback: keepalive received.");
1540 dp_dns_query(comm_t
*comm
, dns_rr_t
*question
)
1543 dnssd_query_t
*query
= dp_query_generate(comm
, question
, false, &rcode
);
1544 const char *failnote
= NULL
;
1546 dp_simple_response(comm
, rcode
);
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
);
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
));
1563 TOWIRE_CHECK("full name", &query
->towire
, dns_full_name_to_wire(NULL
, &query
->towire
, query
->name
));
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
);
1572 // We should check for OPT RR, but for now assume it's there.
1573 query
->is_edns0
= true;
1575 if (!dp_query_start(comm
, query
, &rcode
, dns_query_callback
)) {
1577 dp_simple_response(comm
, rcode
);
1583 // XXX make sure that finalize frees this.
1584 if (comm
->message
) {
1585 query
->question
= comm
->message
;
1586 comm
->message
= NULL
;
1590 void dso_transport_finalize(comm_t
*comm
)
1592 dso_state_t
*dso
= comm
->dso
;
1593 INFO("dso_transport_finalize: " PRI_S_SRP
, dso
->remote_name
);
1595 ioloop_close(&comm
->io
);
1601 void dns_evaluate(comm_t
*comm
)
1604 unsigned offset
= 0;
1606 // Drop incoming responses--we're a server, so we only accept queries.
1607 if (dns_qr_get(&comm
->message
->wire
) == dns_qr_response
) {
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
);
1621 comm
->dso
= dso_create(true, 0, comm
->name
, dns_push_callback
, comm
, comm
);
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
);
1628 comm
->dso
->transport_finalize
= dso_transport_finalize
;
1630 dso_message_received(comm
->dso
, (uint8_t *)&comm
->message
->wire
, comm
->message
->length
);
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
);
1640 if (!dns_rr_parse(&question
, comm
->message
->wire
.data
, comm
->message
->length
, &offset
, 0)) {
1641 dp_simple_response(comm
, dns_rcode_formerr
);
1644 dp_dns_query(comm
, &question
);
1645 dns_rrdata_free(&question
);
1648 // No support for other opcodes yet.
1650 dp_simple_response(comm
, dns_rcode_notimp
);
1655 void dns_input(comm_t
*comm
)
1658 if (comm
->message
!= NULL
) {
1659 message_free(comm
->message
);
1660 comm
->message
= NULL
;
1665 usage(const char *progname
)
1667 ERROR("usage: %s", progname
);
1668 ERROR("ex: dnssd-proxy");
1672 // Called whenever we get a connection.
1674 connected(comm_t
*comm
)
1676 INFO("connection from " PRI_S_SRP
, comm
->name
);
1680 static bool config_string_handler(char **ret
, const char *filename
, const char *string
, int lineno
, bool tdot
,
1684 int add_trailing_dot
= 0;
1685 int add_leading_dot
= ldot
? 1 : 0;
1686 int len
= strlen(string
);
1688 // Space for NUL and leading dot.
1689 if (tdot
&& len
> 0 && string
[len
- 1] != '.') {
1690 add_trailing_dot
= 1;
1692 s
= malloc(strlen(string
) + add_leading_dot
+ add_trailing_dot
+ 1);
1694 ERROR("Unable to allocate domain name %s", string
);
1702 if (add_trailing_dot
) {
1709 static served_domain_t
*
1710 new_served_domain(interface_t
*interface
, char *domain
)
1712 served_domain_t
*sdt
= calloc(1, sizeof *sdt
);
1714 ERROR("Unable to allocate served domain %s", domain
);
1717 sdt
->domain_ld
= malloc(strlen(domain
) + 2);
1718 if (sdt
->domain_ld
== NULL
) {
1719 ERROR("Unable to allocate served domain name %s", domain
);
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
);
1732 ERROR("invalid domain name: %s", sdt
->domain
);
1737 sdt
->next
= served_domains
;
1738 served_domains
= sdt
;
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.
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
)
1750 served_domain_t
*sd
;
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");
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");
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
)
1777 ifaddr
= calloc(1, sizeof *ifaddr
);
1778 sd
->interface
->ifindex
= ifindex
;
1779 if (ifaddr
!= NULL
) {
1780 ifaddr
->addr
= *address
;
1781 ifaddr
->mask
= *mask
;
1784 } else if (event_type
== interface_address_deleted
) {
1785 for (app
= &sd
->interface
->addresses
; *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
))))
1795 *app
= ifaddr
->next
;
1798 app
= &ifaddr
->next
;
1801 if (sd
->interface
->addresses
== NULL
) {
1802 sd
->interface
->ifindex
= 0;
1809 // Config file parsing...
1811 interface_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1813 interface_t
*interface
= calloc(1, sizeof *interface
);
1814 if (interface
== NULL
) {
1815 ERROR("Unable to allocate interface %s", hunks
[1]);
1819 interface
->name
= strdup(hunks
[1]);
1820 if (interface
->name
== NULL
) {
1821 ERROR("Unable to allocate interface name %s", hunks
[1]);
1826 if (!strcmp(hunks
[0], "nopush")) {
1827 interface
->no_push
= true;
1830 if (new_served_domain(interface
, hunks
[2]) == NULL
) {
1831 free(interface
->name
);
1838 static bool port_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1841 long port
= strtol(hunks
[1], &ep
, 10);
1842 if (port
< 0 || port
> 65535 || *ep
!= 0) {
1843 ERROR("Invalid port number: %s", hunks
[1]);
1846 if (!strcmp(hunks
[0], "udp-port")) {
1848 } else if (!strcmp(hunks
[0], "tcp-port")) {
1850 } else if (!strcmp(hunks
[0], "tls-port")) {
1856 static bool my_name_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1858 return config_string_handler(&my_name
, filename
, hunks
[1], lineno
, true, false);
1861 static bool listen_addr_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1863 if (num_listen_addrs
== MAX_ADDRS
) {
1864 ERROR("Only %d IPv4 listen addresses can be configured.", MAX_ADDRS
);
1867 return config_string_handler(&listen_addrs
[num_listen_addrs
++], filename
, hunks
[1], lineno
, false, false);
1870 static bool publish_addr_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1872 if (num_publish_addrs
== MAX_ADDRS
) {
1873 ERROR("Only %d addresses can be published.", MAX_ADDRS
);
1876 return config_string_handler(&publish_addrs
[num_publish_addrs
++], filename
, hunks
[1], lineno
, false, false);
1879 static bool tls_key_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1881 return config_string_handler(&tls_key_filename
, filename
, hunks
[1], lineno
, false, false);
1884 static bool tls_cert_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1886 return config_string_handler(&tls_cert_filename
, filename
, hunks
[1], lineno
, false, false);
1889 static bool tls_cacert_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
1891 return config_string_handler(&tls_cacert_filename
, filename
, hunks
[1], lineno
, false, false);
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>
1907 #define NUMCFVERBS ((sizeof dp_verbs) / sizeof (config_file_verb_t))
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.");
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.");
1928 dnssd_hardwired_push_setup();
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.
1939 keyprogram_start(const char *program
, subproc_callback_t callback
, ...)
1941 #define MAX_SUBPROC_VARS 3
1942 size_t lens
[MAX_SUBPROC_VARS
];
1943 char *vars
[MAX_SUBPROC_VARS
];
1945 char *argv
[MAX_SUBPROC_ARGS
+ 1];
1950 va_start(vl
, callback
);
1952 char *vname
, *value
;
1955 vname
= va_arg(vl
, char *);
1956 if (vname
== NULL
) {
1959 value
= va_arg(vl
, char *);
1961 if (argc
>= MAX_SUBPROC_ARGS
) {
1962 ERROR("keyprogram_start: too many arguments.");
1965 if (value
== NULL
) {
1968 if (num_vars
>= MAX_SUBPROC_VARS
) {
1969 ERROR("Too many variable args: %s %s", vname
, value
);
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
);
1978 snprintf(vars
[num_vars
], lens
[num_vars
], "%s=%s", vname
, value
);
1979 arg
= vars
[num_vars
];
1985 ioloop_subproc(program
, argv
, argc
, callback
);
1987 for (i
= 0; i
< num_vars
; i
++) {
1993 finished_okay(const char *context
, int status
, const char *error
)
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
);
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!
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!
2015 ERROR("%s program exit status unknown: %d", context
, status
);
2016 // And that means we don't have DNS Push--sorry!
2021 // Called after the cert has been generated.
2023 certfile_finished_callback(subproc_t
*subproc
, int status
, const char *error
)
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
;
2031 for (; i
< num_listeners
; i
++) {
2032 INFO("Started " PUB_S_SRP
, listener
[i
]->name
);
2037 // Called after the key has been generated.
2039 keyfile_finished_callback(subproc_t
*subproc
, int status
, const char *error
)
2041 if (finished_okay("Keyfile generation", status
, error
)) {
2042 INFO("Keyfile generation completed.");
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
);
2054 main(int argc
, char **argv
)
2057 bool tls_fail
= false;
2059 udp_port
= tcp_port
= 53;
2062 // Parse command line arguments
2063 for (i
= 1; i
< argc
; i
++) {
2064 if (!strcmp(argv
[i
], "--tls-fail")) {
2067 return usage(argv
[0]);
2071 // Read the config file
2072 if (!config_parse(NULL
, "/etc/dnssd-proxy.cf", dp_verbs
, NUMCFVERBS
)) {
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.");
2082 ioloop_map_interface_addresses(&served_domains
, ifaddr_callback
);
2084 // Set up hardwired answers
2085 dnssd_hardwired_setup();
2088 if (!srp_tls_init()) {
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.
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.
2107 if (!ioloop_init()) {
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
]);
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.");
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.");
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
,
2144 if (listener
[num_listeners
] == NULL
) {
2145 ERROR("UDP4 listener: fail.");
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
,
2153 if (listener
[num_listeners
] == NULL
) {
2154 ERROR("UDP6 listener: fail.");
2160 for (i
= 0; i
< num_listeners
; i
++) {
2161 INFO("Started " PUB_S_SRP
, listener
[i
]->name
);
2170 // c-file-style: "bsd"
2171 // c-basic-offset: 4
2173 // indent-tabs-mode: nil