]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/srp-parse.c
mDNSResponder-1310.60.4.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / srp-parse.c
1 /* srp-parse.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 file contains support routines for the DNSSD SRP update and mDNS proxies.
18 */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <fcntl.h>
29 #include <sys/time.h>
30 #include <dns_sd.h>
31
32 #include "srp.h"
33 #include "dns-msg.h"
34 #include "srp-crypto.h"
35 #include "ioloop.h"
36 #include "dnssd-proxy.h"
37 #include "srp-gw.h"
38 #include "config-parse.h"
39 #include "srp-proxy.h"
40
41 static dns_name_t *service_update_zone; // The zone to update when we receive an update for default.service.arpa.
42
43 // Free the data structures into which the SRP update was parsed. The pointers to the various DNS objects that these
44 // structures point to are owned by the parsed DNS message, and so these do not need to be freed here.
45 void
46 srp_update_free_parts(service_instance_t *service_instances, service_instance_t *added_instances,
47 service_t *services, dns_host_description_t *host_description)
48 {
49 service_instance_t *sip;
50 service_t *sp;
51
52 for (sip = service_instances; sip; ) {
53 service_instance_t *next = sip->next;
54 free(sip);
55 sip = next;
56 }
57 for (sip = added_instances; sip; ) {
58 service_instance_t *next = sip->next;
59 free(sip);
60 sip = next;
61 }
62 for (sp = services; sp; ) {
63 service_t *next = sp->next;
64 free(sp);
65 sp = next;
66 }
67 if (host_description != NULL) {
68 host_addr_t *host_addr, *next;
69 for (host_addr = host_description->addrs; host_addr; host_addr = next) {
70 next = host_addr->next;
71 free(host_addr);
72 }
73 free(host_description);
74 }
75 }
76
77 static bool
78 add_host_addr(host_addr_t **dest, dns_rr_t *rr)
79 {
80 host_addr_t *addr = calloc(1, sizeof *addr);
81 if (addr == NULL) {
82 ERROR("add_host_addr: no memory for record");
83 return false;
84 }
85
86 while (*dest) {
87 dest = &(*dest)->next;
88 }
89 *dest = addr;
90 addr->rr = *rr;
91 return true;
92 }
93
94 static bool
95 replace_zone_name(dns_name_t **nzp_in, dns_name_t *uzp, dns_name_t *replacement_zone)
96 {
97 dns_name_t **nzp = nzp_in;
98 while (*nzp != NULL && *nzp != uzp) {
99 nzp = &((*nzp)->next);
100 }
101 if (*nzp == NULL) {
102 ERROR("replace_zone: dns_name_subdomain_of returned bogus pointer.");
103 return false;
104 }
105
106 // Free the suffix we're replacing
107 dns_name_free(*nzp);
108
109 // Replace it.
110 *nzp = dns_name_copy(replacement_zone);
111 if (*nzp == NULL) {
112 ERROR("replace_zone_name: no memory for replacement zone");
113 return false;
114 }
115 return true;
116 }
117
118 // We call advertise_finished when a client request has finished, successfully or otherwise.
119 static void
120 send_fail_response(comm_t *connection, message_t *message, int rcode)
121 {
122 struct iovec iov;
123 dns_wire_t response;
124
125 memset(&response, 0, DNS_HEADER_SIZE);
126 response.id = message->wire.id;
127 response.bitfield = message->wire.bitfield;
128 dns_rcode_set(&response, rcode);
129 dns_qr_set(&response, dns_qr_response);
130
131 iov.iov_base = &response;
132 iov.iov_len = DNS_HEADER_SIZE;
133
134 ioloop_send_message(connection, message, &iov, 1);
135 }
136
137 bool
138 srp_evaluate(comm_t *connection, dns_message_t *message, message_t *raw_message)
139 {
140 int i;
141 dns_host_description_t *host_description = NULL;
142 delete_t *deletes = NULL, *dp, **dpp = &deletes;
143 service_instance_t *service_instances = NULL, *sip, **sipp = &service_instances;
144 service_t *services = NULL, *sp, **spp = &services;
145 dns_rr_t *signature;
146 bool ret = false;
147 struct timeval now;
148 dns_name_t *update_zone, *replacement_zone;
149 dns_name_t *uzp;
150 dns_rr_t *key = NULL;
151 dns_rr_t **keys = NULL;
152 int num_keys = 0;
153 int max_keys = 1;
154 bool found_key = false;
155 uint32_t lease_time, key_lease_time;
156 dns_edns0_t *edns0;
157 int rcode = dns_rcode_servfail;
158 bool found_lease = false;
159
160 // Update requires a single SOA record as the question
161 if (message->qdcount != 1) {
162 ERROR("srp_evaluate: update received with qdcount > 1");
163 return false;
164 }
165
166 // Update should contain zero answers.
167 if (message->ancount != 0) {
168 ERROR("srp_evaluate: update received with ancount > 0");
169 return false;
170 }
171
172 if (message->questions[0].type != dns_rrtype_soa) {
173 ERROR("srp_evaluate: update received with rrtype %d instead of SOA in question section.",
174 message->questions[0].type);
175 return false;
176 }
177
178 update_zone = message->questions[0].name;
179 if (service_update_zone != NULL && dns_names_equal_text(update_zone, "default.service.arpa.")) {
180 replacement_zone = service_update_zone;
181 } else {
182 replacement_zone = NULL;
183 }
184
185 // Scan over the authority RRs; do the delete consistency check. We can't do other consistency checks
186 // because we can't assume a particular order to the records other than that deletes have to come before
187 // adds.
188 for (i = 0; i < message->nscount; i++) {
189 dns_rr_t *rr = &message->authority[i];
190
191 // If this is a delete for all the RRs on a name, record it in the list of deletes.
192 if (rr->type == dns_rrtype_any && rr->qclass == dns_qclass_any && rr->ttl == 0) {
193 for (dp = deletes; dp; dp = dp->next) {
194 if (dns_names_equal(dp->name, rr->name)) {
195 DNS_NAME_GEN_SRP(rr->name, name_buf);
196 ERROR("srp_evaluate: two deletes for the same name: " PRI_DNS_NAME_SRP,
197 DNS_NAME_PARAM_SRP(rr->name, name_buf));
198 rcode = dns_rcode_formerr;
199 goto out;
200 }
201 }
202 dp = calloc(1, sizeof *dp);
203 if (!dp) {
204 ERROR("srp_evaluate: no memory.");
205 goto out;
206 }
207 *dpp = dp;
208 dpp = &dp->next;
209
210 // Make sure the name is a subdomain of the zone being updated.
211 dp->zone = dns_name_subdomain_of(rr->name, update_zone);
212 if (dp->zone == NULL) {
213 DNS_NAME_GEN_SRP(update_zone, update_zone_buf);
214 DNS_NAME_GEN_SRP(rr->name, name_buf);
215 ERROR("srp_evaluate: delete for record not in update zone " PRI_DNS_NAME_SRP ": " PRI_DNS_NAME_SRP,
216 DNS_NAME_PARAM_SRP(update_zone, update_zone_buf), DNS_NAME_PARAM_SRP(rr->name, name_buf));
217 rcode = dns_rcode_formerr;
218 goto out;
219 }
220 dp->name = rr->name;
221 }
222
223 // The update should really only contain one key, but it's allowed for keys to appear on
224 // service instance names as well, since that's what will be stored in the zone. So if
225 // we get one key, we'll assume it's a host key until we're done scanning, and then check.
226 // If we get more than one, we allocate a buffer and store all the keys so that we can
227 // check them all later.
228 else if (rr->type == dns_rrtype_key) {
229 if (num_keys < 1) {
230 key = rr;
231 num_keys++;
232 } else {
233 if (num_keys == 1) {
234 // We can't have more keys than there are authority records left, plus
235 // one for the key we already have, so allocate a buffer that large.
236 max_keys = message->nscount - i + 1;
237 keys = calloc(max_keys, sizeof *keys);
238 if (keys == NULL) {
239 ERROR("srp_evaluate: no memory");
240 goto out;
241 }
242 keys[0] = key;
243 }
244 if (num_keys >= max_keys) {
245 ERROR("srp_evaluate: coding error in key allocation");
246 goto out;
247 }
248 keys[num_keys++] = rr;
249 }
250 }
251
252 // Otherwise if it's an A or AAAA record, it's part of a hostname entry.
253 else if (rr->type == dns_rrtype_a || rr->type == dns_rrtype_aaaa) {
254 // Allocate the hostname record
255 if (!host_description) {
256 host_description = calloc(1, sizeof *host_description);
257 if (!host_description) {
258 ERROR("srp_evaluate: no memory");
259 goto out;
260 }
261 }
262
263 // Make sure it's preceded by a deletion of all the RRs on the name.
264 if (!host_description->delete) {
265 for (dp = deletes; dp; dp = dp->next) {
266 if (dns_names_equal(dp->name, rr->name)) {
267 break;
268 }
269 }
270 if (dp == NULL) {
271 DNS_NAME_GEN_SRP(rr->name, name_buf);
272 ERROR("srp_evaluate: ADD for hostname " PRI_DNS_NAME_SRP " without a preceding delete.",
273 DNS_NAME_PARAM_SRP(rr->name, name_buf));
274 rcode = dns_rcode_formerr;
275 goto out;
276 }
277 host_description->delete = dp;
278 host_description->name = dp->name;
279 dp->consumed = true; // This delete is accounted for.
280
281 // In principle, we should be checking this name to see that it's a subdomain of the update
282 // zone. However, it turns out we don't need to, because the /delete/ has to be a subdomain
283 // of the update zone, and we won't find that delete if it's not present.
284 }
285
286 if (rr->type == dns_rrtype_a || rr->type == dns_rrtype_aaaa) {
287 if (!add_host_addr(&host_description->addrs, rr)) {
288 goto out;
289 }
290 }
291 }
292
293 // Otherwise if it's an SRV entry, that should be a service instance name.
294 else if (rr->type == dns_rrtype_srv || rr->type == dns_rrtype_txt) {
295 // Should be a delete that precedes this service instance.
296 for (dp = deletes; dp; dp = dp->next) {
297 if (dns_names_equal(dp->name, rr->name)) {
298 break;
299 }
300 }
301 if (dp == NULL) {
302 DNS_NAME_GEN_SRP(rr->name, name_buf);
303 ERROR("srp_evaluate: ADD for service instance not preceded by delete: " PRI_DNS_NAME_SRP,
304 DNS_NAME_PARAM_SRP(rr->name, name_buf));
305 rcode = dns_rcode_formerr;
306 goto out;
307 }
308 for (sip = service_instances; sip; sip = sip->next) {
309 if (dns_names_equal(sip->name, rr->name)) {
310 break;
311 }
312 }
313 if (!sip) {
314 sip = calloc(1, sizeof *sip);
315 if (sip == NULL) {
316 ERROR("srp_evaluate: no memory");
317 goto out;
318 }
319 sip->delete = dp;
320 dp->consumed = true;
321 sip->name = dp->name;
322 *sipp = sip;
323 sipp = &sip->next;
324 }
325 if (rr->type == dns_rrtype_srv) {
326 if (sip->srv != NULL) {
327 DNS_NAME_GEN_SRP(rr->name, name_buf);
328 ERROR("srp_evaluate: more than one SRV rr received for service instance: " PRI_DNS_NAME_SRP,
329 DNS_NAME_PARAM_SRP(rr->name, name_buf));
330 rcode = dns_rcode_formerr;
331 goto out;
332 }
333 sip->srv = rr;
334 } else if (rr->type == dns_rrtype_txt) {
335 if (sip->txt != NULL) {
336 DNS_NAME_GEN_SRP(rr->name, name_buf);
337 ERROR("srp_evaluate: more than one TXT rr received for service instance: " PRI_DNS_NAME_SRP,
338 DNS_NAME_PARAM_SRP(rr->name, name_buf));
339 rcode = dns_rcode_formerr;
340 goto out;
341 }
342 sip->txt = rr;
343 }
344 }
345
346 // Otherwise if it's a PTR entry, that should be a service name
347 else if (rr->type == dns_rrtype_ptr) {
348 sp = calloc(1, sizeof *sp);
349 if (sp == NULL) {
350 ERROR("srp_evaluate: no memory");
351 goto out;
352 }
353 *spp = sp;
354 spp = &sp->next;
355 sp->rr = rr;
356
357 // Make sure the service name is in the update zone.
358 sp->zone = dns_name_subdomain_of(sp->rr->name, update_zone);
359 if (sp->zone == NULL) {
360 DNS_NAME_GEN_SRP(rr->name, name_buf);
361 DNS_NAME_GEN_SRP(rr->data.ptr.name, data_name_buf);
362 ERROR("srp_evaluate: service name " PRI_DNS_NAME_SRP " for " PRI_DNS_NAME_SRP
363 " is not in the update zone", DNS_NAME_PARAM_SRP(rr->name, name_buf),
364 DNS_NAME_PARAM_SRP(rr->data.ptr.name, data_name_buf));
365 rcode = dns_rcode_formerr;
366 goto out;
367 }
368 }
369
370 // Otherwise it's not a valid update
371 else {
372 DNS_NAME_GEN_SRP(rr->name, name_buf);
373 ERROR("srp_evaluate: unexpected rrtype %d on " PRI_DNS_NAME_SRP " in update.", rr->type,
374 DNS_NAME_PARAM_SRP(rr->name, name_buf));
375 rcode = dns_rcode_formerr;
376 goto out;
377 }
378 }
379
380 // Now that we've scanned the whole update, do the consistency checks for updates that might
381 // not have come in order.
382
383 // First, make sure there's a host description.
384 if (host_description == NULL) {
385 ERROR("srp_evaluate: SRP update does not include a host description.");
386 rcode = dns_rcode_formerr;
387 goto out;
388 }
389
390 // Make sure that each service add references a service instance that's in the same update.
391 for (sp = services; sp; sp = sp->next) {
392 for (sip = service_instances; sip; sip = sip->next) {
393 if (dns_names_equal(sip->name, sp->rr->data.ptr.name)) {
394 // Note that we have already verified that there is only one service instance
395 // with this name, so this could only ever happen once in this loop even without
396 // the break statement.
397 sip->service = sp;
398 sip->num_instances++;
399 break;
400 }
401 }
402 // If this service doesn't point to a service instance that's in the update, then the
403 // update fails validation.
404 if (sip == NULL) {
405 DNS_NAME_GEN_SRP(sp->rr->name, name_buf);
406 ERROR("srp_evaluate: service points to an instance that's not included: " PRI_DNS_NAME_SRP,
407 DNS_NAME_PARAM_SRP(sp->rr->name, name_buf));
408 rcode = dns_rcode_formerr;
409 goto out;
410 }
411 }
412
413 for (sip = service_instances; sip; sip = sip->next) {
414 // For each service instance, make sure that at least one service references it
415 if (sip->num_instances == 0) {
416 DNS_NAME_GEN_SRP(sip->name, name_buf);
417 ERROR("srp_evaluate: service instance update for " PRI_DNS_NAME_SRP
418 " is not referenced by a service update.", DNS_NAME_PARAM_SRP(sip->name, name_buf));
419 rcode = dns_rcode_formerr;
420 goto out;
421 }
422
423 // For each service instance, make sure that it references the host description
424 if (dns_names_equal(host_description->name, sip->srv->data.srv.name)) {
425 sip->host = host_description;
426 host_description->num_instances++;
427 }
428 }
429
430 // Make sure that at least one service instance references the host description
431 if (host_description->num_instances == 0) {
432 DNS_NAME_GEN_SRP(host_description->name, name_buf);
433 ERROR("srp_evaluate: host description " PRI_DNS_NAME_SRP " is not referenced by any service instances.",
434 DNS_NAME_PARAM_SRP(host_description->name, name_buf));
435 rcode = dns_rcode_formerr;
436 goto out;
437 }
438
439 // Make sure the host description has at least one address record.
440 if (host_description->addrs == NULL) {
441 DNS_NAME_GEN_SRP(host_description->name, name_buf);
442 ERROR("srp_evaluate: host description " PRI_DNS_NAME_SRP " doesn't contain any IP addresses.",
443 DNS_NAME_PARAM_SRP(host_description->name, name_buf));
444 rcode = dns_rcode_formerr;
445 goto out;
446 }
447
448 for (i = 0; i < num_keys; i++) {
449 // If this isn't the only key, make sure it's got the same contents as the other keys.
450 if (i > 0) {
451 if (!dns_keys_rdata_equal(key, keys[i])) {
452 ERROR("srp_evaluate: more than one key presented");
453 rcode = dns_rcode_formerr;
454 goto out;
455 }
456 // This is a hack so that if num_keys == 1, we don't have to allocate keys[].
457 // At the bottom of this if statement, key is always the key we are looking at.
458 key = keys[i];
459 }
460 // If there is a key, and the host description doesn't currently have a key, check
461 // there first since that's the default.
462 if (host_description->key == NULL && dns_names_equal(key->name, host_description->name)) {
463 host_description->key = key;
464 found_key = true;
465 } else {
466 for (sip = service_instances; sip != NULL; sip = sip->next) {
467 if (dns_names_equal(sip->name, key->name)) {
468 found_key = true;
469 break;
470 }
471 }
472 }
473 if (!found_key) {
474 DNS_NAME_GEN_SRP(key->name, key_name_buf);
475 ERROR("srp_evaluate: key present for name " PRI_DNS_NAME_SRP
476 " which is neither a host nor an instance name.", DNS_NAME_PARAM_SRP(key->name, key_name_buf));
477 rcode = dns_rcode_formerr;
478 goto out;
479 }
480 }
481 if (keys != NULL) {
482 free(keys);
483 keys = NULL;
484 }
485
486 // And make sure it has a key record
487 if (host_description->key == NULL) {
488 DNS_NAME_GEN_SRP(host_description->name, host_name_buf);
489 ERROR("srp_evaluate: host description " PRI_DNS_NAME_SRP " doesn't contain a key.",
490 DNS_NAME_PARAM_SRP(host_description->name, host_name_buf));
491 rcode = dns_rcode_formerr;
492 goto out;
493 }
494
495 // Make sure that all the deletes are for things that are then added.
496 for (dp = deletes; dp; dp = dp->next) {
497 if (!dp->consumed) {
498 DNS_NAME_GEN_SRP(host_description->name, host_name_buf);
499 ERROR("srp_evaluate: delete for which there is no subsequent add: " PRI_DNS_NAME_SRP,
500 DNS_NAME_PARAM_SRP(host_description->name, host_name_buf));
501 rcode = dns_rcode_formerr;
502 goto out;
503 }
504 }
505
506 // The signature should be the last thing in the additional section. Even if the signature
507 // is valid, if it's not at the end we reject it. Note that we are just checking for SIG(0)
508 // so if we don't find what we're looking for, we forward it to the DNS auth server which
509 // will either accept or reject it.
510 if (message->arcount < 1) {
511 ERROR("srp_evaluate: signature not present");
512 rcode = dns_rcode_formerr;
513 goto out;
514 }
515 signature = &message->additional[message->arcount -1];
516 if (signature->type != dns_rrtype_sig) {
517 ERROR("srp_evaluate: signature is not at the end or is not present");
518 rcode = dns_rcode_formerr;
519 goto out;
520 }
521
522 // Make sure that the signer name is the hostname. If it's not, it could be a legitimate
523 // update with a different key, but it's not an SRP update, so we pass it on.
524 if (!dns_names_equal(signature->data.sig.signer, host_description->name)) {
525 DNS_NAME_GEN_SRP(signature->data.sig.signer, signer_name_buf);
526 DNS_NAME_GEN_SRP(host_description->name, host_name_buf);
527 ERROR("srp_evaluate: signer " PRI_DNS_NAME_SRP " doesn't match host " PRI_DNS_NAME_SRP,
528 DNS_NAME_PARAM_SRP(signature->data.sig.signer, signer_name_buf),
529 DNS_NAME_PARAM_SRP(host_description->name, host_name_buf));
530 rcode = dns_rcode_formerr;
531 goto out;
532 }
533
534 // Make sure we're in the time limit for the signature. Zeroes for the inception and expiry times
535 // mean the host that send this doesn't have a working clock. One being zero and the other not isn't
536 // valid unless it's 1970.
537 if (signature->data.sig.inception != 0 || signature->data.sig.expiry != 0) {
538 gettimeofday(&now, NULL);
539 // The sender does the bracketing, so we can just do a simple comparison.
540 if ((uint32_t)(now.tv_sec & UINT32_MAX) > signature->data.sig.expiry ||
541 (uint32_t)(now.tv_sec & UINT32_MAX) < signature->data.sig.inception) {
542 ERROR("signature is not timely: %lu < %lu < %lu does not hold",
543 (unsigned long)signature->data.sig.inception, (unsigned long)now.tv_sec,
544 (unsigned long)signature->data.sig.expiry);
545 goto badsig;
546 }
547 }
548
549 // Now that we have the key, we can validate the signature. If the signature doesn't validate,
550 // there is no need to pass the message on.
551 if (!srp_sig0_verify(&raw_message->wire, host_description->key, signature)) {
552 ERROR("signature is not valid");
553 goto badsig;
554 }
555
556 // Now that we have validated the SRP message, go through and fix up all instances of
557 // *default.service.arpa to use the replacement zone, if this update is for
558 // default.services.arpa and there is a replacement zone.
559 if (replacement_zone != NULL) {
560 // All of the service instances and the host use the name from the delete, so if
561 // we update these, the names for those are taken care of. We already found the
562 // zone for which the delete is a subdomain, so we can just replace it without
563 // finding it again.
564 for (dp = deletes; dp; dp = dp->next) {
565 replace_zone_name(&dp->name, dp->zone, replacement_zone);
566 }
567
568 // All services have PTR records, which point to names. Both the service name and the
569 // PTR name have to be fixed up.
570 for (sp = services; sp; sp = sp->next) {
571 replace_zone_name(&sp->rr->name, sp->zone, replacement_zone);
572 uzp = dns_name_subdomain_of(sp->rr->data.ptr.name, update_zone);
573 // We already validated that the PTR record points to something in the zone, so this
574 // if condition should always be false.
575 if (uzp == NULL) {
576 ERROR("srp_evaluate: service PTR record zone match fail!!");
577 goto out;
578 }
579 replace_zone_name(&sp->rr->data.ptr.name, uzp, replacement_zone);
580 }
581
582 // All service instances have SRV records, which point to names. The service instance
583 // name is already fixed up, because it's the same as the delete, but the name in the
584 // SRV record must also be fixed.
585 for (sip = service_instances; sip; sip = sip->next) {
586 uzp = dns_name_subdomain_of(sip->srv->data.srv.name, update_zone);
587 // We already validated that the SRV record points to something in the zone, so this
588 // if condition should always be false.
589 if (uzp == NULL) {
590 ERROR("srp_evaluate: service instance SRV record zone match fail!!");
591 goto out;
592 }
593 replace_zone_name(&sip->srv->data.srv.name, uzp, replacement_zone);
594 }
595
596 // We shouldn't need to replace the hostname zone because it's actually pointing to
597 // the name of a delete.
598 }
599
600 // Get the lease time.
601 lease_time = 3600;
602 key_lease_time = 604800;
603 for (edns0 = message->edns0; edns0; edns0 = edns0->next) {
604 if (edns0->type == dns_opt_update_lease) {
605 unsigned off = 0;
606 if (edns0->length != 4 && edns0->length != 8) {
607 ERROR("srp_evaluate: edns0 update-lease option length bogus: %d", edns0->length);
608 rcode = dns_rcode_formerr;
609 goto out;
610 }
611 dns_u32_parse(edns0->data, edns0->length, &off, &lease_time);
612 if (edns0->length == 8) {
613 dns_u32_parse(edns0->data, edns0->length, &off, &key_lease_time);
614 } else {
615 key_lease_time = 7 * lease_time;
616 }
617 found_lease = true;
618 break;
619 }
620 }
621
622 // Start the update.
623 DNS_NAME_GEN_SRP(host_description->name, host_description_name_buf);
624 INFO("srp_evaluate: update for " PRI_DNS_NAME_SRP " xid %x validates.",
625 DNS_NAME_PARAM_SRP(host_description->name, host_description_name_buf), raw_message->wire.id);
626 rcode = dns_rcode_noerror;
627 ret = srp_update_start(connection, message, raw_message, host_description, service_instances, services,
628 replacement_zone == NULL ? update_zone : replacement_zone,
629 lease_time, key_lease_time);
630 if (ret) {
631 goto success;
632 }
633 ERROR("update start failed");
634 goto out;
635
636 badsig:
637 // True means it was intended for us, and shouldn't be forwarded.
638 ret = true;
639 // We're not actually going to return this; it simply indicates that we aren't sending a fail response.
640 rcode = dns_rcode_noerror;
641 // Because we're saying this is ours, we have to free the parsed message.
642 dns_message_free(message);
643
644 out:
645 // free everything we allocated but (it turns out) aren't going to use
646 if (keys != NULL) {
647 free(keys);
648 }
649 srp_update_free_parts(service_instances, NULL, services, host_description);
650
651 success:
652 // No matter how we get out of this, we free the delete structures, because they are not
653 // used to do the update.
654 for (dp = deletes; dp; ) {
655 delete_t *next = dp->next;
656 free(dp);
657 dp = next;
658 }
659
660 if (ret == true && rcode != dns_rcode_noerror) {
661 send_fail_response(connection, raw_message, rcode);
662 }
663 return ret;
664 }
665
666 static void
667 dns_evaluate(comm_t *connection, message_t *message)
668 {
669 dns_message_t *parsed_message;
670
671 // Drop incoming responses--we're a server, so we only accept queries.
672 if (dns_qr_get(&message->wire) == dns_qr_response) {
673 ERROR("dns_evaluate: received a message that was a DNS response: %d", dns_opcode_get(&message->wire));
674 return;
675 }
676
677 // Forward incoming messages that are queries but not updates.
678 // XXX do this later--for now we operate only as a translator, not a proxy.
679 if (dns_opcode_get(&message->wire) != dns_opcode_update) {
680 send_fail_response(connection, message, dns_rcode_refused);
681 ERROR("dns_evaluate: received a message that was not a DNS update: %d", dns_opcode_get(&message->wire));
682 return;
683 }
684
685 // Parse the UPDATE message.
686 if (!dns_wire_parse(&parsed_message, &message->wire, message->length)) {
687 send_fail_response(connection, message, dns_rcode_servfail);
688 ERROR("dns_wire_parse failed.");
689 return;
690 }
691
692 // We need the wire message to validate the signature...
693 if (!srp_evaluate(connection, parsed_message, message)) {
694 // The message wasn't invalid, but wasn't an SRP message.
695 dns_message_free(parsed_message);
696 // dns_forward(connection)
697 send_fail_response(connection, message, dns_rcode_refused);
698 }
699 }
700
701 void
702 dns_input(comm_t *comm, message_t *message, void *context)
703 {
704 (void)context;
705 dns_evaluate(comm, message);
706 }
707
708 struct srp_proxy_listener_state {
709 comm_t *NULLABLE tcp_listener;
710 comm_t *NULLABLE tls_listener;
711 comm_t *NULLABLE udp_listener;
712 };
713
714 void
715 srp_proxy_listener_cancel(srp_proxy_listener_state_t *listener_state)
716 {
717 if (listener_state->tcp_listener != NULL) {
718 ioloop_listener_cancel(listener_state->tcp_listener);
719 ioloop_listener_release(listener_state->tcp_listener);
720 }
721 if (listener_state->tls_listener != NULL) {
722 ioloop_listener_cancel(listener_state->tls_listener);
723 ioloop_listener_release(listener_state->tls_listener);
724 }
725 if (listener_state->udp_listener != NULL) {
726 ioloop_listener_cancel(listener_state->udp_listener);
727 ioloop_listener_release(listener_state->udp_listener);
728 }
729 free(listener_state);
730 }
731
732 srp_proxy_listener_state_t *
733 srp_proxy_listen(const char *update_zone, uint16_t *avoid_ports, int num_avoid_ports, ready_callback_t ready)
734 {
735 #if SRP_STREAM_LISTENER_ENABLED
736 uint16_t tcp_listen_port;
737 #ifndef EXCLUDE_TLS
738 uint16_t tls_listen_port;
739 #endif
740 #endif
741 srp_proxy_listener_state_t *listeners = calloc(1, sizeof *listeners);
742 if (listeners == NULL) {
743 ERROR("srp_proxy_listen: no memory for listeners structure.");
744 return NULL;
745 }
746 (void)avoid_ports;
747 (void)num_avoid_ports;
748
749 #if SRP_STREAM_LISTENER_ENABLED
750 tcp_listen_port = 53;
751 tls_listen_port = 853;
752 #endif
753
754 // Set up listeners
755 // XXX UDP listeners should bind to interface addresses, not INADDR_ANY.
756 listeners->udp_listener = ioloop_listener_create(false, false, avoid_ports,
757 num_avoid_ports, NULL, NULL, "UDP listener", dns_input,
758 NULL, NULL, ready, NULL, NULL);
759 if (listeners->udp_listener == NULL) {
760 srp_proxy_listener_cancel(listeners);
761 ERROR("UDP listener: fail.");
762 return 0;
763 }
764 #ifdef SRP_STREAM_LISTENER_ENABLED
765 listeners->tcp_listener = ioloop_listener_create(true, false, NULL, 0, NULL, NULL,
766 "TCP listener", dns_input, NULL, NULL, ready, NULL, NULL);
767 if (listeners->tcp_listener == NULL) {
768 srp_proxy_listener_cancel(listeners);
769 ERROR("TCP listener: fail.");
770 return 0;
771 }
772 #ifndef EXCLUDE_TLS
773 listeners->tls_listener = ioloop_listener_create(true, true, NULL, 0, NULL, NULL,
774 "TLS listener", dns_input, NULL, NULL, ready, NULL, NULL);
775 if (listeners->tls_listener == NULL) {
776 srp_proxy_listener_cancel(listeners);
777 ERROR("TLS listener: fail.");
778 return 0;
779 }
780 #endif
781 #endif
782
783 // For now, hardcoded, should be configurable
784 if (service_update_zone != NULL) {
785 dns_name_free(service_update_zone);
786 }
787 service_update_zone = dns_pres_name_parse(update_zone);
788
789 return listeners;
790 }
791
792 // Local Variables:
793 // mode: C
794 // tab-width: 4
795 // c-file-style: "bsd"
796 // c-basic-offset: 4
797 // fill-column: 108
798 // indent-tabs-mode: nil
799 // End: