Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1 /* srp-dns-proxy.c
      2  *
      3  * Copyright (c) 2018-2021 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  *     https://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, false)) {
    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:
   1187