3 * Copyright (c) 2018 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 DNSSD Service Registration Protocol gateway. The purpose of this is to make it possible
18 * for SRP clients to update DNS servers that don't support SRP.
20 * The way it works is that this gateway listens on port ANY:53 and forwards either to another port on
21 * the same host (not recommended) or to any port (usually 53) on a different host. Requests are accepted
22 * over both TCP and UDP in principle, but UDP requests should be from constrained nodes, and rely on
23 * network topology for authentication.
25 * Note that this is not a full DNS proxy, so you can't just put it in front of a DNS server.
28 // Get DNS server IP address
29 // Get list of permitted source subnets for TCP updates
30 // Get list of permitted source subnet/interface tuples for UDP updates
31 // Set up UDP listener
32 // Set up TCP listener (no TCP Fast Open)
34 // Transaction processing:
35 // 1. If UDP, validate that it's from a subnet that is valid for the interface on which it was received.
36 // 2. If TCP, validate that it's from a permitted subnet
37 // 3. Check that the message is a valid SRP update according to the rules
38 // 4. Check the signature
39 // 5. Do a DNS Update with prerequisites to prevent overwriting a host record with the same owner name but
41 // 6. Send back the response
43 #define __APPLE_USE_RFC_3542
49 #include <sys/errno.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <sys/event.h>
59 #include "srp-crypto.h"
61 #include "dnssd-proxy.h"
63 #pragma mark structures
65 typedef struct subnet subnet_t
;
67 subnet_t
*NULLABLE next
;
73 typedef struct udp_validator udp_validator_t
;
74 struct udp_validator
{
75 udp_validator_t
*NULLABLE next
;
82 usage(const char *progname
)
84 ERROR("usage: %s -s <addr> <port> -t <subnet> ... -u <ifname> <subnet> ...", progname
);
85 ERROR(" -s can only appear once.");
86 ERROR(" -t can only appear once, and is followed by one or more subnets.");
87 ERROR(" -u can appear more than once, is followed by one interface name, and");
88 ERROR(" one or more subnets.");
89 ERROR(" <addr> is an IPv4 address or IPv6 address.");
90 ERROR(" <port> is a UDP port number.");
91 ERROR(" <subnet> is an IP address followed by a slash followed by the prefix width.");
92 ERROR(" <ifname> is the printable name of the interface.");
93 ERROR("ex: srp-gw -s 2001:DB8::1 53 -t 2001:DB8:1300::/48 -u en0 2001:DB8:1300:1100::/56");
97 typedef struct delete delete_t
;
103 typedef struct dns_host_description dns_host_description_t
;
104 struct dns_host_description
{
106 dns_rr_t
*a
, *aaaa
, *key
;
111 typedef struct service_instance service_instance_t
;
112 struct service_instance
{
113 service_instance_t
*next
;
114 dns_host_description_t
*host_description
;
121 typedef struct service service_t
;
124 service_instance_t
*instance
;
130 srp_relay(comm_t
*comm
, dns_message_t
*message
)
132 dns_name_t
*update_zone
;
133 bool updating_services_dot_arpa
= false;
135 dns_host_description_t
*host_description
= NULL
;
136 delete_t
*deletes
= NULL
, *dp
, **dpp
= &deletes
;
137 service_instance_t
*service_instances
= NULL
, *sip
, **sipp
= &service_instances
;
138 service_t
*services
= NULL
, *sp
, **spp
= &services
;
140 char namebuf
[DNS_MAX_NAME_SIZE
+ 1], namebuf1
[DNS_MAX_NAME_SIZE
+ 1];
144 // Update requires a single SOA record as the question
145 if (message
->qdcount
!= 1) {
146 ERROR("srp_relay: update received with qdcount > 1");
150 // Update should contain zero answers.
151 if (message
->ancount
!= 0) {
152 ERROR("srp_relay: update received with ancount > 0");
156 if (message
->questions
[0].type
!= dns_rrtype_soa
) {
157 ERROR("srp_relay: update received with rrtype %d instead of SOA in question section.",
158 message
->questions
[0].type
);
161 update_zone
= message
->questions
[0].name
;
163 // What zone are we updating?
164 if (dns_names_equal_text(update_zone
, "services.arpa")) {
165 updating_services_dot_arpa
= true;
168 // Scan over the authority RRs; do the delete consistency check. We can't do other consistency checks
169 // because we can't assume a particular order to the records other than that deletes have to come before
171 for (i
= 0; i
< message
->nscount
; i
++) {
172 dns_rr_t
*rr
= &message
->authority
[i
];
174 // If this is a delete for all the RRs on a name, record it in the list of deletes.
175 if (rr
->type
== dns_rrtype_any
&& rr
->qclass
== dns_qclass_any
&& rr
->ttl
== 0) {
176 for (dp
= deletes
; dp
; dp
= dp
->next
) {
177 if (dns_names_equal(dp
->name
, rr
->name
)) {
178 ERROR("srp_relay: two deletes for the same name: %s",
179 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
183 dp
= calloc(sizeof *dp
, 1);
185 ERROR("srp_relay: no memory.");
193 // Otherwise if it's an A or AAAA record, it's part of a hostname entry.
194 else if (rr
->type
== dns_rrtype_a
|| rr
->type
== dns_rrtype_aaaa
|| rr
->type
== dns_rrtype_key
) {
195 // Allocate the hostname record
196 if (!host_description
) {
197 host_description
= calloc(sizeof *host_description
, 1);
198 if (!host_description
) {
199 ERROR("srp_relay: no memory");
204 // Make sure it's preceded by a deletion of all the RRs on the name.
205 if (!host_description
->delete) {
206 for (dp
= deletes
; dp
; dp
= dp
->next
) {
207 if (dns_names_equal(dp
->name
, rr
->name
)) {
212 ERROR("srp_relay: ADD for hostname %s without a preceding delete.",
213 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
216 host_description
->delete = dp
;
217 host_description
->name
= dp
->name
;
220 if (rr
->type
== dns_rrtype_a
) {
221 if (host_description
->a
!= NULL
) {
222 ERROR("srp_relay: more than one A rrset received for name: %s",
223 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
226 host_description
->a
= rr
;
227 } else if (rr
->type
== dns_rrtype_aaaa
) {
228 if (host_description
->aaaa
!= NULL
) {
229 ERROR("srp_relay: more than one AAAA rrset received for name: %s",
230 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
233 host_description
->aaaa
= rr
;
234 } else if (rr
->type
== dns_rrtype_key
) {
235 if (host_description
->key
!= NULL
) {
236 ERROR("srp_relay: more than one KEY rrset received for name: %s",
237 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
240 host_description
->key
= rr
;
244 // Otherwise if it's an SRV entry, that should be a service instance name.
245 else if (rr
->type
== dns_rrtype_srv
|| rr
->type
== dns_rrtype_txt
) {
246 // Should be a delete that precedes this service instance.
247 for (dp
= deletes
; dp
; dp
= dp
->next
) {
248 if (dns_names_equal(dp
->name
, rr
->name
)) {
253 ERROR("srp_relay: ADD for service instance not preceded by delete: %s",
254 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
257 for (sip
= service_instances
; sip
; sip
= sip
->next
) {
258 if (dns_names_equal(sip
->name
, rr
->name
)) {
263 sip
= calloc(sizeof *sip
, 1);
265 ERROR("srp_relay: no memory");
269 sip
->name
= dp
->name
;
273 if (rr
->type
== dns_rrtype_srv
) {
274 if (sip
->srv
!= NULL
) {
275 ERROR("srp_relay: more than one SRV rr received for service instance: %s",
276 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
280 } else if (rr
->type
== dns_rrtype_txt
) {
281 if (sip
->txt
!= NULL
) {
282 ERROR("srp_relay: more than one SRV rr received for service instance: %s",
283 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
289 // Otherwise if it's a PTR entry, that should be a service name
290 else if (rr
->type
== dns_rrtype_ptr
) {
291 sp
= calloc(sizeof *sp
, 1);
293 ERROR("srp_relay: no memory");
301 // Otherwise it's not a valid update
303 ERROR("srp_relay: unexpected rrtype %d on %s in update.", rr
->type
,
304 dns_name_print(rr
->name
, namebuf
, sizeof namebuf
));
309 // Now that we've scanned the whole update, do the consistency checks for updates that might
310 // not have come in order.
312 // First, make sure there's a host description.
313 if (host_description
== NULL
) {
314 ERROR("srp_relay: SRP update does not include a host description.");
318 // Make sure that each service add references a service instance that's in the same update.
319 for (sp
= services
; sp
; sp
= sp
->next
) {
320 for (sip
= service_instances
; sip
; sip
= sip
->next
) {
321 if (dns_names_equal(sip
->name
, sp
->rr
->data
.ptr
.name
)) {
322 // Note that we have already verified that there is only one service instance
323 // with this name, so this could only ever happen once in this loop even without
324 // the break statement.
326 sip
->num_instances
++;
330 // If this service doesn't point to a service instance that's in the update, then the
331 // update fails validation.
333 ERROR("srp_relay: service %s points to an instance that's not included: %s",
334 dns_name_print(sp
->name
, namebuf
, sizeof namebuf
),
335 dns_name_print(sip
->name
, namebuf1
, sizeof namebuf1
));
340 for (sip
= service_instances
; sip
; sip
= sip
->next
) {
341 // For each service instance, make sure that at least one service references it
342 if (sip
->num_instances
== 0) {
343 ERROR("srp_relay: service instance update for %s is not referenced by a service update.",
344 dns_name_print(sip
->name
, namebuf
, sizeof namebuf
));
348 // For each service instance, make sure that it references the host description
349 if (dns_names_equal(host_description
->name
, sip
->srv
->data
.srv
.name
)) {
350 sip
->host_description
= host_description
;
351 host_description
->num_instances
++;
355 // Make sure that at least one service instance references the host description
356 if (host_description
->num_instances
== 0) {
357 ERROR("srp_relay: host description %s is not referenced by any service instances.",
358 dns_name_print(host_description
->name
, namebuf
, sizeof namebuf
));
362 // Make sure the host description has at least one address record.
363 if (host_description
->a
== NULL
&& host_description
->aaaa
== NULL
) {
364 ERROR("srp_relay: host description %s doesn't contain any IP addresses.",
365 dns_name_print(host_description
->name
, namebuf
, sizeof namebuf
));
368 // And make sure it has a key record
369 if (host_description
->key
== NULL
) {
370 ERROR("srp_relay: host description %s doesn't contain a key.",
371 dns_name_print(host_description
->name
, namebuf
, sizeof namebuf
));
375 // The signature should be the last thing in the additional section. Even if the signature
376 // is valid, if it's not at the end we reject it. Note that we are just checking for SIG(0)
377 // so if we don't find what we're looking for, we forward it to the DNS auth server which
378 // will either accept or reject it.
379 if (message
->arcount
< 1) {
380 ERROR("srp_relay: signature not present");
383 signature
= &message
->additional
[message
->arcount
-1];
384 if (signature
->type
!= dns_rrtype_sig
) {
385 ERROR("srp_relay: signature is not at the end or is not present");
389 // Make sure that the signer name is the hostname. If it's not, it could be a legitimate
390 // update with a different key, but it's not an SRP update, so we pass it on.
391 if (!dns_names_equal(signature
->data
.sig
.signer
, host_description
->name
)) {
392 ERROR("srp_relay: signer %s doesn't match host %s",
393 dns_name_print(signature
->data
.sig
.signer
, namebuf
, sizeof namebuf
),
394 dns_name_print(host_description
->name
, namebuf1
, sizeof namebuf1
));
398 // Make sure we're in the time limit for the signature. Zeroes for the inception and expiry times
399 // mean the host that send this doesn't have a working clock. One being zero and the other not isn't
400 // valid unless it's 1970.
401 if (signature
->data
.sig
.inception
!= 0 || signature
->data
.sig
.expiry
!= 0) {
402 gettimeofday(&now
, NULL
);
403 // The sender does the bracketing, so we can just do a simple comparison.
404 if (now
.tv_sec
> signature
->data
.sig
.expiry
|| now
.tv_sec
< signature
->data
.sig
.inception
) {
405 ERROR("signature is not timely: %lu < %lu < %lu does not hold",
406 (unsigned long)signature
->data
.sig
.inception
, (unsigned long)now
.tv_sec
,
407 (unsigned long)signature
->data
.sig
.expiry
);
412 // Now that we have the key, we can validate the signature. If the signature doesn't validate,
413 // there is no need to pass the message on.
414 if (!srp_sig0_verify(message
->wire
, host_description
->key
, signature
)) {
415 ERROR("signature is not valid");
420 // True means we consumed it, not that it was valid.
424 // free everything we allocated but (it turns out) aren't going to use
425 for (dp
= deletes
; dp
; ) {
426 delete_t
*next
= dp
->next
;
430 for (sip
= service_instances
; sip
; ) {
431 service_instance_t
*next
= sip
->next
;
435 for (sp
= services
; sp
; ) {
436 service_t
*next
= sp
->next
;
440 if (host_description
!= NULL
) {
441 free(host_description
);
447 dns_evaluate(comm_t
*comm
)
449 dns_message_t
*message
;
451 // Drop incoming responses--we're a server, so we only accept queries.
452 if (dns_qr_get(&comm
->message
->wire
) == dns_qr_response
) {
456 // Forward incoming messages that are queries but not updates.
457 // XXX do this later--for now we operate only as a translator, not a proxy.
458 if (dns_opcode_get(&comm
->message
->wire
) != dns_opcode_update
) {
462 // Parse the UPDATE message.
463 if (!dns_wire_parse(&message
, &comm
->message
->wire
, comm
->message
->length
)) {
464 ERROR("dns_wire_parse failed.");
468 // We need the wire message to validate the signature...
469 message
->wire
= &comm
->message
->wire
;
470 if (!srp_relay(comm
, message
)) {
471 // The message wasn't invalid, but wasn't an SRP message.
474 // But we don't save it.
475 message
->wire
= NULL
;
477 //dns_message_free(message);
480 void dns_input(comm_t
*comm
)
483 message_free(comm
->message
);
484 comm
->message
= NULL
;
488 main(int argc
, char **argv
)
491 subnet_t
*tcp_validators
= NULL
;
492 udp_validator_t
*udp_validators
= NULL
;
493 udp_validator_t
*NULLABLE
*NONNULL up
= &udp_validators
;
494 subnet_t
*NULLABLE
*NONNULL nt
= &tcp_validators
;
495 subnet_t
*NULLABLE
*NONNULL sp
;
498 socklen_t len
, prefalen
;
501 uint16_t listen_port
;
503 listen_port
= htons(53);
505 // Read the configuration from the command line.
506 for (i
= 1; i
< argc
; i
++) {
507 if (!strcmp(argv
[i
], "-s")) {
509 ERROR("-s is missing server IP address.");
510 return usage(argv
[0]);
512 len
= getipaddr(&server
, argv
[i
]);
514 ERROR("Invalid IP address: %s.", argv
[i
]);
515 return usage(argv
[0]);
517 server
.sa
.sa_len
= len
;
519 ERROR("-s is missing server port.");
520 return usage(argv
[0]);
522 port
= strtol(argv
[i
], &s
, 10);
523 if (s
== argv
[i
] || s
[0] != '\0') {
524 ERROR("Invalid port number: %s", argv
[i
]);
525 return usage(argv
[0]);
527 if (server
.sa
.sa_family
== AF_INET
) {
528 server
.sin
.sin_port
= htons(port
);
530 server
.sin6
.sin6_port
= htons(port
);
533 } else if (!strcmp(argv
[i
], "-t") || !strcmp(argv
[i
], "-u")) {
534 if (!strcmp(argv
[i
], "-u")) {
536 ERROR("-u is missing interface name.");
537 return usage(argv
[0]);
539 *up
= calloc(1, sizeof **up
);
541 ERROR("udp_validators: out of memory.");
542 return usage(argv
[0]);
544 (*up
)->ifname
= strdup(argv
[i
]);
545 if ((*up
)->ifname
== NULL
) {
546 ERROR("udp validators: ifname: out of memory.");
547 return usage(argv
[0]);
549 sp
= &((*up
)->subnets
);
555 ERROR("%s requires at least one prefix.", argv
[i
- 1]);
556 return usage(argv
[0]);
558 s
= strchr(argv
[i
], '/');
560 ERROR("%s is not a prefix.", argv
[i
]);
561 return usage(argv
[0]);
565 prefalen
= getipaddr(&pref
, argv
[i
]);
567 ERROR("%s is not a valid prefix address.", argv
[i
]);
568 return usage(argv
[0]);
570 width
= strtol(s
, &p
, 10);
571 if (s
== p
|| p
[0] != '\0') {
572 ERROR("%s (prefix width) is not a number.", p
);
573 return usage(argv
[0]);
576 (pref
.sa
.sa_family
== AF_INET
&& width
> 32) ||
577 (pref
.sa
.sa_family
== AF_INET6
&& width
> 64)) {
578 ERROR("%s is not a valid prefix length for %s", p
,
579 pref
.sa
.sa_family
== AF_INET
? "IPv4" : "IPv6");
580 return usage(argv
[0]);
583 *nt
= calloc(1, sizeof **nt
);
585 ERROR("tcp_validators: out of memory.");
589 (*nt
)->preflen
= width
;
590 (*nt
)->family
= pref
.sa
.sa_family
;
591 if (pref
.sa
.sa_family
== AF_INET
) {
592 memcpy((*nt
)->bytes
, &pref
.sin
.sin_addr
, 4);
594 memcpy((*nt
)->bytes
, &pref
.sin6
.sin6_addr
, 8);
597 // *up will be non-null for -u and null for -t.
606 if (!ioloop_init()) {
611 if (!setup_listener_socket(AF_INET
, IPPROTO_UDP
, listen_port
, "UDPv4 listener", dns_input
, 0, 0)) {
612 ERROR("UDPv4 listener: fail.");
615 if (!setup_listener_socket(AF_INET6
, IPPROTO_UDP
, listen_port
, "UDPv6 listener", dns_input
, 0, 0)) {
616 ERROR("UDPv6 listener: fail.");
619 if (!setup_listener_socket(AF_INET
, IPPROTO_TCP
, listen_port
, "TCPv4 listener", dns_input
, 0, 0)) {
620 ERROR("TCPv4 listener: fail.");
623 if (!setup_listener_socket(AF_INET6
, IPPROTO_TCP
, listen_port
, "TCPv6 listener", dns_input
, 0, 0)) {
624 ERROR("TCPv4 listener: fail.");
630 something
= ioloop_events(0);
631 INFO("dispatched %d events.", something
);
638 // c-file-style: "bsd"
641 // indent-tabs-mode: nil