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