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 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
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
59 #include "srp-crypto.h"
62 #include "config-parse.h"
63 #include "srp-proxy.h"
65 static addr_t dns_server
;
66 static dns_name_t
*service_update_zone
; // The zone to update when we receive an update for default.service.arpa.
67 static hmac_key_t
*key
;
70 usage(const char *progname
)
72 ERROR("usage: %s -s <addr> <port> -k <key-file> -t <subnet> ... -u <ifname> <subnet> ...", progname
);
73 ERROR(" -s can only appear once.");
74 ERROR(" -k can appear once.");
75 ERROR(" -t can only appear once, and is followed by one or more subnets.");
76 ERROR(" -u can appear more than once, is followed by one interface name, and");
77 ERROR(" one or more subnets.");
78 ERROR(" <addr> is an IPv4 address or IPv6 address.");
79 ERROR(" <port> is a UDP port number.");
80 ERROR(" <key-file> is a file containing an HMAC-SHA256 key for authenticating updates to the auth server.");
81 ERROR(" <subnet> is an IP address followed by a slash followed by the prefix width.");
82 ERROR(" <ifname> is the printable name of the interface.");
83 ERROR("ex: srp-gw -s 2001:DB8::1 53 -k srp.key -t 2001:DB8:1300::/48 -u en0 2001:DB8:1300:1100::/56");
87 // Free the data structures into which the SRP update was parsed. The pointers to the various DNS objects that these
88 // structures point to are owned by the parsed DNS message, and so these do not need to be freed here.
90 update_free_parts(service_instance_t
*service_instances
, service_instance_t
*added_instances
,
91 service_t
*services
, dns_host_description_t
*host_description
)
93 service_instance_t
*sip
;
96 for (sip
= service_instances
; sip
; ) {
97 service_instance_t
*next
= sip
->next
;
101 for (sip
= added_instances
; sip
; ) {
102 service_instance_t
*next
= sip
->next
;
106 for (sp
= services
; sp
; ) {
107 service_t
*next
= sp
->next
;
111 if (host_description
!= NULL
) {
112 free(host_description
);
116 // Free all the stuff that we accumulated while processing the SRP update.
118 update_free(update_t
*update
)
120 // Free all of the structures we collated RRs into:
121 update_free_parts(update
->instances
, update
->added_instances
, update
->services
, update
->host
);
122 // We don't need to free the zone name: it's either borrowed from the message,
123 // or it's service_update_zone, which is static.
124 message_free(update
->message
);
125 dns_message_free(update
->parsed_message
);
130 #define name_to_wire(towire, name) name_to_wire_(towire, name, __LINE__)
132 name_to_wire_(dns_towire_state_t
*towire
, dns_name_t
*name
, int line
)
134 // Does compression...
135 dns_concatenate_name_to_wire_(towire
, name
, NULL
, NULL
, line
);
139 rdata_to_wire(dns_towire_state_t
*towire
, dns_rr_t
*rr
)
141 dns_rdlength_begin(towire
);
143 // These are the only types we expect to see. If something else were passed, it would be written as rdlen=0.
146 name_to_wire(towire
, rr
->data
.ptr
.name
);
150 dns_u16_to_wire(towire
, rr
->data
.srv
.priority
);
151 dns_u16_to_wire(towire
, rr
->data
.srv
.weight
);
152 dns_u16_to_wire(towire
, rr
->data
.srv
.port
);
153 name_to_wire(towire
, rr
->data
.srv
.name
);
157 dns_rdata_raw_data_to_wire(towire
, rr
->data
.txt
.data
, rr
->data
.txt
.len
);
161 dns_u16_to_wire(towire
, rr
->data
.key
.flags
);
162 dns_u8_to_wire(towire
, rr
->data
.key
.protocol
);
163 dns_u8_to_wire(towire
, rr
->data
.key
.algorithm
);
164 dns_rdata_raw_data_to_wire(towire
, rr
->data
.key
.key
, rr
->data
.key
.len
);
168 dns_rdata_raw_data_to_wire(towire
, &rr
->data
.a
, sizeof rr
->data
.a
);
171 case dns_rrtype_aaaa
:
172 dns_rdata_raw_data_to_wire(towire
, &rr
->data
.aaaa
, sizeof rr
->data
.aaaa
);
176 dns_rdlength_end(towire
);
179 // We only list the types we are using--there are other types that we don't support.
180 typedef enum prereq_type prereq_type_t
;
182 update_rrset_equals
, // RFC 2136 section 2.4.2: RRset Exists (Value Dependent)
183 update_name_not_in_use
, // RFC 2136 section 2.4.5: Name Is Not In Use
187 add_prerequisite(dns_wire_t
*msg
, dns_towire_state_t
*towire
, prereq_type_t ptype
, dns_name_t
*name
, dns_rr_t
*rr
)
189 char namebuf
[DNS_MAX_NAME_SIZE
+ 1];
190 if (ntohs(msg
->nscount
) != 0 || ntohs(msg
->arcount
) != 0) {
191 ERROR("%s: adding prerequisite after updates", dns_name_print(name
, namebuf
, sizeof namebuf
));
192 towire
->truncated
= true;
194 name_to_wire(towire
, name
);
196 case update_rrset_equals
:
197 dns_u16_to_wire(towire
, rr
->type
);
198 dns_u16_to_wire(towire
, rr
->qclass
);
199 dns_ttl_to_wire(towire
, 0);
200 rdata_to_wire(towire
, rr
);
202 case update_name_not_in_use
:
203 dns_u16_to_wire(towire
, dns_rrtype_any
); // TYPE
204 dns_u16_to_wire(towire
, dns_qclass_none
); // CLASS
205 dns_ttl_to_wire(towire
, 0); // TTL
206 dns_u16_to_wire(towire
, 0); // RDLEN
209 msg
->ancount
= htons(ntohs(msg
->ancount
) + 1);
212 // We actually only support one type of delete, so it's a bit silly to specify it, but in principle we might
214 typedef enum delete_type delete_type_t
;
216 delete_name
, // RFC 2136 section 2.5.3: Delete all RRsets from a name
220 add_delete(dns_wire_t
*msg
, dns_towire_state_t
*towire
, delete_type_t dtype
, dns_name_t
*name
)
222 name_to_wire(towire
, name
);
225 dns_u16_to_wire(towire
, dns_rrtype_any
); // TYPE
226 dns_u16_to_wire(towire
, dns_qclass_any
); // CLASS
227 dns_ttl_to_wire(towire
, 0); // TTL
228 dns_u16_to_wire(towire
, 0); // RDLEN
231 msg
->nscount
= htons(ntohs(msg
->nscount
) + 1);
234 // Copy the RR we received in the SRP update out in wire format.
237 add_rr(dns_wire_t
*msg
, dns_towire_state_t
*towire
, dns_name_t
*name
, dns_rr_t
*rr
)
240 name_to_wire(towire
, name
);
241 dns_u16_to_wire(towire
, rr
->type
); // TYPE
242 dns_u16_to_wire(towire
, rr
->qclass
); // CLASS
243 dns_ttl_to_wire(towire
, rr
->ttl
); // TTL
244 rdata_to_wire(towire
, rr
); // RDLEN
245 msg
->nscount
= htons(ntohs(msg
->nscount
) + 1);
249 // Construct an update of the specified type, assuming that the record being updated
250 // either exists or does not exist, depending on the value of exists. Actual records
251 // to be update are taken from the update_t.
255 // The goal of the update is to either bring the zone to the state described in the SRP update, or
256 // determine that the state described in the SRP update conflicts with what is already present in
259 // Possible scenarios:
260 // 1. Update and Zone are the same (A and AAAA records may differ):
262 // a. for each instance: KEY RR exists on instance name and is the same
263 // b. for host: KEY RR exists on host name and is the same
265 // a. for each instance: delete all records on instance name, add KEY RR, add SRV RR, add TXT RR
266 // b. for host: delete host instance, add A, AAAA and KEY RRs
267 // c. for each service: add PTR record pointing on service name to service instance name
269 // We should try 1 first, because it should be the steady state case; that is, it should be what happens
271 // If 1 fails, then we could have some service instances present and others not. There is no way to
272 // know without trying. We can at this point either try to add each service instance in a separate update,
273 // or assume that none are present and add them all at once, and then if this fails add them individually.
274 // I think that it makes sense to try them all first, because that should be the second most common case:
276 // 2. Nothing in update is present in zone:
278 // a. For each instance: instance name is not in use
279 // b. Host name is not in use
281 // a. for each instance: add KEY RR, add SRV RR, add TXT RR on instance name
282 // b. for host: add A, AAAA and KEY RRs on host name
283 // c. for each service: add PTR record pointing on service name to service instance name
285 // If either (1) or (2) works, we're done. If both fail, then we need to do the service instance updates
286 // and host update one by one. This is a bit nasty because we actually have to try twice: once assuming
287 // the RR exists, and once assuming it doesn't. If any of the instance updates fail, or the host update
288 // fails, we delete all the ones that succeeded.
290 // In the cases other than (1) and (2), we can add all the service PTRs in the host update, because they're
291 // only added if the host update succeeds; if it fails, we have to go back and remove all the service
294 // One open question for the SRP document: we probably want to signal whether the conflict is with the
295 // hostname or one of the service instance names. We can do this with an EDNS(0) option.
298 // - Try to update assuming everything is there already (case 1)
299 // - Try to update assuming nothing is there already (case 2)
300 // - For each service instance:
301 // - Try to update assuming it's not there; if this succeeds, add this instance to the list of
302 // instances that have been added. If not:
303 // - Try to update assuming it is there
304 // - If this fails, go to fail
305 // - Try to update the host (and also services) assuming the host is not there. If this fails:
306 // - Try to update the host (and also services) assuming the host is there. If this succeeds:
309 // - For each service instance in the list of instances that have been added:
310 // - delete all records on the instance name.
312 // One thing that isn't accounted for here: it's possible that a previous update added some but not all
313 // instances in the current update. Subsequently, some other device may have claimed an instance that is
314 // present but in conflict in the current update. In this case, all of the instances prior to that one
315 // in the update will actually have been updated by this update, but then the update as a whole will fail.
316 // I think this is unlikely to be an actual problem, and there's no way to address it without a _lot_ of
320 construct_update(update_t
*update
)
322 dns_towire_state_t towire
;
323 dns_wire_t
*msg
= update
->update
; // Solely to reduce the amount of typing.
324 service_instance_t
*instance
;
326 host_addr_t
*host_addr
;
328 // Set up the message constructor
329 memset(&towire
, 0, sizeof towire
);
330 towire
.p
= &msg
->data
[0]; // We start storing RR data here.
331 towire
.lim
= &msg
->data
[0] + update
->update_max
; // This is the limit to how much we can store.
332 towire
.message
= msg
;
334 // Initialize the update message...
335 memset(msg
, 0, DNS_HEADER_SIZE
);
336 dns_qr_set(msg
, dns_qr_query
);
337 dns_opcode_set(msg
, dns_opcode_update
);
338 msg
->id
= srp_random16();
340 // An update always has one question, which is the zone name.
341 msg
->qdcount
= htons(1);
342 name_to_wire(&towire
, update
->zone_name
);
343 dns_u16_to_wire(&towire
, dns_rrtype_soa
);
344 dns_u16_to_wire(&towire
, dns_qclass_in
);
346 switch(update
->state
) {
347 case connect_to_server
:
348 ERROR("Update construction requested when still connecting.");
349 update
->update_length
= 0;
352 // Do a DNS Update for a service instance
353 case refresh_existing
:
354 // Add a "KEY exists and is <x> and a PTR exists and is <x> prerequisite for each instance being updated.
355 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
356 add_prerequisite(msg
, &towire
, update_rrset_equals
, instance
->name
, update
->host
->key
);
358 add_prerequisite(msg
, &towire
, update_rrset_equals
, update
->host
->name
, update
->host
->key
);
359 // Now add a delete for each service instance
360 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
361 add_delete(msg
, &towire
, delete_name
, instance
->name
);
363 add_delete(msg
, &towire
, delete_name
, update
->host
->name
);
366 // Now add the update for each instance.
367 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
368 add_rr(msg
, &towire
, instance
->name
, update
->host
->key
);
369 add_rr(msg
, &towire
, instance
->name
, instance
->srv
);
370 add_rr(msg
, &towire
, instance
->name
, instance
->txt
);
372 // Add the update for each service
373 for (service
= update
->services
; service
; service
= service
->next
) {
374 add_rr(msg
, &towire
, service
->rr
->name
, service
->rr
);
376 // Add the host records...
377 add_rr(msg
, &towire
, update
->host
->name
, update
->host
->key
);
378 for (host_addr
= update
->host
->addrs
; host_addr
; host_addr
= host_addr
->next
) {
379 add_rr(msg
, &towire
, update
->host
->name
, &host_addr
->rr
);
383 case create_nonexistent
:
384 // Add a "name not in use" prerequisite for each instance being updated.
385 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
386 add_prerequisite(msg
, &towire
, update_name_not_in_use
, instance
->name
, (dns_rr_t
*)NULL
);
388 add_prerequisite(msg
, &towire
, update_name_not_in_use
, update
->host
->name
, (dns_rr_t
*)NULL
);
391 case create_nonexistent_instance
:
392 // The only prerequisite is that this specific service instance doesn't exist.
393 add_prerequisite(msg
, &towire
, update_name_not_in_use
, update
->instance
->name
, (dns_rr_t
*)NULL
);
396 case refresh_existing_instance
:
397 // If instance already exists, prerequisite is that it has the same key, and we also have to
398 // delete all RRs on the name before adding our RRs, in case they have changed.
399 add_prerequisite(msg
, &towire
, update_rrset_equals
, update
->instance
->name
, update
->host
->key
);
400 add_delete(msg
, &towire
, delete_name
, update
->instance
->name
);
402 add_rr(msg
, &towire
, update
->instance
->name
, update
->host
->key
);
403 add_rr(msg
, &towire
, update
->instance
->name
, update
->instance
->srv
);
404 add_rr(msg
, &towire
, update
->instance
->name
, update
->instance
->txt
);
407 case create_nonexistent_host
:
408 add_prerequisite(msg
, &towire
, update_name_not_in_use
, update
->host
->name
, (dns_rr_t
*)NULL
);
411 case refresh_existing_host
:
412 add_prerequisite(msg
, &towire
, update_rrset_equals
, update
->host
->name
, update
->host
->key
);
413 add_delete(msg
, &towire
, delete_name
, update
->host
->name
);
414 // Add the service PTRs here--these don't need to be in a separate update, because if we get here
415 // the only thing that can make adding them not okay is if adding the host fails.
416 // Add the update for each service
417 for (service
= update
->services
; service
; service
= service
->next
) {
418 add_rr(msg
, &towire
, service
->rr
->name
, service
->rr
);
421 // Add the host records...
422 add_rr(msg
, &towire
, update
->host
->name
, update
->host
->key
);
423 for (host_addr
= update
->host
->addrs
; host_addr
; host_addr
= host_addr
->next
) {
424 add_rr(msg
, &towire
, update
->host
->name
, &host_addr
->rr
);
428 case delete_failed_instance
:
429 // Delete all the instances we successfull added before discovering a problem.
430 // It is possible in principle that these could have been overwritten by some other
431 // process and we could be deleting the wrong stuff, but in practice this should
432 // never happen if these are legitimately managed by SRP. Once a name has been
433 // claimed by SRP, it should continue to be managed by SRP until its lease expires
434 // and SRP deletes it, at which point it is of course fair game.
435 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
436 add_delete(msg
, &towire
, delete_name
, instance
->name
);
440 if (towire
.error
!= 0) {
441 ERROR("construct_update: error %s while generating update at line %d", strerror(towire
.error
), towire
.line
);
444 update
->update_length
= towire
.p
- (uint8_t *)msg
;
449 update_finished(update_t
*update
, int rcode
)
451 comm_t
*comm
= update
->client
;
454 INFO("Update Finished, rcode = " PUB_S_SRP
, dns_rcode_name(rcode
));
456 memset(&response
, 0, DNS_HEADER_SIZE
);
457 response
.id
= update
->message
->wire
.id
;
458 response
.bitfield
= update
->message
->wire
.bitfield
;
459 dns_rcode_set(&response
, rcode
);
460 dns_qr_set(&response
, dns_qr_response
);
462 iov
.iov_base
= &response
;
463 iov
.iov_len
= DNS_HEADER_SIZE
;
465 comm
->send_response(comm
, update
->message
, &iov
, 1);
467 // If success, construct a response
468 // If fail, send a quick status code
469 // Signal host name conflict and instance name conflict using different rcodes (?)
470 // Okay, so if there's a host name/instance name conflict, and the host name has the right key, then
471 // the instance name is actually bogus and should be overwritten.
472 // If the host has the wrong key, and the instance is present, then the instance is also bogus.
473 // So in each of these cases, perhaps we should just gc the instance.
474 // This would mean that there is nothing to signal: either the instance is a mismatch, and we
475 // overwrite it and return success, or the host is a mismatch and we gc the instance and return failure.
476 ioloop_close(&update
->server
->io
);
481 update_send(update_t
*update
)
484 dns_towire_state_t towire
;
485 dns_wire_t
*msg
= update
->update
;
488 #ifdef DEBUG_DECODE_UPDATE
489 dns_message_t
*decoded
;
492 // Set up the message constructor
493 memset(&towire
, 0, sizeof towire
);
494 towire
.p
= (uint8_t *)msg
+ update
->update_length
; // We start storing RR data here.
495 towire
.lim
= &msg
->data
[0] + update
->update_max
; // This is the limit to how much we can store.
496 towire
.message
= msg
;
497 towire
.p_rdlength
= NULL
;
500 // If we have a key, sign the message with the key using TSIG HMAC-SHA256.
502 // Maintain an IOV with the bits of the message that we need to sign.
503 iov
[0].iov_base
= msg
;
505 name_to_wire(&towire
, key
->name
);
506 iov
[0].iov_len
= towire
.p
- (uint8_t *)iov
[0].iov_base
;
507 dns_u16_to_wire(&towire
, dns_rrtype_tsig
); // RRTYPE
508 iov
[1].iov_base
= towire
.p
;
509 dns_u16_to_wire(&towire
, dns_qclass_any
); // CLASS
510 dns_ttl_to_wire(&towire
, 0); // TTL
511 iov
[1].iov_len
= towire
.p
- (uint8_t *)iov
[1].iov_base
;
512 // The message digest skips the RDLEN field.
513 dns_rdlength_begin(&towire
); // RDLEN
514 iov
[2].iov_base
= towire
.p
;
515 dns_full_name_to_wire(NULL
, &towire
, "hmac-sha256."); // Algorithm Name
516 gettimeofday(&tv
, NULL
);
517 dns_u48_to_wire(&towire
, tv
.tv_sec
); // Time since epoch
518 dns_u16_to_wire(&towire
, 300); // Fudge interval
519 // (clocks can be skewed by up to 5 minutes)
520 // Message digest doesn't cover MAC size or MAC fields, for obvious reasons, nor original message ID.
521 iov
[2].iov_len
= towire
.p
- (uint8_t *)iov
[2].iov_base
;
522 dns_u16_to_wire(&towire
, SRP_SHA256_DIGEST_SIZE
); // MAC Size
523 p_mac
= towire
.p
; // MAC
525 if (towire
.p
+ SRP_SHA256_DIGEST_SIZE
>= towire
.lim
) {
526 towire
.error
= ENOBUFS
;
527 towire
.truncated
= true;
528 towire
.line
= __LINE__
;
530 towire
.p
+= SRP_SHA256_DIGEST_SIZE
;
533 // We have to copy the message ID into the tsig signature; this is because in some cases, although not this one,
534 // the message ID will be overwritten. So the copy of the ID is what's validated, but it's copied into the
535 // header for validation, so we don't include it when generating the hash.
536 dns_rdata_raw_data_to_wire(&towire
, &msg
->id
, sizeof msg
->id
);
537 iov
[3].iov_base
= towire
.p
;
538 dns_u16_to_wire(&towire
, 0); // TSIG Error (always 0 on send).
539 dns_u16_to_wire(&towire
, 0); // Other Len (MBZ?)
540 iov
[3].iov_len
= towire
.p
- (uint8_t *)iov
[3].iov_base
;
541 dns_rdlength_end(&towire
);
543 // Okay, we have stored the TSIG signature, now compute the message digest.
544 srp_hmac_iov(key
, p_mac
, SRP_SHA256_DIGEST_SIZE
, &iov
[0], 4);
545 msg
->arcount
= htons(ntohs(msg
->arcount
) + 1);
546 update
->update_length
= towire
.p
- (const uint8_t *)msg
;
549 if (towire
.error
!= 0) {
550 ERROR("update_send: error \"%s\" while generating update at line %d",
551 strerror(towire
.error
), towire
.line
);
552 update_finished(update
, dns_rcode_servfail
);
556 #ifdef DEBUG_DECODE_UPDATE
557 if (!dns_wire_parse(&decoded
, msg
, update
->update_length
)) {
558 ERROR("Constructed message does not successfully parse.");
559 update_finished(update
, dns_rcode_servfail
);
564 // Transmit the update
565 iov
[0].iov_base
= update
->update
;
566 iov
[0].iov_len
= update
->update_length
;
567 update
->server
->send_response(update
->server
, update
->message
, iov
, 1);
571 update_connect_callback(comm_t
*comm
)
573 update_t
*update
= comm
->context
;
575 // Once we're connected, construct the first update.
576 INFO("Connected to " PUB_S_SRP
".", comm
->name
);
577 // STATE CHANGE: connect_to_server -> refresh_existing
578 update
->state
= refresh_existing
;
579 if (!construct_update(update
)) {
580 update_finished(update
, dns_rcode_servfail
);
587 update_state_name(update_state_t state
)
590 case connect_to_server
:
591 return "connect_to_server";
592 case create_nonexistent
:
593 return "create_nonexistent";
594 case refresh_existing
:
595 return "refresh_existing";
596 case create_nonexistent_instance
:
597 return "create_nonexistent_instance";
598 case refresh_existing_instance
:
599 return "refresh_existing_instance";
600 case create_nonexistent_host
:
601 return "create_nonexistent_host";
602 case refresh_existing_host
:
603 return "refresh_existing_host";
604 case delete_failed_instance
:
605 return "delete_failed_instance";
607 return "unknown state";
611 update_finalize(io_t
*context
)
616 update_disconnect_callback(comm_t
*comm
, int error
)
618 update_t
*update
= comm
->context
;
620 if (update
->state
== connect_to_server
) {
621 INFO(PUB_S_SRP
" disconnected: " PUB_S_SRP
, comm
->name
, strerror(error
));
622 update_finished(update
, dns_rcode_servfail
);
624 // This could be bad if any updates succeeded.
625 ERROR("%s disconnected during update in state %s: %s",
626 comm
->name
, update_state_name(update
->state
), strerror(error
));
627 update_finished(update
, dns_rcode_servfail
);
632 update_reply_callback(comm_t
*comm
)
634 update_t
*update
= comm
->context
;
635 dns_wire_t
*wire
= &comm
->message
->wire
;
636 char namebuf
[DNS_MAX_NAME_SIZE
+ 1], namebuf1
[DNS_MAX_NAME_SIZE
+ 1];
637 service_instance_t
**pinstance
;
638 update_state_t initial_state
;
639 service_instance_t
*initial_instance
;
641 initial_instance
= update
->instance
;
642 initial_state
= update
->state
;
644 INFO("Message from " PUB_S_SRP
" in state " PUB_S_SRP
", rcode = " PUB_S_SRP
".", comm
->name
,
645 update_state_name(update
->state
), dns_rcode_name(dns_rcode_get(wire
)));
647 // Sanity check the response
648 if (dns_qr_get(wire
) == dns_qr_query
) {
649 ERROR("Received a query from the authoritative server!");
650 update_finished(update
, dns_rcode_servfail
);
653 if (dns_opcode_get(wire
) != dns_opcode_update
) {
654 ERROR("Received a response with opcode %d from the authoritative server!",
655 dns_opcode_get(wire
));
656 update_finished(update
, dns_rcode_servfail
);
659 if (update
->update
== NULL
) {
660 ERROR("Received a response from auth server when no update has been sent yet.");
661 update_finished(update
, dns_rcode_servfail
);
663 // This isn't an error in the protocol, because we might be pipelining. But we _aren't_ pipelining,
664 // so there is only one message in flight. So the message IDs should match.
665 if (update
->update
->id
!= wire
->id
) {
666 ERROR("Response doesn't have the expected id: %x != %x.", wire
->id
, update
->update
->id
);
667 update_finished(update
, dns_rcode_servfail
);
670 // Handle the case where the update succeeded.
671 switch(dns_rcode_get(wire
)) {
672 case dns_rcode_noerror
:
673 switch(update
->state
) {
674 case connect_to_server
: // Can't get a response when connecting.
676 ERROR("Invalid rcode \"%s\" for state %s",
677 dns_rcode_name(dns_rcode_get(wire
)), update_state_name(update
->state
));
678 update_finished(update
, dns_rcode_servfail
);
681 case create_nonexistent
:
682 DM_NAME_GEN_SRP(update
->host
->name
, freshly_added_name_buf
);
683 INFO("SRP Update for host " PRI_DM_NAME_SRP
" was freshly added.",
684 DM_NAME_PARAM_SRP(update
->host
->name
, freshly_added_name_buf
));
685 update_finished(update
, dns_rcode_noerror
);
688 case refresh_existing
:
689 DM_NAME_GEN_SRP(update
->host
->name
, refreshed_name_buf
);
690 INFO("SRP Update for host " PRI_DM_NAME_SRP
" was refreshed.",
691 DM_NAME_PARAM_SRP(update
->host
->name
, refreshed_name_buf
));
692 update_finished(update
, dns_rcode_noerror
);
695 case create_nonexistent_instance
:
696 DM_NAME_GEN_SRP(update
->instance
->name
, create_instance_buf
);
697 INFO("Instance create for " PRI_DM_NAME_SRP
" succeeded",
698 DM_NAME_PARAM_SRP(update
->instance
->name
, create_instance_buf
));
699 // If we created a new instance, we need to remember it in case we have to undo it.
700 // To do that, we have to take it off the list.
701 for (pinstance
= &update
->instances
; *pinstance
!= NULL
; pinstance
= &((*pinstance
)->next
)) {
702 if (*pinstance
== update
->instance
) {
706 *pinstance
= update
->instance
->next
;
707 // If there are no more instances to update, then do the host add.
708 if (*pinstance
== NULL
) {
709 // STATE CHANGE: create_nonexistent_instance -> create_nonexistent_host
710 update
->state
= create_nonexistent_host
;
712 // Not done yet, do the next one.
713 update
->instance
= *pinstance
;
717 case refresh_existing_instance
:
718 DM_NAME_GEN_SRP(update
->instance
->name
, refreshed_instance_buf
);
719 INFO("Instance refresh for " PRI_S_SRP
" succeeded",
720 DM_NAME_PARAM_SRP(update
->instance
->name
, refreshed_instance_buf
));
722 // Move on to the next instance to update.
723 update
->instance
= update
->instance
->next
;
724 // If there are no more instances to update, then do the host add.
725 if (update
->instance
== NULL
) {
726 // STATE CHANGE: refresh_existing_instance -> create_nonexistent_host
727 update
->state
= create_nonexistent_host
;
729 // Not done yet, do the next one.
730 // STATE CHANGE: refresh_existing_instance -> create_nonexistent_instance
731 update
->state
= create_nonexistent_instance
;
735 case create_nonexistent_host
:
736 DM_NAME_GEN_SRP(update
->instance
->name
, new_host_buf
);
737 INFO("SRP Update for new host " PRI_S_SRP
" was successful.",
738 DM_NAME_PARAM_SRP(update
->instance
->name
, new_host_buf
));
739 update_finished(update
, dns_rcode_noerror
);
742 case refresh_existing_host
:
743 DM_NAME_GEN_SRP(update
->instance
->name
, existing_host_buf
);
744 INFO("SRP Update for existing host " PRI_S_SRP
" was successful.",
745 DM_NAME_PARAM_SRP(update
->instance
->name
, existing_host_buf
));
746 update_finished(update
, dns_rcode_noerror
);
749 case delete_failed_instance
:
750 DM_NAME_GEN_SRP(update
->host
->name
, failed_instance_buf
);
751 INFO("Instance deletes for host %s succeeded",
752 DM_NAME_PARAM_SRP(update
->host
->name
, failed_instance_buf
));
753 update_finished(update
, update
->fail_rcode
);
758 // We will get NXRRSET if we were adding an existing host with the prerequisite that a KEY
759 // RR exist on the name with the specified value. Some other KEY RR may exist, or there may
760 // be no such RRSET; we can't tell from this response.
761 case dns_rcode_nxrrset
:
762 switch(update
->state
) {
763 case connect_to_server
: // Can't get a response while connecting.
764 case create_nonexistent
: // Can't get nxdomain when creating.
765 case create_nonexistent_instance
: // same
766 case create_nonexistent_host
: // same
767 case delete_failed_instance
: // There are no prerequisites for deleting failed instances, so
768 // in principle this should never fail.
771 case refresh_existing
:
772 // If we get an NXDOMAIN when doing a refresh, it means either that there is a conflict,
773 // or that one of the instances we are refreshing doesn't exist. So now do the instances
776 // STATE CHANGE: refresh_existing -> create_nonexistent
777 update
->state
= create_nonexistent
;
778 update
->instance
= update
->instances
;
781 case refresh_existing_instance
:
782 // In this case, we tried to update an existing instance and found that the prerequisite
783 // didn't match. This means either that there is a conflict, or else that the instance
784 // expired and was deleted between the time that we attempted to create it and the time
785 // we attempted to update it. We could account for this with an create_nonexistent_instance_again
786 // state, but currently do not.
788 // If we have added some instances, we need to delete them before we send the fail response.
789 if (update
->added_instances
!= NULL
) {
790 // STATE CHANGE: refresh_existing_instance -> delete_failed_instance
791 update
->state
= delete_failed_instance
;
792 delete_added_instances
:
793 update
->instance
= update
->added_instances
;
794 update
->fail_rcode
= dns_rcode_get(wire
);
797 update_finished(update
, dns_rcode_get(wire
));
801 case refresh_existing_host
:
802 // In this case, there is a conflicting host entry. This means that all the service
803 // instances that exist and are owned by the key we are using are bogus, whether we
804 // created them or they were already there. However, it is not our mission to remove
805 // pre-existing messes here, so we'll just delete the ones we added.
806 if (update
->added_instances
!= NULL
) {
807 // STATE CHANGE: refresh_existing_host -> delete_failed_instance
808 update
->state
= delete_failed_instance
;
809 goto delete_added_instances
;
811 update_finished(update
, dns_rcode_get(wire
));
815 // We get YXDOMAIN if we specify a prerequisite that the name not exist, but it does exist.
816 case dns_rcode_yxdomain
:
817 switch(update
->state
) {
818 case connect_to_server
: // We can't get a response while connecting.
819 case refresh_existing
: // If we are refreshing, our prerequisites are all looking for
820 case refresh_existing_instance
: // a specific RR with a specific value, so we can never get
821 case refresh_existing_host
: // YXDOMAIN.
822 case delete_failed_instance
: // And if we are deleting failed instances, we should never get an error.
825 case create_nonexistent
:
826 // If we get an NXDOMAIN when doing a refresh, it means either that there is a conflict,
827 // or that one of the instances we are refreshing doesn't exist. So now do the instances
830 // STATE CHANGE: create_nonexistent -> create_nonexistent_instance
831 update
->state
= create_nonexistent_instance
;
832 update
->instance
= update
->instances
;
835 case create_nonexistent_instance
:
836 // STATE CHANGE: create_nonexistent_instance -> refresh_existing_instance
837 update
->state
= refresh_existing_instance
;
840 case create_nonexistent_host
:
841 // STATE CHANGE: create_nonexistent_host -> refresh_existing_host
842 update
->state
= refresh_existing_host
;
847 case dns_rcode_notauth
:
848 ERROR("DNS Authoritative server does not think we are authorized to update it, please fix.");
849 update_finished(update
, dns_rcode_servfail
);
852 // We may want to return different error codes or do more informative logging for some of these:
853 case dns_rcode_formerr
:
854 case dns_rcode_servfail
:
855 case dns_rcode_notimp
:
856 case dns_rcode_refused
:
857 case dns_rcode_yxrrset
:
858 case dns_rcode_notzone
:
859 case dns_rcode_dsotypeni
:
864 if (update
->state
!= initial_state
) {
865 INFO("Update state changed from " PUB_S_SRP
" to " PUB_S_SRP
, update_state_name(initial_state
),
866 update_state_name(update
->state
));
868 if (update
->instance
!= initial_instance
) {
869 DM_NAME_GEN_SRP(initial_instance
->name
, initial_name_buf
);
870 DM_NAME_GEN_SRP(update
->instance
->name
, updated_name_buf
);
871 INFO("Update instance changed from " PRI_DM_NAME_SRP
" to " PRI_DM_NAME_SRP
,
872 DM_NAME_PARAM_SRP(initial_instance
->name
, initial_name_buf
),
873 DM_NAME_PARAM_SRP(update
->instance
->name
, updated_name_buf
));
875 if (construct_update(update
)) {
878 ERROR("Failed to construct update");
879 update_finished(update
, dns_rcode_servfail
);
885 srp_update_start(comm_t
*connection
, dns_message_t
*parsed_message
, dns_host_description_t
*host
,
886 service_instance_t
*instance
, service_t
*service
, dns_name_t
*update_zone
,
887 uint32_t lease_time
, uint32_t key_lease_time
)
891 // Allocate the data structure
892 update
= calloc(1, sizeof *update
);
893 if (update
== NULL
) {
894 ERROR("start_dns_update: unable to allocate update structure!");
897 // Allocate the buffer in which updates will be constructed.
898 update
->update
= calloc(1, DNS_MAX_UDP_PAYLOAD
);
899 if (update
->update
== NULL
) {
900 ERROR("start_dns_update: unable to allocate update message buffer.");
903 update
->update_max
= DNS_DATA_SIZE
;
905 // Retain the stuff we're supposed to send.
907 update
->instances
= instance
;
908 update
->services
= service
;
909 update
->parsed_message
= parsed_message
;
910 update
->message
= connection
->message
;
911 update
->state
= connect_to_server
;
912 update
->zone_name
= update_zone
;
913 update
->client
= connection
;
915 // Start the connection to the server
916 update
->server
= ioloop_connect(&dns_server
, false, true, update_reply_callback
,
917 update_connect_callback
, update_disconnect_callback
, update_finalize
, update
);
918 if (update
->server
== NULL
) {
922 INFO("Connecting to auth server.");
927 key_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
929 hmac_key_t
*key
= context
;
933 uint8_t keybuf
[SRP_SHA256_DIGEST_SIZE
];
936 // Validate the constant-size stuff first.
937 if (strcasecmp(hunks
[1], "in")) {
938 ERROR("Expecting tsig key class IN, got %s.", hunks
[1]);
942 if (strcasecmp(hunks
[2], "key")) {
943 ERROR("expecting tsig key type KEY, got %s", hunks
[2]);
947 // There's not much meaning to be extracted from the flags.
948 val
= strtol(hunks
[3], &endptr
, 10);
949 if (*endptr
!= 0 || endptr
== hunks
[3]) {
950 ERROR("Invalid key flags: %s", hunks
[3]);
954 // The protocol number as produced by BIND will always be 3, meaning DNSSEC, but of
955 // course we aren't using this key for DNSSEC, so it's not clear that we should take
956 // this seriously; hence we just check to see that it's a number.
957 val
= strtol(hunks
[4], &endptr
, 10);
958 if (*endptr
!= 0 || endptr
== hunks
[4]) {
959 ERROR("Invalid protocol number: %s", hunks
[4]);
963 // The key algorithm should be HMAC-SHA253. BIND uses 163, but this is not registered
964 // with IANA. So again, we don't actually require this, but we do validate it so that
965 // if someone generated the wrong key type, they'll get a message.
966 val
= strtol(hunks
[5], &endptr
, 10);
967 if (*endptr
!= 0 || endptr
== hunks
[5]) {
968 ERROR("Invalid protocol number: %s", hunks
[5]);
972 INFO("Warning: Protocol number for HMAC-SHA256 TSIG KEY is not 163, but %ld", val
);
975 key
->name
= dns_pres_name_parse(hunks
[0]);
976 if (key
->name
== NULL
) {
977 ERROR("Invalid key name: %s", hunks
[0]);
981 error
= srp_base64_parse(hunks
[6], &len
, keybuf
, sizeof keybuf
);
983 ERROR("Invalid HMAC-SHA256 key: %s", strerror(errno
));
987 // The key should be 32 bytes (256 bits).
989 ERROR("Invalid (null) secret for key %s", hunks
[0]);
992 key
->secret
= malloc(len
);
993 if (key
->secret
== NULL
) {
994 ERROR("Unable to allocate space for secret for key %s", hunks
[0]);
996 dns_name_free(key
->name
);
1000 memcpy(key
->secret
, keybuf
, len
);
1002 key
->algorithm
= SRP_HMAC_TYPE_SHA256
;
1006 config_file_verb_t key_verbs
[] = {
1007 { NULL
, 7, 7, key_handler
}
1009 #define NUMKEYVERBS ((sizeof key_verbs) / sizeof (config_file_verb_t))
1012 parse_hmac_key_file(const char *filename
)
1014 hmac_key_t
*key
= calloc(1, sizeof *key
);
1016 ERROR("No memory for tsig key structure.");
1019 if (!config_parse(key
, filename
, key_verbs
, NUMKEYVERBS
)) {
1020 ERROR("Failed to parse key file.");
1028 main(int argc
, char **argv
)
1031 subnet_t
*tcp_validators
= NULL
;
1032 udp_validator_t
*udp_validators
= NULL
;
1033 udp_validator_t
*NULLABLE
*NONNULL up
= &udp_validators
;
1034 subnet_t
*NULLABLE
*NONNULL nt
= &tcp_validators
;
1035 subnet_t
*NULLABLE
*NONNULL sp
;
1038 socklen_t len
, prefalen
;
1041 bool got_server
= false;
1043 // Read the configuration from the command line.
1044 for (i
= 1; i
< argc
; i
++) {
1045 if (!strcmp(argv
[i
], "-s")) {
1047 ERROR("only one authoritative server can be specified.");
1048 return usage(argv
[0]);
1051 ERROR("-s is missing dns server IP address.");
1052 return usage(argv
[0]);
1054 len
= getipaddr(&dns_server
, argv
[i
]);
1056 ERROR("Invalid IP address: %s.", argv
[i
]);
1057 return usage(argv
[0]);
1060 ERROR("-s is missing dns server port.");
1061 return usage(argv
[0]);
1063 port
= strtol(argv
[i
], &s
, 10);
1064 if (s
== argv
[i
] || s
[0] != '\0') {
1065 ERROR("Invalid port number: %s", argv
[i
]);
1066 return usage(argv
[0]);
1068 if (dns_server
.sa
.sa_family
== AF_INET
) {
1069 dns_server
.sin
.sin_port
= htons(port
);
1071 dns_server
.sin6
.sin6_port
= htons(port
);
1074 } else if (!strcmp(argv
[i
], "-k")) {
1076 ERROR("-k is missing key file name.");
1077 return usage(argv
[0]);
1079 key
= parse_hmac_key_file(argv
[i
]);
1080 // Someething should already have printed the error message.
1084 } else if (!strcmp(argv
[i
], "-t") || !strcmp(argv
[i
], "-u")) {
1085 if (!strcmp(argv
[i
], "-u")) {
1087 ERROR("-u is missing interface name.");
1088 return usage(argv
[0]);
1090 *up
= calloc(1, sizeof **up
);
1092 ERROR("udp_validators: out of memory.");
1093 return usage(argv
[0]);
1095 (*up
)->ifname
= strdup(argv
[i
]);
1096 if ((*up
)->ifname
== NULL
) {
1097 ERROR("udp validators: ifname: out of memory.");
1098 return usage(argv
[0]);
1100 sp
= &((*up
)->subnets
);
1106 ERROR("%s requires at least one prefix.", argv
[i
- 1]);
1107 return usage(argv
[0]);
1109 s
= strchr(argv
[i
], '/');
1111 ERROR("%s is not a prefix.", argv
[i
]);
1112 return usage(argv
[0]);
1116 prefalen
= getipaddr(&pref
, argv
[i
]);
1118 ERROR("%s is not a valid prefix address.", argv
[i
]);
1119 return usage(argv
[0]);
1121 width
= strtol(s
, &p
, 10);
1122 if (s
== p
|| p
[0] != '\0') {
1123 ERROR("%s (prefix width) is not a number.", p
);
1124 return usage(argv
[0]);
1127 (pref
.sa
.sa_family
== AF_INET
&& width
> 32) ||
1128 (pref
.sa
.sa_family
== AF_INET6
&& width
> 64)) {
1129 ERROR("%s is not a valid prefix length for %s", p
,
1130 pref
.sa
.sa_family
== AF_INET
? "IPv4" : "IPv6");
1131 return usage(argv
[0]);
1134 *nt
= calloc(1, sizeof **nt
);
1136 ERROR("tcp_validators: out of memory.");
1140 (*nt
)->preflen
= width
;
1141 (*nt
)->family
= pref
.sa
.sa_family
;
1142 if (pref
.sa
.sa_family
== AF_INET
) {
1143 memcpy((*nt
)->bytes
, &pref
.sin
.sin_addr
, 4);
1145 memcpy((*nt
)->bytes
, &pref
.sin6
.sin6_addr
, 8);
1148 // *up will be non-null for -u and null for -t.
1150 up
= &((*up
)->next
);
1157 ERROR("No authoritative DNS server specified to take updates!");
1161 if (!ioloop_init()) {
1165 if (!srp_proxy_listen("home.arpa")) {
1169 // For now, hardcoded, should be configurable
1170 service_update_zone
= dns_pres_name_parse("home.arpa");
1174 something
= ioloop_events(0);
1175 INFO("dispatched %d events.", something
);
1182 // c-file-style: "bsd"
1183 // c-basic-offset: 4
1185 // indent-tabs-mode: nil