]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/srp-dns-proxy.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / srp-dns-proxy.c
1 /* srp-gw.c
2 *
3 * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * This is a 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.
19 *
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.
24 *
25 * Note that this is not a full DNS proxy, so you can't just put it in front of a DNS server.
26 */
27
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)
33 // Event loop
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
40 // a different key.
41 // 6. Send back the response
42
43 #define __APPLE_USE_RFC_3542
44
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <errno.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <fcntl.h>
54 #include <sys/time.h>
55 #include <dns_sd.h>
56
57 #include "srp.h"
58 #include "dns-msg.h"
59 #include "srp-crypto.h"
60 #include "ioloop.h"
61 #include "srp-gw.h"
62 #include "config-parse.h"
63 #include "srp-proxy.h"
64
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;
68
69 static int
70 usage(const char *progname)
71 {
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");
84 return 1;
85 }
86
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.
89 void
90 update_free_parts(service_instance_t *service_instances, service_instance_t *added_instances,
91 service_t *services, dns_host_description_t *host_description)
92 {
93 service_instance_t *sip;
94 service_t *sp;
95
96 for (sip = service_instances; sip; ) {
97 service_instance_t *next = sip->next;
98 free(sip);
99 sip = next;
100 }
101 for (sip = added_instances; sip; ) {
102 service_instance_t *next = sip->next;
103 free(sip);
104 sip = next;
105 }
106 for (sp = services; sp; ) {
107 service_t *next = sp->next;
108 free(sp);
109 sp = next;
110 }
111 if (host_description != NULL) {
112 free(host_description);
113 }
114 }
115
116 // Free all the stuff that we accumulated while processing the SRP update.
117 void
118 update_free(update_t *update)
119 {
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);
126 free(update);
127 }
128
129
130 #define name_to_wire(towire, name) name_to_wire_(towire, name, __LINE__)
131 void
132 name_to_wire_(dns_towire_state_t *towire, dns_name_t *name, int line)
133 {
134 // Does compression...
135 dns_concatenate_name_to_wire_(towire, name, NULL, NULL, line);
136 }
137
138 void
139 rdata_to_wire(dns_towire_state_t *towire, dns_rr_t *rr)
140 {
141 dns_rdlength_begin(towire);
142
143 // These are the only types we expect to see. If something else were passed, it would be written as rdlen=0.
144 switch(rr->type) {
145 case dns_rrtype_ptr:
146 name_to_wire(towire, rr->data.ptr.name);
147 break;
148
149 case dns_rrtype_srv:
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);
154 break;
155
156 case dns_rrtype_txt:
157 dns_rdata_raw_data_to_wire(towire, rr->data.txt.data, rr->data.txt.len);
158 break;
159
160 case dns_rrtype_key:
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);
165 break;
166
167 case dns_rrtype_a:
168 dns_rdata_raw_data_to_wire(towire, &rr->data.a, sizeof rr->data.a);
169 break;
170
171 case dns_rrtype_aaaa:
172 dns_rdata_raw_data_to_wire(towire, &rr->data.aaaa, sizeof rr->data.aaaa);
173 break;
174 }
175
176 dns_rdlength_end(towire);
177 }
178
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;
181 enum prereq_type {
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
184 };
185
186 void
187 add_prerequisite(dns_wire_t *msg, dns_towire_state_t *towire, prereq_type_t ptype, dns_name_t *name, dns_rr_t *rr)
188 {
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;
193 }
194 name_to_wire(towire, name);
195 switch(ptype) {
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);
201 break;
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
207 break;
208 }
209 msg->ancount = htons(ntohs(msg->ancount) + 1);
210 }
211
212 // We actually only support one type of delete, so it's a bit silly to specify it, but in principle we might
213 // want more later.
214 typedef enum delete_type delete_type_t;
215 enum delete_type {
216 delete_name, // RFC 2136 section 2.5.3: Delete all RRsets from a name
217 };
218
219 void
220 add_delete(dns_wire_t *msg, dns_towire_state_t *towire, delete_type_t dtype, dns_name_t *name)
221 {
222 name_to_wire(towire, name);
223 switch(dtype) {
224 case delete_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
229 break;
230 }
231 msg->nscount = htons(ntohs(msg->nscount) + 1);
232 }
233
234 // Copy the RR we received in the SRP update out in wire format.
235
236 void
237 add_rr(dns_wire_t *msg, dns_towire_state_t *towire, dns_name_t *name, dns_rr_t *rr)
238 {
239 if (rr != NULL) {
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);
246 }
247 }
248
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.
252 //
253 // Analysis:
254 //
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
257 // the zone.
258 //
259 // Possible scenarios:
260 // 1. Update and Zone are the same (A and AAAA records may differ):
261 // Prerequisites:
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
264 // Update:
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
268 //
269 // We should try 1 first, because it should be the steady state case; that is, it should be what happens
270 // most of the time.
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:
275 //
276 // 2. Nothing in update is present in zone:
277 // Prerequisites:
278 // a. For each instance: instance name is not in use
279 // b. Host name is not in use
280 // Update:
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
284 //
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.
289 //
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
292 // instances.
293 //
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.
296 //
297 // The flow will be:
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:
307 // - return success
308 // fail:
309 // - For each service instance in the list of instances that have been added:
310 // - delete all records on the instance name.
311 //
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
317 // complexity.
318
319 bool
320 construct_update(update_t *update)
321 {
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;
325 service_t *service;
326 host_addr_t *host_addr;
327
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;
333
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();
339
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);
345
346 switch(update->state) {
347 case connect_to_server:
348 ERROR("Update construction requested when still connecting.");
349 update->update_length = 0;
350 return false;
351
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);
357 }
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);
362 }
363 add_delete(msg, &towire, delete_name, update->host->name);
364
365 add_instances:
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);
371 }
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);
375 }
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);
380 }
381 break;
382
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);
387 }
388 add_prerequisite(msg, &towire, update_name_not_in_use, update->host->name, (dns_rr_t *)NULL);
389 goto add_instances;
390
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);
394 goto add_instance;
395
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);
401 add_instance:
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);
405 break;
406
407 case create_nonexistent_host:
408 add_prerequisite(msg, &towire, update_name_not_in_use, update->host->name, (dns_rr_t *)NULL);
409 goto add_host;
410
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);
419 }
420 add_host:
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);
425 }
426 break;
427
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);
437 }
438 break;
439 }
440 if (towire.error != 0) {
441 ERROR("construct_update: error %s while generating update at line %d", strerror(towire.error), towire.line);
442 return false;
443 }
444 update->update_length = towire.p - (uint8_t *)msg;
445 return true;
446 }
447
448 void
449 update_finished(update_t *update, int rcode)
450 {
451 comm_t *comm = update->client;
452 struct iovec iov;
453 dns_wire_t response;
454 INFO("Update Finished, rcode = " PUB_S_SRP, dns_rcode_name(rcode));
455
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);
461
462 iov.iov_base = &response;
463 iov.iov_len = DNS_HEADER_SIZE;
464
465 comm->send_response(comm, update->message, &iov, 1);
466
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);
477 update_free(update);
478 }
479
480 void
481 update_send(update_t *update)
482 {
483 struct iovec iov[4];
484 dns_towire_state_t towire;
485 dns_wire_t *msg = update->update;
486 struct timeval tv;
487 uint8_t *p_mac;
488 #ifdef DEBUG_DECODE_UPDATE
489 dns_message_t *decoded;
490 #endif
491
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;
498 towire.p_opt = NULL;
499
500 // If we have a key, sign the message with the key using TSIG HMAC-SHA256.
501 if (key != NULL) {
502 // Maintain an IOV with the bits of the message that we need to sign.
503 iov[0].iov_base = msg;
504
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
524 if (!towire.error) {
525 if (towire.p + SRP_SHA256_DIGEST_SIZE >= towire.lim) {
526 towire.error = ENOBUFS;
527 towire.truncated = true;
528 towire.line = __LINE__;
529 } else {
530 towire.p += SRP_SHA256_DIGEST_SIZE;
531 }
532 }
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);
542
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;
547 }
548
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);
553 return;
554 }
555
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);
560 return;
561 }
562 #endif
563
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);
568 }
569
570 void
571 update_connect_callback(comm_t *comm)
572 {
573 update_t *update = comm->context;
574
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);
581 return;
582 }
583 update_send(update);
584 }
585
586 const char *NONNULL
587 update_state_name(update_state_t state)
588 {
589 switch(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";
606 }
607 return "unknown state";
608 }
609
610 void
611 update_finalize(io_t *context)
612 {
613 }
614
615 void
616 update_disconnect_callback(comm_t *comm, int error)
617 {
618 update_t *update = comm->context;
619
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);
623 } else {
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);
628 }
629 }
630
631 void
632 update_reply_callback(comm_t *comm)
633 {
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;
640
641 initial_instance = update->instance;
642 initial_state = update->state;
643
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)));
646
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);
651 return;
652 }
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);
657 return;
658 }
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);
662 }
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);
668 }
669
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.
675 invalid:
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);
679 return;
680
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);
686 return;
687
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);
693 return;
694
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) {
703 break;
704 }
705 }
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;
711 } else {
712 // Not done yet, do the next one.
713 update->instance = *pinstance;
714 }
715 break;
716
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));
721
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;
728 } else {
729 // Not done yet, do the next one.
730 // STATE CHANGE: refresh_existing_instance -> create_nonexistent_instance
731 update->state = create_nonexistent_instance;
732 }
733 break;
734
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);
740 return;
741
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);
747 return;
748
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);
754 return;
755 }
756 break;
757
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.
769 goto invalid;
770
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
774 // one at a time.
775
776 // STATE CHANGE: refresh_existing -> create_nonexistent
777 update->state = create_nonexistent;
778 update->instance = update->instances;
779 break;
780
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.
787
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);
795 break;
796 } else {
797 update_finished(update, dns_rcode_get(wire));
798 return;
799 }
800
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;
810 }
811 update_finished(update, dns_rcode_get(wire));
812 return;
813 }
814 break;
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.
823 goto invalid;
824
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
828 // one at a time.
829
830 // STATE CHANGE: create_nonexistent -> create_nonexistent_instance
831 update->state = create_nonexistent_instance;
832 update->instance = update->instances;
833 break;
834
835 case create_nonexistent_instance:
836 // STATE CHANGE: create_nonexistent_instance -> refresh_existing_instance
837 update->state = refresh_existing_instance;
838 break;
839
840 case create_nonexistent_host:
841 // STATE CHANGE: create_nonexistent_host -> refresh_existing_host
842 update->state = refresh_existing_host;
843 break;
844 }
845 break;
846
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);
850 return;
851
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:
860 default:
861 goto invalid;
862 }
863
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));
867 }
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));
874 }
875 if (construct_update(update)) {
876 update_send(update);
877 } else {
878 ERROR("Failed to construct update");
879 update_finished(update, dns_rcode_servfail);
880 }
881 return;
882 }
883
884 bool
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)
888 {
889 update_t *update;
890
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!");
895 return false;
896 }
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.");
901 return false;
902 }
903 update->update_max = DNS_DATA_SIZE;
904
905 // Retain the stuff we're supposed to send.
906 update->host = host;
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;
914
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) {
919 free(update);
920 return false;
921 }
922 INFO("Connecting to auth server.");
923 return true;
924 }
925
926 static bool
927 key_handler(void *context, const char *filename, char **hunks, int num_hunks, int lineno)
928 {
929 hmac_key_t *key = context;
930 long val;
931 char *endptr;
932 size_t len;
933 uint8_t keybuf[SRP_SHA256_DIGEST_SIZE];
934 int error;
935
936 // Validate the constant-size stuff first.
937 if (strcasecmp(hunks[1], "in")) {
938 ERROR("Expecting tsig key class IN, got %s.", hunks[1]);
939 return false;
940 }
941
942 if (strcasecmp(hunks[2], "key")) {
943 ERROR("expecting tsig key type KEY, got %s", hunks[2]);
944 return false;
945 }
946
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]);
951 return false;
952 }
953
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]);
960 return false;
961 }
962
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]);
969 return false;
970 }
971 if (val != 163) {
972 INFO("Warning: Protocol number for HMAC-SHA256 TSIG KEY is not 163, but %ld", val);
973 }
974
975 key->name = dns_pres_name_parse(hunks[0]);
976 if (key->name == NULL) {
977 ERROR("Invalid key name: %s", hunks[0]);
978 return false;
979 }
980
981 error = srp_base64_parse(hunks[6], &len, keybuf, sizeof keybuf);
982 if (error != 0) {
983 ERROR("Invalid HMAC-SHA256 key: %s", strerror(errno));
984 goto fail;
985 }
986
987 // The key should be 32 bytes (256 bits).
988 if (len == 0) {
989 ERROR("Invalid (null) secret for key %s", hunks[0]);
990 goto fail;
991 }
992 key->secret = malloc(len);
993 if (key->secret == NULL) {
994 ERROR("Unable to allocate space for secret for key %s", hunks[0]);
995 fail:
996 dns_name_free(key->name);
997 key->name = NULL;
998 return false;
999 }
1000 memcpy(key->secret, keybuf, len);
1001 key->length = len;
1002 key->algorithm = SRP_HMAC_TYPE_SHA256;
1003 return true;
1004 }
1005
1006 config_file_verb_t key_verbs[] = {
1007 { NULL, 7, 7, key_handler }
1008 };
1009 #define NUMKEYVERBS ((sizeof key_verbs) / sizeof (config_file_verb_t))
1010
1011 hmac_key_t *
1012 parse_hmac_key_file(const char *filename)
1013 {
1014 hmac_key_t *key = calloc(1, sizeof *key);
1015 if (key == NULL) {
1016 ERROR("No memory for tsig key structure.");
1017 return NULL;
1018 }
1019 if (!config_parse(key, filename, key_verbs, NUMKEYVERBS)) {
1020 ERROR("Failed to parse key file.");
1021 free(key);
1022 return NULL;
1023 }
1024 return key;
1025 }
1026
1027 int
1028 main(int argc, char **argv)
1029 {
1030 int i;
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;
1036 addr_t pref;
1037 uint16_t port;
1038 socklen_t len, prefalen;
1039 char *s, *p;
1040 int width;
1041 bool got_server = false;
1042
1043 // Read the configuration from the command line.
1044 for (i = 1; i < argc; i++) {
1045 if (!strcmp(argv[i], "-s")) {
1046 if (got_server) {
1047 ERROR("only one authoritative server can be specified.");
1048 return usage(argv[0]);
1049 }
1050 if (++i == argc) {
1051 ERROR("-s is missing dns server IP address.");
1052 return usage(argv[0]);
1053 }
1054 len = getipaddr(&dns_server, argv[i]);
1055 if (!len) {
1056 ERROR("Invalid IP address: %s.", argv[i]);
1057 return usage(argv[0]);
1058 }
1059 if (++i == argc) {
1060 ERROR("-s is missing dns server port.");
1061 return usage(argv[0]);
1062 }
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]);
1067 }
1068 if (dns_server.sa.sa_family == AF_INET) {
1069 dns_server.sin.sin_port = htons(port);
1070 } else {
1071 dns_server.sin6.sin6_port = htons(port);
1072 }
1073 got_server = true;
1074 } else if (!strcmp(argv[i], "-k")) {
1075 if (++i == argc) {
1076 ERROR("-k is missing key file name.");
1077 return usage(argv[0]);
1078 }
1079 key = parse_hmac_key_file(argv[i]);
1080 // Someething should already have printed the error message.
1081 if (key == NULL) {
1082 return 1;
1083 }
1084 } else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "-u")) {
1085 if (!strcmp(argv[i], "-u")) {
1086 if (++i == argc) {
1087 ERROR("-u is missing interface name.");
1088 return usage(argv[0]);
1089 }
1090 *up = calloc(1, sizeof **up);
1091 if (*up == NULL) {
1092 ERROR("udp_validators: out of memory.");
1093 return usage(argv[0]);
1094 }
1095 (*up)->ifname = strdup(argv[i]);
1096 if ((*up)->ifname == NULL) {
1097 ERROR("udp validators: ifname: out of memory.");
1098 return usage(argv[0]);
1099 }
1100 sp = &((*up)->subnets);
1101 } else {
1102 sp = nt;
1103 }
1104
1105 if (++i == argc) {
1106 ERROR("%s requires at least one prefix.", argv[i - 1]);
1107 return usage(argv[0]);
1108 }
1109 s = strchr(argv[i], '/');
1110 if (s == NULL) {
1111 ERROR("%s is not a prefix.", argv[i]);
1112 return usage(argv[0]);
1113 }
1114 *s = 0;
1115 ++s;
1116 prefalen = getipaddr(&pref, argv[i]);
1117 if (!prefalen) {
1118 ERROR("%s is not a valid prefix address.", argv[i]);
1119 return usage(argv[0]);
1120 }
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]);
1125 }
1126 if (width < 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]);
1132 }
1133
1134 *nt = calloc(1, sizeof **nt);
1135 if (!*nt) {
1136 ERROR("tcp_validators: out of memory.");
1137 return 1;
1138 }
1139
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);
1144 } else {
1145 memcpy((*nt)->bytes, &pref.sin6.sin6_addr, 8);
1146 }
1147
1148 // *up will be non-null for -u and null for -t.
1149 if (*up) {
1150 up = &((*up)->next);
1151 } else {
1152 nt = sp;
1153 }
1154 }
1155 }
1156 if (!got_server) {
1157 ERROR("No authoritative DNS server specified to take updates!");
1158 return 1;
1159 }
1160
1161 if (!ioloop_init()) {
1162 return 1;
1163 }
1164
1165 if (!srp_proxy_listen("home.arpa")) {
1166 return 1;
1167 }
1168
1169 // For now, hardcoded, should be configurable
1170 service_update_zone = dns_pres_name_parse("home.arpa");
1171
1172 do {
1173 int something = 0;
1174 something = ioloop_events(0);
1175 INFO("dispatched %d events.", something);
1176 } while (1);
1177 }
1178
1179 // Local Variables:
1180 // mode: C
1181 // tab-width: 4
1182 // c-file-style: "bsd"
1183 // c-basic-offset: 4
1184 // fill-column: 108
1185 // indent-tabs-mode: nil
1186 // End: