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 update proxy. 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>
58 #include "srp-crypto.h"
60 #include "dnssd-proxy.h"
62 #include "config-parse.h"
64 static addr_t dns_server
;
65 static hmac_key_t
*key
;
68 usage(const char *progname
)
70 ERROR("usage: %s -s <addr> <port> -k <key-file> -t <subnet> ... -u <ifname> <subnet> ...", progname
);
71 ERROR(" -s can only appear once.");
72 ERROR(" -k can appear once.");
73 ERROR(" -t can only appear once, and is followed by one or more subnets.");
74 ERROR(" -u can appear more than once, is followed by one interface name, and");
75 ERROR(" one or more subnets.");
76 ERROR(" <addr> is an IPv4 address or IPv6 address.");
77 ERROR(" <port> is a UDP port number.");
78 ERROR(" <key-file> is a file containing an HMAC-SHA256 key for authenticating updates to the auth server.");
79 ERROR(" <subnet> is an IP address followed by a slash followed by the prefix width.");
80 ERROR(" <ifname> is the printable name of the interface.");
81 ERROR("ex: srp-gw -s 2001:DB8::1 53 -k srp.key -t 2001:DB8:1300::/48 -u en0 2001:DB8:1300:1100::/56");
85 #define name_to_wire(towire, name) name_to_wire_(towire, name, __LINE__)
87 name_to_wire_(dns_towire_state_t
*towire
, dns_name_t
*name
, int line
)
89 // Does compression...
90 dns_concatenate_name_to_wire_(towire
, name
, NULL
, NULL
, line
);
94 rdata_to_wire(dns_towire_state_t
*towire
, dns_rr_t
*rr
)
96 dns_txt_element_t
*txt
;
98 dns_rdlength_begin(towire
);
100 // These are the only types we expect to see. If something else were passed, it would be written as rdlen=0.
103 name_to_wire(towire
, rr
->data
.ptr
.name
);
107 dns_u16_to_wire(towire
, rr
->data
.srv
.priority
);
108 dns_u16_to_wire(towire
, rr
->data
.srv
.weight
);
109 dns_u16_to_wire(towire
, rr
->data
.srv
.port
);
110 name_to_wire(towire
, rr
->data
.srv
.name
);
114 for (txt
= rr
->data
.txt
; txt
!= NULL
; txt
= txt
->next
) {
115 dns_u8_to_wire(towire
, txt
->len
);
116 dns_rdata_raw_data_to_wire(towire
, txt
->data
, txt
->len
);
121 dns_u16_to_wire(towire
, rr
->data
.key
.flags
);
122 dns_u8_to_wire(towire
, rr
->data
.key
.protocol
);
123 dns_u8_to_wire(towire
, rr
->data
.key
.algorithm
);
124 dns_rdata_raw_data_to_wire(towire
, rr
->data
.key
.key
, rr
->data
.key
.len
);
128 dns_rdata_raw_data_to_wire(towire
, &rr
->data
.a
, sizeof rr
->data
.a
);
131 case dns_rrtype_aaaa
:
132 dns_rdata_raw_data_to_wire(towire
, &rr
->data
.aaaa
, sizeof rr
->data
.aaaa
);
136 dns_rdlength_end(towire
);
139 // We only list the types we are using--there are other types that we don't support.
140 typedef enum prereq_type prereq_type_t
;
142 update_rrset_equals
, // RFC 2136 section 2.4.2: RRset Exists (Value Dependent)
143 update_name_not_in_use
, // RFC 2136 section 2.4.5: Name Is Not In Use
147 add_prerequisite(dns_wire_t
*msg
, dns_towire_state_t
*towire
, prereq_type_t ptype
, dns_name_t
*name
, dns_rr_t
*rr
)
149 char namebuf
[DNS_MAX_NAME_SIZE
+ 1];
150 if (ntohs(msg
->nscount
) != 0 || ntohs(msg
->arcount
) != 0) {
151 ERROR("%s: adding prerequisite after updates", dns_name_print(name
, namebuf
, sizeof namebuf
));
152 towire
->truncated
= true;
154 name_to_wire(towire
, name
);
156 case update_rrset_equals
:
157 dns_u16_to_wire(towire
, rr
->type
);
158 dns_u16_to_wire(towire
, rr
->qclass
);
159 dns_ttl_to_wire(towire
, 0);
160 rdata_to_wire(towire
, rr
);
162 case update_name_not_in_use
:
163 dns_u16_to_wire(towire
, dns_rrtype_any
); // TYPE
164 dns_u16_to_wire(towire
, dns_qclass_none
); // CLASS
165 dns_ttl_to_wire(towire
, 0); // TTL
166 dns_u16_to_wire(towire
, 0); // RDLEN
169 msg
->ancount
= htons(ntohs(msg
->ancount
) + 1);
172 // We actually only support one type of delete, so it's a bit silly to specify it, but in principle we might
174 typedef enum delete_type delete_type_t
;
176 delete_name
, // RFC 2136 section 2.5.3: Delete all RRsets from a name
180 add_delete(dns_wire_t
*msg
, dns_towire_state_t
*towire
, delete_type_t dtype
, dns_name_t
*name
)
182 name_to_wire(towire
, name
);
185 dns_u16_to_wire(towire
, dns_rrtype_any
); // TYPE
186 dns_u16_to_wire(towire
, dns_qclass_any
); // CLASS
187 dns_ttl_to_wire(towire
, 0); // TTL
188 dns_u16_to_wire(towire
, 0); // RDLEN
191 msg
->nscount
= htons(ntohs(msg
->nscount
) + 1);
194 // Copy the RR we received in the SRP update out in wire format.
197 add_rr(dns_wire_t
*msg
, dns_towire_state_t
*towire
, dns_name_t
*name
, dns_rr_t
*rr
)
200 name_to_wire(towire
, name
);
201 dns_u16_to_wire(towire
, rr
->type
); // TYPE
202 dns_u16_to_wire(towire
, rr
->qclass
); // CLASS
203 dns_ttl_to_wire(towire
, rr
->ttl
); // TTL
204 rdata_to_wire(towire
, rr
); // RDLEN
205 msg
->nscount
= htons(ntohs(msg
->nscount
) + 1);
209 // Free all the stuff that we accumulated while processing the SRP update.
211 srp_update_free(update_t
*update
)
213 // Free all of the structures we collated RRs into:
214 srp_update_free_parts(update
->instances
, update
->added_instances
, update
->services
, update
->host
);
215 // We don't need to free the zone name: it's either borrowed from the message,
216 // or it's service_update_zone, which is static.
217 ioloop_message_release(update
->message
);
218 dns_message_free(update
->parsed_message
);
222 // Construct an update of the specified type, assuming that the record being updated
223 // either exists or does not exist, depending on the value of exists. Actual records
224 // to be update are taken from the update_t.
228 // The goal of the update is to either bring the zone to the state described in the SRP update, or
229 // determine that the state described in the SRP update conflicts with what is already present in
232 // Possible scenarios:
233 // 1. Update and Zone are the same (A and AAAA records may differ):
235 // a. for each instance: KEY RR exists on instance name and is the same
236 // b. for host: KEY RR exists on host name and is the same
238 // a. for each instance: delete all records on instance name, add KEY RR, add SRV RR, add TXT RR
239 // b. for host: delete host instance, add A, AAAA and KEY RRs
240 // c. for each service: add PTR record pointing on service name to service instance name
242 // We should try 1 first, because it should be the steady state case; that is, it should be what happens
244 // If 1 fails, then we could have some service instances present and others not. There is no way to
245 // know without trying. We can at this point either try to add each service instance in a separate update,
246 // or assume that none are present and add them all at once, and then if this fails add them individually.
247 // I think that it makes sense to try them all first, because that should be the second most common case:
249 // 2. Nothing in update is present in zone:
251 // a. For each instance: instance name is not in use
252 // b. Host name is not in use
254 // a. for each instance: add KEY RR, add SRV RR, add TXT RR on instance name
255 // b. for host: add A, AAAA and KEY RRs on host name
256 // c. for each service: add PTR record pointing on service name to service instance name
258 // If either (1) or (2) works, we're done. If both fail, then we need to do the service instance updates
259 // and host update one by one. This is a bit nasty because we actually have to try twice: once assuming
260 // the RR exists, and once assuming it doesn't. If any of the instance updates fail, or the host update
261 // fails, we delete all the ones that succeeded.
263 // In the cases other than (1) and (2), we can add all the service PTRs in the host update, because they're
264 // only added if the host update succeeds; if it fails, we have to go back and remove all the service
267 // One open question for the SRP document: we probably want to signal whether the conflict is with the
268 // hostname or one of the service instance names. We can do this with an EDNS(0) option.
271 // - Try to update assuming everything is there already (case 1)
272 // - Try to update assuming nothing is there already (case 2)
273 // - For each service instance:
274 // - Try to update assuming it's not there; if this succeeds, add this instance to the list of
275 // instances that have been added. If not:
276 // - Try to update assuming it is there
277 // - If this fails, go to fail
278 // - Try to update the host (and also services) assuming the host is not there. If this fails:
279 // - Try to update the host (and also services) assuming the host is there. If this succeeds:
282 // - For each service instance in the list of instances that have been added:
283 // - delete all records on the instance name.
285 // One thing that isn't accounted for here: it's possible that a previous update added some but not all
286 // instances in the current update. Subsequently, some other device may have claimed an instance that is
287 // present but in conflict in the current update. In this case, all of the instances prior to that one
288 // in the update will actually have been updated by this update, but then the update as a whole will fail.
289 // I think this is unlikely to be an actual problem, and there's no way to address it without a _lot_ of
293 construct_update(update_t
*update
)
295 dns_towire_state_t towire
;
296 dns_wire_t
*msg
= update
->update
; // Solely to reduce the amount of typing.
297 service_instance_t
*instance
;
301 // Set up the message constructor
302 memset(&towire
, 0, sizeof towire
);
303 towire
.p
= &msg
->data
[0]; // We start storing RR data here.
304 towire
.lim
= &msg
->data
[0] + update
->update_max
; // This is the limit to how much we can store.
305 towire
.message
= msg
;
307 // Initialize the update message...
308 memset(msg
, 0, DNS_HEADER_SIZE
);
309 dns_qr_set(msg
, dns_qr_query
);
310 dns_opcode_set(msg
, dns_opcode_update
);
311 msg
->id
= srp_random16();
313 // An update always has one question, which is the zone name.
314 msg
->qdcount
= htons(1);
315 name_to_wire(&towire
, update
->zone_name
);
316 dns_u16_to_wire(&towire
, dns_rrtype_soa
);
317 dns_u16_to_wire(&towire
, dns_qclass_in
);
319 switch(update
->state
) {
320 case connect_to_server
:
321 ERROR("Update construction requested when still connecting.");
322 update
->update_length
= 0;
325 // Do a DNS Update for a service instance
326 case refresh_existing
:
327 // Add a "KEY exists and is <x> and a PTR exists and is <x> prerequisite for each instance being updated.
328 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
329 add_prerequisite(msg
, &towire
, update_rrset_equals
, instance
->name
, update
->host
->key
);
331 add_prerequisite(msg
, &towire
, update_rrset_equals
, update
->host
->name
, update
->host
->key
);
332 // Now add a delete for each service instance
333 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
334 add_delete(msg
, &towire
, delete_name
, instance
->name
);
336 add_delete(msg
, &towire
, delete_name
, update
->host
->name
);
339 // Now add the update for each instance.
340 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
341 add_rr(msg
, &towire
, instance
->name
, update
->host
->key
);
342 add_rr(msg
, &towire
, instance
->name
, instance
->srv
);
343 add_rr(msg
, &towire
, instance
->name
, instance
->txt
);
345 // Add the update for each service
346 for (service
= update
->services
; service
; service
= service
->next
) {
347 add_rr(msg
, &towire
, service
->rr
->name
, service
->rr
);
349 // Add the host records...
350 add_rr(msg
, &towire
, update
->host
->name
, update
->host
->key
);
351 for (reg
= update
->host
->a
; reg
; reg
= reg
->next
) {
352 add_rr(msg
, &towire
, update
->host
->name
, reg
->rr
);
354 for (reg
= update
->host
->aaaa
; reg
; reg
= reg
->next
) {
355 add_rr(msg
, &towire
, update
->host
->name
, reg
->rr
);
359 case create_nonexistent
:
360 // Add a "name not in use" prerequisite for each instance being updated.
361 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
362 add_prerequisite(msg
, &towire
, update_name_not_in_use
, instance
->name
, (dns_rr_t
*)NULL
);
364 add_prerequisite(msg
, &towire
, update_name_not_in_use
, update
->host
->name
, (dns_rr_t
*)NULL
);
367 case create_nonexistent_instance
:
368 // The only prerequisite is that this specific service instance doesn't exist.
369 add_prerequisite(msg
, &towire
, update_name_not_in_use
, update
->instance
->name
, (dns_rr_t
*)NULL
);
372 case refresh_existing_instance
:
373 // If instance already exists, prerequisite is that it has the same key, and we also have to
374 // delete all RRs on the name before adding our RRs, in case they have changed.
375 add_prerequisite(msg
, &towire
, update_rrset_equals
, update
->instance
->name
, update
->host
->key
);
376 add_delete(msg
, &towire
, delete_name
, update
->instance
->name
);
378 add_rr(msg
, &towire
, update
->instance
->name
, update
->host
->key
);
379 add_rr(msg
, &towire
, update
->instance
->name
, update
->instance
->srv
);
380 add_rr(msg
, &towire
, update
->instance
->name
, update
->instance
->txt
);
383 case create_nonexistent_host
:
384 add_prerequisite(msg
, &towire
, update_name_not_in_use
, update
->host
->name
, (dns_rr_t
*)NULL
);
387 case refresh_existing_host
:
388 add_prerequisite(msg
, &towire
, update_rrset_equals
, update
->host
->name
, update
->host
->key
);
389 add_delete(msg
, &towire
, delete_name
, update
->host
->name
);
390 // Add the service PTRs here--these don't need to be in a separate update, because if we get here
391 // the only thing that can make adding them not okay is if adding the host fails.
392 // Add the update for each service
393 for (service
= update
->services
; service
; service
= service
->next
) {
394 add_rr(msg
, &towire
, service
->rr
->name
, service
->rr
);
397 // Add the host records...
398 add_rr(msg
, &towire
, update
->host
->name
, update
->host
->key
);
399 for (reg
= update
->host
->a
; reg
; reg
= reg
->next
) {
400 add_rr(msg
, &towire
, update
->host
->name
, reg
->rr
);
402 for (reg
= update
->host
->aaaa
; reg
; reg
= reg
->next
) {
403 add_rr(msg
, &towire
, update
->host
->name
, reg
->rr
);
407 case delete_failed_instance
:
408 // Delete all the instances we successfull added before discovering a problem.
409 // It is possible in principle that these could have been overwritten by some other
410 // process and we could be deleting the wrong stuff, but in practice this should
411 // never happen if these are legitimately managed by SRP. Once a name has been
412 // claimed by SRP, it should continue to be managed by SRP until its lease expires
413 // and SRP deletes it, at which point it is of course fair game.
414 for (instance
= update
->instances
; instance
; instance
= instance
->next
) {
415 add_delete(msg
, &towire
, delete_name
, instance
->name
);
419 if (towire
.error
!= 0) {
420 ERROR("construct_update: error %s while generating update at line %d", strerror(towire
.error
), towire
.line
);
423 update
->update_length
= towire
.p
- (uint8_t *)msg
;
428 update_finished(update_t
*update
, int rcode
)
430 comm_t
*comm
= update
->client
;
433 INFO("Update Finished, rcode = " PUB_S_SRP
, dns_rcode_name(rcode
));
435 memset(&response
, 0, DNS_HEADER_SIZE
);
436 response
.id
= update
->message
->wire
.id
;
437 response
.bitfield
= update
->message
->wire
.bitfield
;
438 dns_rcode_set(&response
, rcode
);
440 iov
.iov_base
= &response
;
441 iov
.iov_len
= DNS_HEADER_SIZE
;
443 comm
->send_response(comm
, update
->message
, &iov
, 1);
445 // If success, construct a response
446 // If fail, send a quick status code
447 // Signal host name conflict and instance name conflict using different rcodes (?)
448 // Okay, so if there's a host name/instance name conflict, and the host name has the right key, then
449 // the instance name is actually bogus and should be overwritten.
450 // If the host has the wrong key, and the instance is present, then the instance is also bogus.
451 // So in each of these cases, perhaps we should just gc the instance.
452 // This would mean that there is nothing to signal: either the instance is a mismatch, and we
453 // overwrite it and return success, or the host is a mismatch and we gc the instance and return failure.
454 ioloop_close(&update
->server
->io
);
455 srp_update_free(update
);
459 update_send(update_t
*update
)
462 dns_towire_state_t towire
;
463 dns_wire_t
*msg
= update
->update
;
466 #ifdef DEBUG_DECODE_UPDATE
467 dns_message_t
*decoded
;
470 // Set up the message constructor
471 memset(&towire
, 0, sizeof towire
);
472 towire
.p
= (uint8_t *)msg
+ update
->update_length
; // We start storing RR data here.
473 towire
.lim
= &msg
->data
[0] + update
->update_max
; // This is the limit to how much we can store.
474 towire
.message
= msg
;
475 towire
.p_rdlength
= NULL
;
478 // If we have a key, sign the message with the key using TSIG HMAC-SHA256.
480 // Maintain an IOV with the bits of the message that we need to sign.
481 iov
[0].iov_base
= msg
;
483 name_to_wire(&towire
, key
->name
);
484 iov
[0].iov_len
= towire
.p
- (uint8_t *)iov
[0].iov_base
;
485 dns_u16_to_wire(&towire
, dns_rrtype_tsig
); // RRTYPE
486 iov
[1].iov_base
= towire
.p
;
487 dns_u16_to_wire(&towire
, dns_qclass_any
); // CLASS
488 dns_ttl_to_wire(&towire
, 0); // TTL
489 iov
[1].iov_len
= towire
.p
- (uint8_t *)iov
[1].iov_base
;
490 // The message digest skips the RDLEN field.
491 dns_rdlength_begin(&towire
); // RDLEN
492 iov
[2].iov_base
= towire
.p
;
493 dns_full_name_to_wire(NULL
, &towire
, "hmac-sha256."); // Algorithm Name
494 gettimeofday(&tv
, NULL
);
495 dns_u48_to_wire(&towire
, tv
.tv_sec
); // Time since epoch
496 dns_u16_to_wire(&towire
, 300); // Fudge interval
497 // (clocks can be skewed by up to 5 minutes)
498 // Message digest doesn't cover MAC size or MAC fields, for obvious reasons, nor original message ID.
499 iov
[2].iov_len
= towire
.p
- (uint8_t *)iov
[2].iov_base
;
500 dns_u16_to_wire(&towire
, SRP_SHA256_DIGEST_SIZE
); // MAC Size
501 p_mac
= towire
.p
; // MAC
503 if (towire
.p
+ SRP_SHA256_DIGEST_SIZE
>= towire
.lim
) {
504 towire
.error
= ENOBUFS
;
505 towire
.truncated
= true;
506 towire
.line
= __LINE__
;
508 towire
.p
+= SRP_SHA256_DIGEST_SIZE
;
511 // We have to copy the message ID into the tsig signature; this is because in some cases, although not this one,
512 // the message ID will be overwritten. So the copy of the ID is what's validated, but it's copied into the
513 // header for validation, so we don't include it when generating the hash.
514 dns_rdata_raw_data_to_wire(&towire
, &msg
->id
, sizeof msg
->id
);
515 iov
[3].iov_base
= towire
.p
;
516 dns_u16_to_wire(&towire
, 0); // TSIG Error (always 0 on send).
517 dns_u16_to_wire(&towire
, 0); // Other Len (MBZ?)
518 iov
[3].iov_len
= towire
.p
- (uint8_t *)iov
[3].iov_base
;
519 dns_rdlength_end(&towire
);
521 // Okay, we have stored the TSIG signature, now compute the message digest.
522 srp_hmac_iov(key
, p_mac
, SRP_SHA256_DIGEST_SIZE
, &iov
[0], 4);
523 msg
->arcount
= htons(ntohs(msg
->arcount
) + 1);
524 update
->update_length
= towire
.p
- (const uint8_t *)msg
;
527 if (towire
.error
!= 0) {
528 ERROR("update_send: error \"%s\" while generating update at line %d",
529 strerror(towire
.error
), towire
.line
);
530 update_finished(update
, dns_rcode_servfail
);
534 #ifdef DEBUG_DECODE_UPDATE
535 if (!dns_wire_parse(&decoded
, msg
, update
->update_length
)) {
536 ERROR("Constructed message does not successfully parse.");
537 update_finished(update
, dns_rcode_servfail
);
542 // Transmit the update
543 iov
[0].iov_base
= update
->update
;
544 iov
[0].iov_len
= update
->update_length
;
545 update
->server
->send_response(update
->server
, update
->message
, iov
, 1);
549 update_connect_callback(comm_t
*comm
)
551 update_t
*update
= comm
->context
;
553 // Once we're connected, construct the first update.
554 INFO("Connected to " PUB_S_SRP
".", comm
->name
);
555 // STATE CHANGE: connect_to_server -> refresh_existing
556 update
->state
= refresh_existing
;
557 if (!construct_update(update
)) {
558 update_finished(update
, dns_rcode_servfail
);
565 update_state_name(update_state_t state
)
568 case connect_to_server
:
569 return "connect_to_server";
570 case create_nonexistent
:
571 return "create_nonexistent";
572 case refresh_existing
:
573 return "refresh_existing";
574 case create_nonexistent_instance
:
575 return "create_nonexistent_instance";
576 case refresh_existing_instance
:
577 return "refresh_existing_instance";
578 case create_nonexistent_host
:
579 return "create_nonexistent_host";
580 case refresh_existing_host
:
581 return "refresh_existing_host";
582 case delete_failed_instance
:
583 return "delete_failed_instance";
585 return "unknown state";
589 update_disconnect_callback(comm_t
*comm
, int error
)
591 update_t
*update
= comm
->context
;
593 if (update
->state
== connect_to_server
) {
594 INFO(PUB_S_SRP
" disconnected: " PUB_S_SRP
, comm
->name
, strerror(error
));
595 update_finished(update
, dns_rcode_servfail
);
597 // This could be bad if any updates succeeded.
598 ERROR("%s disconnected during update in state %s: %s",
599 comm
->name
, update_state_name(update
->state
), strerror(error
));
600 update_finished(update
, dns_rcode_servfail
);
605 update_reply_callback(comm_t
*comm
)
607 update_t
*update
= comm
->context
;
608 dns_wire_t
*wire
= &comm
->message
->wire
;
609 char namebuf
[DNS_MAX_NAME_SIZE
+ 1], namebuf1
[DNS_MAX_NAME_SIZE
+ 1];
610 service_instance_t
**pinstance
;
611 update_state_t initial_state
;
612 service_instance_t
*initial_instance
;
614 initial_instance
= update
->instance
;
615 initial_state
= update
->state
;
617 INFO("Message from " PUB_S_SRP
" in state " PUB_S_SRP
", rcode = " PUB_S_SRP
".", comm
->name
,
618 update_state_name(update
->state
), dns_rcode_name(dns_rcode_get(wire
)));
620 // Sanity check the response
621 if (dns_qr_get(wire
) == dns_qr_query
) {
622 ERROR("Received a query from the authoritative server!");
623 update_finished(update
, dns_rcode_servfail
);
626 if (dns_opcode_get(wire
) != dns_opcode_update
) {
627 ERROR("Received a response with opcode %d from the authoritative server!",
628 dns_opcode_get(wire
));
629 update_finished(update
, dns_rcode_servfail
);
632 if (update
->update
== NULL
) {
633 ERROR("Received a response from auth server when no update has been sent yet.");
634 update_finished(update
, dns_rcode_servfail
);
636 // This isn't an error in the protocol, because we might be pipelining. But we _aren't_ pipelining,
637 // so there is only one message in flight. So the message IDs should match.
638 if (update
->update
->id
!= wire
->id
) {
639 ERROR("Response doesn't have the expected id: %x != %x.", wire
->id
, update
->update
->id
);
640 update_finished(update
, dns_rcode_servfail
);
643 // Handle the case where the update succeeded.
644 switch(dns_rcode_get(wire
)) {
645 case dns_rcode_noerror
:
646 switch(update
->state
) {
647 case connect_to_server
: // Can't get a response when connecting.
649 ERROR("Invalid rcode \"%s\" for state %s",
650 dns_rcode_name(dns_rcode_get(wire
)), update_state_name(update
->state
));
651 update_finished(update
, dns_rcode_servfail
);
654 case create_nonexistent
: {
655 DM_NAME_GEN_SRP(update
->host
->name
, name_buf
);
656 INFO("SRP Update for host " PRI_DM_NAME_SRP
" was freshly added.",
657 DM_NAME_PARAM_SRP(update
->host
->name
, name_buf
));
658 update_finished(update
, dns_rcode_noerror
);
662 case refresh_existing
: {
663 DM_NAME_GEN_SRP(update
->host
->name
, name_buf
);
664 INFO("SRP Update for host " PRI_DM_NAME_SRP
" was refreshed.",
665 DM_NAME_PARAM_SRP(update
->host
->name
, name_buf
));
666 update_finished(update
, dns_rcode_noerror
);
670 case create_nonexistent_instance
: {
671 DM_NAME_GEN_SRP(update
->instances
->name
, name_buf
);
672 INFO("Instance create for " PRI_DM_NAME_SRP
" succeeded",
673 DM_NAME_PARAM_SRP(update
->instances
->name
, name_buf
));
674 // If we created a new instance, we need to remember it in case we have to undo it.
675 // To do that, we have to take it off the list.
676 for (pinstance
= &update
->instances
; *pinstance
!= NULL
; pinstance
= &((*pinstance
)->next
)) {
677 if (*pinstance
== update
->instance
) {
681 *pinstance
= update
->instance
->next
;
682 // If there are no more instances to update, then do the host add.
683 if (*pinstance
== NULL
) {
684 // STATE CHANGE: create_nonexistent_instance -> create_nonexistent_host
685 update
->state
= create_nonexistent_host
;
687 // Not done yet, do the next one.
688 update
->instance
= *pinstance
;
693 case refresh_existing_instance
: {
694 DM_NAME_GEN_SRP(update
->instance
->name
, name_buf
);
695 INFO("Instance refresh for " PRI_DM_NAME_SRP
" succeeded",
696 DM_NAME_PARAM_SRP(update
->instances
->name
, name_buf
));
698 // Move on to the next instance to update.
699 update
->instance
= update
->instance
->next
;
700 // If there are no more instances to update, then do the host add.
701 if (update
->instance
== NULL
) {
702 // STATE CHANGE: refresh_existing_instance -> create_nonexistent_host
703 update
->state
= create_nonexistent_host
;
705 // Not done yet, do the next one.
706 // STATE CHANGE: refresh_existing_instance -> create_nonexistent_instance
707 update
->state
= create_nonexistent_instance
;
712 case create_nonexistent_host
: {
713 DM_NAME_GEN_SRP(update
->host
->name
, name_buf
);
714 INFO("SRP Update for new host " PRI_DM_NAME_SRP
" was successful.",
715 DM_NAME_PARAM_SRP(update
->host
->name
, name_buf
));
716 update_finished(update
, dns_rcode_noerror
);
720 case refresh_existing_host
: {
721 DM_NAME_GEN_SRP(update
->host
->name
, name_buf
);
722 INFO("SRP Update for existing host " PRI_DM_NAME_SRP
" was successful.",
723 DM_NAME_PARAM_SRP(update
->host
->name
, name_buf
));
724 update_finished(update
, dns_rcode_noerror
);
728 case delete_failed_instance
: {
729 DM_NAME_GEN_SRP(update
->host
->name
, name_buf
);
730 INFO("Instance deletes for host " PRI_DM_NAME_SRP
" succeeded",
731 DM_NAME_PARAM_SRP(update
->host
->name
, name_buf
));
732 update_finished(update
, update
->fail_rcode
);
737 // We will get NXRRSET if we were adding an existing host with the prerequisite that a KEY
738 // RR exist on the name with the specified value. Some other KEY RR may exist, or there may
739 // be no such RRSET; we can't tell from this response.
740 case dns_rcode_nxrrset
:
741 switch(update
->state
) {
742 case connect_to_server
: // Can't get a response while connecting.
743 case create_nonexistent
: // Can't get nxdomain when creating.
744 case create_nonexistent_instance
: // same
745 case create_nonexistent_host
: // same
746 case delete_failed_instance
: // There are no prerequisites for deleting failed instances, so
747 // in principle this should never fail.
750 case refresh_existing
:
751 // If we get an NXDOMAIN when doing a refresh, it means either that there is a conflict,
752 // or that one of the instances we are refreshing doesn't exist. So now do the instances
755 // STATE CHANGE: refresh_existing -> create_nonexistent
756 update
->state
= create_nonexistent
;
757 update
->instance
= update
->instances
;
760 case refresh_existing_instance
:
761 // In this case, we tried to update an existing instance and found that the prerequisite
762 // didn't match. This means either that there is a conflict, or else that the instance
763 // expired and was deleted between the time that we attempted to create it and the time
764 // we attempted to update it. We could account for this with an create_nonexistent_instance_again
765 // state, but currently do not.
767 // If we have added some instances, we need to delete them before we send the fail response.
768 if (update
->added_instances
!= NULL
) {
769 // STATE CHANGE: refresh_existing_instance -> delete_failed_instance
770 update
->state
= delete_failed_instance
;
771 delete_added_instances
:
772 update
->instance
= update
->added_instances
;
773 update
->fail_rcode
= dns_rcode_get(wire
);
776 update_finished(update
, dns_rcode_get(wire
));
780 case refresh_existing_host
:
781 // In this case, there is a conflicting host entry. This means that all the service
782 // instances that exist and are owned by the key we are using are bogus, whether we
783 // created them or they were already there. However, it is not our mission to remove
784 // pre-existing messes here, so we'll just delete the ones we added.
785 if (update
->added_instances
!= NULL
) {
786 // STATE CHANGE: refresh_existing_host -> delete_failed_instance
787 update
->state
= delete_failed_instance
;
788 goto delete_added_instances
;
790 update_finished(update
, dns_rcode_get(wire
));
794 // We get YXDOMAIN if we specify a prerequisite that the name not exist, but it does exist.
795 case dns_rcode_yxdomain
:
796 switch(update
->state
) {
797 case connect_to_server
: // We can't get a response while connecting.
798 case refresh_existing
: // If we are refreshing, our prerequisites are all looking for
799 case refresh_existing_instance
: // a specific RR with a specific value, so we can never get
800 case refresh_existing_host
: // YXDOMAIN.
801 case delete_failed_instance
: // And if we are deleting failed instances, we should never get an error.
804 case create_nonexistent
:
805 // If we get an NXDOMAIN when doing a refresh, it means either that there is a conflict,
806 // or that one of the instances we are refreshing doesn't exist. So now do the instances
809 // STATE CHANGE: create_nonexistent -> create_nonexistent_instance
810 update
->state
= create_nonexistent_instance
;
811 update
->instance
= update
->instances
;
814 case create_nonexistent_instance
:
815 // STATE CHANGE: create_nonexistent_instance -> refresh_existing_instance
816 update
->state
= refresh_existing_instance
;
819 case create_nonexistent_host
:
820 // STATE CHANGE: create_nonexistent_host -> refresh_existing_host
821 update
->state
= refresh_existing_host
;
826 case dns_rcode_notauth
:
827 ERROR("DNS Authoritative server does not think we are authorized to update it, please fix.");
828 update_finished(update
, dns_rcode_servfail
);
831 // We may want to return different error codes or do more informative logging for some of these:
832 case dns_rcode_formerr
:
833 case dns_rcode_servfail
:
834 case dns_rcode_notimp
:
835 case dns_rcode_refused
:
836 case dns_rcode_yxrrset
:
837 case dns_rcode_notzone
:
838 case dns_rcode_dsotypeni
:
843 if (update
->state
!= initial_state
) {
844 INFO("Update state changed from " PUB_S_SRP
" to " PUB_S_SRP
, update_state_name(initial_state
),
845 update_state_name(update
->state
));
847 if (update
->instance
!= initial_instance
) {
848 DM_NAME_GEN_SRP(initial_instance
->name
, initial_name_buf
);
849 DM_NAME_GEN_SRP(update
->instance
->name
, updated_name_buf
);
850 INFO("Update instance changed from " PRI_DM_NAME_SRP
" to " PRI_DM_NAME_SRP
,
851 DM_NAME_PARAM_SRP(initial_instance
->name
, initial_name_buf
),
852 DM_NAME_PARAM_SRP(update
->instance
->name
, updated_name_buf
));
854 if (construct_update(update
)) {
857 ERROR("Failed to construct update");
858 update_finished(update
, dns_rcode_servfail
);
864 srp_update_start(comm_t
*connection
, dns_message_t
*parsed_message
, dns_host_description_t
*host
,
865 service_instance_t
*instance
, service_t
*service
, dns_name_t
*update_zone
)
869 // Allocate the data structure
870 update
= calloc(1, sizeof *update
);
871 if (update
== NULL
) {
872 ERROR("start_dns_update: unable to allocate update structure!");
875 // Allocate the buffer in which updates will be constructed.
876 update
->update
= calloc(1, DNS_MAX_UDP_PAYLOAD
);
877 if (update
->update
== NULL
) {
878 ERROR("start_dns_update: unable to allocate update message buffer.");
881 update
->update_max
= DNS_DATA_SIZE
;
883 // Retain the stuff we're supposed to send.
885 update
->instances
= instance
;
886 update
->services
= service
;
887 update
->parsed_message
= parsed_message
;
888 update
->message
= connection
->message
;
889 update
->state
= connect_to_server
;
890 update
->zone_name
= update_zone
;
891 update
->client
= connection
;
893 // Start the connection to the server
894 update
->server
= connect_to_host(&dns_server
, false, update_reply_callback
,
895 update_connect_callback
, update_disconnect_callback
, update
);
896 if (update
->server
== NULL
) {
904 key_handler(void *context
, const char *filename
, char **hunks
, int num_hunks
, int lineno
)
906 hmac_key_t
*key
= context
;
910 uint8_t keybuf
[SRP_SHA256_DIGEST_SIZE
];
913 // Validate the constant-size stuff first.
914 if (strcasecmp(hunks
[1], "in")) {
915 ERROR("Expecting tsig key class IN, got %s.", hunks
[1]);
919 if (strcasecmp(hunks
[2], "key")) {
920 ERROR("expecting tsig key type KEY, got %s", hunks
[2]);
924 // There's not much meaning to be extracted from the flags.
925 val
= strtol(hunks
[3], &endptr
, 10);
926 if (*endptr
!= 0 || endptr
== hunks
[3]) {
927 ERROR("Invalid key flags: %s", hunks
[3]);
931 // The protocol number as produced by BIND will always be 3, meaning DNSSEC, but of
932 // course we aren't using this key for DNSSEC, so it's not clear that we should take
933 // this seriously; hence we just check to see that it's a number.
934 val
= strtol(hunks
[4], &endptr
, 10);
935 if (*endptr
!= 0 || endptr
== hunks
[4]) {
936 ERROR("Invalid protocol number: %s", hunks
[4]);
940 // The key algorithm should be HMAC-SHA253. BIND uses 163, but this is not registered
941 // with IANA. So again, we don't actually require this, but we do validate it so that
942 // if someone generated the wrong key type, they'll get a message.
943 val
= strtol(hunks
[5], &endptr
, 10);
944 if (*endptr
!= 0 || endptr
== hunks
[5]) {
945 ERROR("Invalid protocol number: %s", hunks
[5]);
949 INFO("Warning: Protocol number for HMAC-SHA256 TSIG KEY is not 163, but %ld", val
);
952 key
->name
= dns_pres_name_parse(hunks
[0]);
953 if (key
->name
== NULL
) {
954 ERROR("Invalid key name: %s", hunks
[0]);
958 error
= srp_base64_parse(hunks
[6], &len
, keybuf
, sizeof keybuf
);
960 ERROR("Invalid HMAC-SHA256 key: %s", strerror(errno
));
964 // The key should be 32 bytes (256 bits).
966 ERROR("Invalid (null) secret for key %s", hunks
[0]);
969 key
->secret
= malloc(len
);
970 if (key
->secret
== NULL
) {
971 ERROR("Unable to allocate space for secret for key %s", hunks
[0]);
973 dns_name_free(key
->name
);
977 memcpy(key
->secret
, keybuf
, len
);
979 key
->algorithm
= SRP_HMAC_TYPE_SHA256
;
983 config_file_verb_t key_verbs
[] = {
984 { NULL
, 7, 7, key_handler
}
986 #define NUMKEYVERBS ((sizeof key_verbs) / sizeof (config_file_verb_t))
989 parse_hmac_key_file(const char *filename
)
991 hmac_key_t
*key
= calloc(1, sizeof *key
);
993 ERROR("No memory for tsig key structure.");
996 if (!config_parse(key
, filename
, key_verbs
, NUMKEYVERBS
)) {
997 ERROR("Failed to parse key file.");
1005 main(int argc
, char **argv
)
1008 subnet_t
*tcp_validators
= NULL
;
1009 udp_validator_t
*udp_validators
= NULL
;
1010 udp_validator_t
*NULLABLE
*NONNULL up
= &udp_validators
;
1011 subnet_t
*NULLABLE
*NONNULL nt
= &tcp_validators
;
1012 subnet_t
*NULLABLE
*NONNULL sp
;
1015 socklen_t len
, prefalen
;
1018 bool got_server
= false;
1020 // Read the configuration from the command line.
1021 for (i
= 1; i
< argc
; i
++) {
1022 if (!strcmp(argv
[i
], "-s")) {
1024 ERROR("only one authoritative server can be specified.");
1025 return usage(argv
[0]);
1028 ERROR("-s is missing dns server IP address.");
1029 return usage(argv
[0]);
1031 len
= getipaddr(&dns_server
, argv
[i
]);
1033 ERROR("Invalid IP address: %s.", argv
[i
]);
1034 return usage(argv
[0]);
1037 ERROR("-s is missing dns server port.");
1038 return usage(argv
[0]);
1040 port
= strtol(argv
[i
], &s
, 10);
1041 if (s
== argv
[i
] || s
[0] != '\0') {
1042 ERROR("Invalid port number: %s", argv
[i
]);
1043 return usage(argv
[0]);
1045 if (dns_server
.sa
.sa_family
== AF_INET
) {
1046 dns_server
.sin
.sin_port
= htons(port
);
1048 dns_server
.sin6
.sin6_port
= htons(port
);
1051 } else if (!strcmp(argv
[i
], "-k")) {
1053 ERROR("-k is missing key file name.");
1054 return usage(argv
[0]);
1056 key
= parse_hmac_key_file(argv
[i
]);
1057 // Someething should already have printed the error message.
1061 } else if (!strcmp(argv
[i
], "-t") || !strcmp(argv
[i
], "-u")) {
1062 if (!strcmp(argv
[i
], "-u")) {
1064 ERROR("-u is missing interface name.");
1065 return usage(argv
[0]);
1067 *up
= calloc(1, sizeof **up
);
1069 ERROR("udp_validators: out of memory.");
1070 return usage(argv
[0]);
1072 (*up
)->ifname
= strdup(argv
[i
]);
1073 if ((*up
)->ifname
== NULL
) {
1074 ERROR("udp validators: ifname: out of memory.");
1075 return usage(argv
[0]);
1077 sp
= &((*up
)->subnets
);
1083 ERROR("%s requires at least one prefix.", argv
[i
- 1]);
1084 return usage(argv
[0]);
1086 s
= strchr(argv
[i
], '/');
1088 ERROR("%s is not a prefix.", argv
[i
]);
1089 return usage(argv
[0]);
1093 prefalen
= getipaddr(&pref
, argv
[i
]);
1095 ERROR("%s is not a valid prefix address.", argv
[i
]);
1096 return usage(argv
[0]);
1098 width
= strtol(s
, &p
, 10);
1099 if (s
== p
|| p
[0] != '\0') {
1100 ERROR("%s (prefix width) is not a number.", p
);
1101 return usage(argv
[0]);
1104 (pref
.sa
.sa_family
== AF_INET
&& width
> 32) ||
1105 (pref
.sa
.sa_family
== AF_INET6
&& width
> 64)) {
1106 ERROR("%s is not a valid prefix length for %s", p
,
1107 pref
.sa
.sa_family
== AF_INET
? "IPv4" : "IPv6");
1108 return usage(argv
[0]);
1111 *nt
= calloc(1, sizeof **nt
);
1113 ERROR("tcp_validators: out of memory.");
1117 (*nt
)->preflen
= width
;
1118 (*nt
)->family
= pref
.sa
.sa_family
;
1119 if (pref
.sa
.sa_family
== AF_INET
) {
1120 memcpy((*nt
)->bytes
, &pref
.sin
.sin_addr
, 4);
1122 memcpy((*nt
)->bytes
, &pref
.sin6
.sin6_addr
, 8);
1125 // *up will be non-null for -u and null for -t.
1127 up
= &((*up
)->next
);
1134 ERROR("No authoritative DNS server specified to take updates!");
1138 if (!ioloop_init()) {
1142 if (!srp_proxy_listen()) {
1148 something
= ioloop_events(0);
1149 INFO("dispatched %d events.", something
);
1156 // c-file-style: "bsd"
1157 // c-basic-offset: 4
1159 // indent-tabs-mode: nil