Home | History | Annotate | Line # | Download | only in ServiceRegistration
      1 /* dso-utils.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 
     18 #include <netinet/in.h>
     19 #include "dns-msg.h"
     20 #include "ioloop.h"
     21 #include "dso-utils.h"
     22 #include "dso.h"
     23 
     24 void
     25 dso_simple_response(comm_t *comm, message_t *message, const dns_wire_t *wire, int rcode)
     26 {
     27     struct iovec iov;
     28     dns_wire_t response;
     29     memset(&response, 0, DNS_HEADER_SIZE);
     30 
     31     // We take the ID and the opcode from the incoming message, because if the
     32     // header has been mangled, we (a) wouldn't have gotten here and (b) don't
     33     // have any better choice anyway.
     34     response.id = wire->id;
     35     dns_qr_set(&response, dns_qr_response);
     36     dns_opcode_set(&response, dns_opcode_get(wire));
     37     dns_rcode_set(&response, rcode);
     38 
     39     size_t length = DNS_HEADER_SIZE;
     40     uint16_t wire_length = message != NULL ? message->length : (uint16_t)sizeof(*wire);
     41     dns_rr_t question;
     42     memset(&question, 0, sizeof(question));
     43     unsigned offp = 0;
     44     if (ntohs(wire->qdcount) == 1 &&
     45         dns_rr_parse(&question, wire->data, wire_length - DNS_HEADER_SIZE, &offp, false, false))
     46     {
     47         dns_towire_state_t towire;
     48         memset(&towire, 0, sizeof(towire));
     49         towire.p = &response.data[0];
     50         towire.lim = ((uint8_t *)&response) + sizeof(response);
     51         towire.message = &response;
     52 
     53         size_t namelen = dns_name_to_wire_canonical(towire.p, towire.lim - towire.p, question.name);
     54         if (namelen != 0) {
     55             towire.p += namelen;
     56             dns_u16_to_wire(&towire, question.type);
     57             dns_u16_to_wire(&towire, question.qclass);
     58             if (!towire.truncated && !towire.error) {
     59                 response.qdcount = htons(1);
     60                 length += towire.p - (uint8_t *)&response.data[0];
     61             }
     62         }
     63         dns_name_free(question.name);
     64     }
     65     iov.iov_base = &response;
     66     iov.iov_len = length; // No RRs
     67     ioloop_send_message(comm, message, &iov, 1);
     68 }
     69 
     70 bool
     71 dso_send_simple_response(dso_state_t *dso, int rcode, const dns_wire_t *header, const char *UNUSED rcode_name)
     72 {
     73     dso_simple_response((comm_t *)dso->transport, NULL, header, rcode);
     74     return true;
     75 }
     76 
     77 bool
     78 dso_send_formerr(dso_state_t *dso, const dns_wire_t *header)
     79 {
     80     comm_t *transport = dso->transport;
     81     (void)header;
     82     dso_simple_response(transport, NULL, header, dns_rcode_formerr);
     83     return true;
     84 }
     85 
     86 void
     87 dso_retry_delay_response(comm_t *comm, message_t *message, const dns_wire_t *wire, int rcode, uint32_t milliseconds)
     88 {
     89     dns_wire_t response;
     90     dns_towire_state_t towire;
     91     struct iovec iov;
     92     memset(&response, 0, DNS_HEADER_SIZE);
     93     memset(&towire, 0, sizeof(towire));
     94 
     95     towire.p = &response.data[0];  // We start storing RR data here.
     96     towire.lim = ((uint8_t *)&response) + sizeof(response);
     97     towire.message = &response;
     98     towire.p_rdlength = NULL;
     99     towire.p_opt = NULL;
    100 
    101     response.id = wire->id;
    102     dns_qr_set(&response, dns_qr_response);
    103     dns_opcode_set(&response, dns_opcode_get(wire));
    104     dns_rcode_set(&response, rcode);
    105 
    106     dns_u16_to_wire(&towire, kDSOType_RetryDelay);
    107     // This shouldn't be possible.
    108     if (towire.p + 2 > towire.lim) {
    109         FAULT("No room for dso length in Retry Delay message.");
    110         return;
    111     }
    112     uint8_t *p_dso_length = towire.p;
    113     towire.p += 2;
    114 
    115     dns_u32_to_wire(&towire, milliseconds);
    116 
    117     int16_t dso_length = towire.p - p_dso_length - 2;
    118     iov.iov_len = (towire.p - (uint8_t *)&response);
    119     iov.iov_base = &response;
    120 
    121     towire.p = p_dso_length;
    122     dns_u16_to_wire(&towire, dso_length);
    123     ioloop_send_message(comm, message, &iov, 1);
    124 }
    125 
    126 int32_t
    127 dso_transport_idle(void * UNUSED context, int32_t UNUSED now, int32_t next_event)
    128 {
    129     return next_event;
    130 }
    131 
    132 // Local Variables:
    133 // mode: C
    134 // tab-width: 4
    135 // c-file-style: "bsd"
    136 // c-basic-offset: 4
    137 // fill-column: 108
    138 // indent-tabs-mode: nil
    139 // End:
    140