1 /* srp-parse.c
2  *
3  * Copyright (c) 2018-2020 Apple 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
srp_update_free_parts(service_instance_t * service_instances,service_instance_t * added_instances,service_t * services,dns_host_description_t * host_description)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
add_host_addr(host_addr_t ** dest,dns_rr_t * rr)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
replace_zone_name(dns_name_t ** nzp_in,dns_name_t * uzp,dns_name_t * replacement_zone)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
send_fail_response(comm_t * connection,message_t * message,int rcode)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
srp_evaluate(comm_t * connection,dns_message_t * message,message_t * raw_message)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
dns_evaluate(comm_t * connection,message_t * message)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
dns_input(comm_t * comm,message_t * message,void * context)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
srp_proxy_listener_cancel(srp_proxy_listener_state_t * listener_state)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     }
720     if (listener_state->tls_listener != NULL) {
721         ioloop_listener_cancel(listener_state->tls_listener);
722     }
723     if (listener_state->udp_listener != NULL) {
724         ioloop_listener_cancel(listener_state->udp_listener);
725     }
726     free(listener_state);
727 }
728 
729 srp_proxy_listener_state_t *
srp_proxy_listen(const char * update_zone,uint16_t * avoid_ports,int num_avoid_ports,ready_callback_t ready)730 srp_proxy_listen(const char *update_zone, uint16_t *avoid_ports, int num_avoid_ports, ready_callback_t ready)
731 {
732 #if SRP_STREAM_LISTENER_ENABLED
733     uint16_t tcp_listen_port;
734 #ifndef EXCLUDE_TLS
735     uint16_t tls_listen_port;
736 #endif
737 #endif
738     srp_proxy_listener_state_t *listeners = calloc(1, sizeof *listeners);
739     if (listeners == NULL) {
740         ERROR("srp_proxy_listen: no memory for listeners structure.");
741         return NULL;
742     }
743     (void)avoid_ports;
744     (void)num_avoid_ports;
745 
746 #if SRP_STREAM_LISTENER_ENABLED
747     tcp_listen_port = 53;
748     tls_listen_port = 853;
749 #endif
750 
751     // Set up listeners
752     // XXX UDP listeners should bind to interface addresses, not INADDR_ANY.
753     listeners->udp_listener = ioloop_listener_create(false, false, avoid_ports,
754                                                      num_avoid_ports, NULL, NULL, "UDP listener", dns_input,
755                                                      NULL, NULL, ready, NULL, NULL);
756     if (listeners->udp_listener == NULL) {
757         srp_proxy_listener_cancel(listeners);
758         ERROR("UDP listener: fail.");
759         return 0;
760     }
761 #ifdef SRP_STREAM_LISTENER_ENABLED
762     listeners->tcp_listener = ioloop_listener_create(true, false, NULL, 0, NULL, NULL,
763                                                      "TCP listener", dns_input, NULL, NULL, ready, NULL, NULL);
764     if (listeners->tcp_listener == NULL) {
765         srp_proxy_listener_cancel(listeners);
766         ERROR("TCP listener: fail.");
767         return 0;
768     }
769 #ifndef EXCLUDE_TLS
770     listeners->tls_listener = ioloop_listener_create(true, true, NULL, 0, NULL, NULL,
771                                                      "TLS listener", dns_input, NULL, NULL, ready, NULL, NULL);
772     if (listeners->tls_listener == NULL) {
773         srp_proxy_listener_cancel(listeners);
774         ERROR("TLS listener: fail.");
775         return 0;
776     }
777 #endif
778 #endif
779 
780     // For now, hardcoded, should be configurable
781     if (service_update_zone != NULL) {
782         dns_name_free(service_update_zone);
783     }
784     service_update_zone = dns_pres_name_parse(update_zone);
785 
786     return listeners;
787 }
788 
789 // Local Variables:
790 // mode: C
791 // tab-width: 4
792 // c-file-style: "bsd"
793 // c-basic-offset: 4
794 // fill-column: 108
795 // indent-tabs-mode: nil
796 // End:
797