1 /* dso.h 2 * 3 * Copyright (c) 2018-2023 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 19 #ifndef __DSO_H 20 #define __DSO_H 21 22 #include <stdbool.h> 23 #include <stdint.h> 24 #include "nullability.h" 25 26 // Maximum number of additional TLVs we support in a DSO message. 27 #define MAX_ADDITLS 2 28 29 // Use 0 to represent an invalid ID for the object dso_connect_t. 30 #define DSO_STATE_INVALID_SERIAL 0 31 32 typedef enum { 33 // When we get a DSO query or response with no primary TLV, the TLV type will be "No Primary TLV," which is not 34 // otherwise a valid DSO TLV type. 35 kDSOType_NoPrimaryTLV = 0, 36 // Standard DSO Types from RFC 8490 37 kDSOType_Keepalive = 1, 38 kDSOType_RetryDelay = 2, 39 kDSOType_EncryptionPadding = 3, 40 41 // Standard DSO Types from RFC 8765 42 kDSOType_DNSPushSubscribe = 0x40, 43 kDSOType_DNSPushUpdate = 0x41, 44 kDSOType_DNSPushUnsubscribe = 0x42, 45 kDSOType_DNSPushReconfirm = 0x43, 46 47 // Experimental types, taken from the experimental number space, for the discovery relay. 48 kDSOType_mDNSLinkRequest = 0xF901, 49 kDSOType_mDNSLinkDiscontinue = 0xF902, 50 kDSOType_mDNSMessage = 0xF903, 51 kDSOType_LinkIdentifier = 0xF904, 52 kDSOType_L2SourceAddress = 0xF905, 53 kDSOType_IPSourceAddress = 0xF906, 54 kDSOType_mDNSReportLinkChanges = 0xF907, 55 kDSOType_mDNSStopLinkChanges = 0xF908, 56 kDSOType_mDNSLinkAvailable = 0xF900, 57 kDSOType_mDNSLinkUnavailable = 0xF90a, 58 kDSOType_LinkPrefix = 0xF90b, 59 60 // Experimental types, taken from the experimental number space, for SRP Replication. 61 kDSOType_SRPLSession = 0xF90c, 62 kDSOType_SRPLSendCandidates = 0xF90d, 63 kDSOType_SRPLCandidate = 0xF90e, 64 kDSOType_SRPLHost = 0xF90f, 65 kDSOType_SRPLServerID = 0xF910, 66 kDSOType_SRPLCandidateYes = 0xF911, 67 kDSOType_SRPLCandidateNo = 0xF912, 68 kDSOType_SRPLConflict = 0xF913, 69 kDSOType_SRPLHostname = 0xF914, 70 kDSOType_SRPLHostMessage = 0xF915, 71 kDSOType_SRPLTimeOffset = 0xF916, 72 kDSOType_SRPLKeyID = 0xF917, 73 kDSOType_SRPLServerStableID = 0xF918, 74 kDSOType_SRPLVersion = 0xF919, 75 kDSOType_SRPLDomainName = 0xF91a, 76 kDSOType_SRPLNewPartner = 0xF91b, 77 } dso_message_types_t; 78 79 // When a DSO message arrives, or one that was sent is acknowledged, or the state of the DSO connection 80 // changes, we need to call the user of the DSO connection. 81 typedef enum { 82 kDSOEventType_DNSMessage, // A DNS message that is not a DSO message 83 kDSOEventType_DNSResponse, // A DNS response that is not a DSO response 84 kDSOEventType_DSOMessage, // DSOState.primary and DSOState.additl will contain the message TLVs; 85 // header will contain the DNS header 86 kDSOEventType_Finalize, // The DSO connection to the other DSO endpoint has terminated and we are 87 // in the idle loop. 88 kDSOEventType_DSOResponse, // DSOState.primary and DSOState.additl contain any TLVs in the response; 89 // header contains the DNS header 90 kDSOEventType_Connected, // We succeeded in making a connection 91 kDSOEventType_ConnectFailed, // We failed to get a connection 92 kDSOEventType_Disconnected, // We were connected, but have disconnected or been disconnected 93 kDSOEventType_ShouldReconnect, // We are disconnected, and a scheduled reconnect timer has gone off. 94 // Recipient is responsible for reconnecting, or deciding not to. 95 kDSOEventType_Inactive, // We went inactive and the inactivity timeout expired, so it's time to drop the connection. 96 kDSOEventType_Keepalive, // It's time to send a keepalive message, here are the values to send 97 kDSOEventType_KeepaliveRcvd, // We just received a keepalive from a client, here are the values. 98 kDSOEventType_RetryDelay // We got a RetryDelay from the server. Have to shut down. 99 } dso_event_type_t; 100 101 typedef struct dso_outstanding_query { 102 uint16_t id; 103 void *context; 104 } dso_outstanding_query_t; 105 106 typedef struct dso_outstanding_query_state { 107 int outstanding_query_count; 108 int max_outstanding_queries; 109 dso_outstanding_query_t queries[0]; 110 } dso_outstanding_query_state_t; 111 112 typedef struct dso_query_receive_context { 113 void *query_context; 114 void *message_context; 115 uint16_t rcode; 116 } dso_query_receive_context_t; 117 118 typedef struct dso_disconnect_context { 119 uint32_t reconnect_delay; 120 } dso_disconnect_context_t; 121 122 typedef struct dso_keepalive_context { 123 uint32_t inactivity_timeout; 124 uint32_t keepalive_interval; 125 uint16_t xid; 126 bool send_response; 127 } dso_keepalive_context_t; 128 129 // Structure to represent received DSO TLVs 130 typedef struct dsotlv { 131 uint16_t opcode; 132 uint16_t length; 133 const uint8_t *payload; 134 } dso_tlv_t; 135 136 // DSO message under construction 137 typedef struct dso_message { 138 uint8_t *buf; // The buffer in which we are constructing the message 139 size_t max; // Size of the buffer 140 size_t cur; // Current position in the buffer 141 bool building_tlv; // True if we have started and not finished building a TLV 142 int outstanding_query_number; // Number of the outstanding query state entry for this message, or -1 143 size_t tlv_len; // Current length of the TLV we are building. 144 size_t tlv_len_offset; // Where to store the length of the current TLV when finished. 145 const uint8_t *no_copy_bytes; // One TLV can have data that isn't copied into the buffer 146 size_t no_copy_bytes_len; // Length of that data, if any. 147 size_t no_copy_bytes_offset; // Where in the buffer the data should be interposed. 148 } dso_message_t; 149 150 // Record of ongoing activity 151 typedef struct dso_activity dso_activity_t; 152 struct dso_activity { 153 dso_activity_t *next; 154 void (*finalize)(dso_activity_t *activity); 155 const char *activity_type; // Name of the activity type, must be the same pointer for all activities of a type. 156 void *context; // Activity implementation's context (if any). 157 char *name; // Name of the individual activity. 158 }; 159 160 typedef struct dso_transport dso_transport_t; 161 typedef struct dso_state dso_state_t; 162 typedef int32_t event_time_t; 163 164 typedef void (*dso_event_callback_t)(void *context, void *header, 165 dso_state_t *dso, dso_event_type_t eventType); 166 typedef void (*dso_transport_finalize_t)(dso_transport_t *transport, const char *whence); 167 168 typedef enum { 169 // When the object is created and holds a reference to the context, the callback(see below) is called with 170 // dso_life_cycle_create. 171 dso_life_cycle_create, 172 // When the object is canceled, the callback(see below) is called with dso_life_cycle_cancel to provide a chance 173 // for the context to do the corresponding cleaning work(cancel or release/free). 174 dso_life_cycle_cancel, 175 // When the object is freed, the callback(see below) is called with dso_life_cycle_free to provide a chance for the 176 // context to clean anything remains allocated. 177 dso_life_cycle_free 178 } dso_life_cycle_t; 179 180 typedef bool (*dso_life_cycle_context_callback_t)(const dso_life_cycle_t life_cycle, void *const context, 181 dso_state_t *const dso); 182 183 // DNS Stateless Operations state 184 struct dso_state { 185 dso_state_t *next; 186 void *context; // The context of the next layer up (e.g., a Discovery Proxy) 187 // The callback gets called when dso_state_t is created, canceled or freed. 188 dso_life_cycle_context_callback_t context_callback; 189 dso_event_callback_t cb; // Called when an event happens 190 191 // Transport state; handled separately for reusability 192 dso_transport_t *transport; // The transport (e.g., dso-transport.c or other). 193 dso_transport_finalize_t transport_finalize; 194 195 uint32_t serial; // Unique serial number which can be used after the DSO has been dropped. 196 bool is_server; // True if the endpoint represented by this DSO state is a server 197 // (according to the DSO spec) 198 bool has_session; // True if DSO session establishment has happened for this DSO endpoint 199 event_time_t response_awaited; // If we are waiting for a session-establishing response, when it's 200 // expected; otherwise zero. 201 uint32_t keepalive_interval; // Time between keepalives (to be sent, on client, expected, on server) 202 uint32_t inactivity_timeout; // Session can't be inactive more than this amount of time. 203 event_time_t keepalive_due; // When the next keepalive is due (to be received or sent) 204 event_time_t inactivity_due; // When next activity has to happen for connection to remain active 205 dso_activity_t *activities; // Outstanding DSO activities. 206 207 dso_tlv_t primary; // Primary TLV for current message 208 dso_tlv_t *additl; // Additional TLVs 209 unsigned num_additls; // Number of additional TLVs in this message 210 unsigned max_additls; // Maximum number of additional TLVs this DSO state can represent 211 dso_tlv_t additl_buf[MAX_ADDITLS]; // Initial buffer for additional TLVs. 212 213 char *remote_name; 214 215 dso_outstanding_query_state_t *outstanding_queries; 216 }; 217 218 // Provided by dso.c 219 dso_state_t *dso_state_create(bool is_server, int max_outstanding_queries, const char *remote_name, 220 dso_event_callback_t callback, void *const context, 221 const dso_life_cycle_context_callback_t context_callback, 222 dso_transport_t *transport); 223 dso_state_t *dso_find_by_serial(uint32_t serial); 224 void dso_state_cancel(dso_state_t *dso); 225 void dso_cleanup(bool call_callbacks); 226 int32_t dso_idle(void *context, int32_t now, int32_t next_timer_event); 227 void dso_set_event_context(dso_state_t *dso, void *context); 228 void dso_set_event_callback(dso_state_t *dso, dso_event_callback_t callback); 229 void dso_set_life_cycle_callback(dso_state_t *dso, dso_life_cycle_context_callback_t callback); 230 void dso_start_tlv(dso_message_t *state, int opcode); 231 void dso_add_tlv_bytes(dso_message_t *state, const uint8_t *bytes, size_t len); 232 void dso_add_tlv_bytes_no_copy(dso_message_t *state, const uint8_t *bytes, size_t len); 233 void dso_add_tlv_byte(dso_message_t *state, uint8_t byte); 234 void dso_add_tlv_u16(dso_message_t *state, uint16_t u16); 235 void dso_add_tlv_u32(dso_message_t *state, uint32_t u32); 236 void dso_finish_tlv(dso_message_t *state); 237 dso_activity_t *dso_find_activity(dso_state_t *dso, const char *name, const char *activity_type, void *context); 238 dso_activity_t *dso_add_activity(dso_state_t *dso, const char *name, const char *activity_type, 239 void *context, void (*finalize)(dso_activity_t *)); 240 void dso_drop_activity(dso_state_t *dso, dso_activity_t *activity); 241 uint32_t dso_ignore_further_responses(dso_state_t *dso, const void *context); 242 243 /*! 244 * @brief 245 * Update the context of the outstanding queries in the DSO state. 246 * 247 * @param dso 248 * The reference to the DSO state. 249 * 250 * @param old_context 251 * The original context of the outstanding query to be updated. 252 * 253 * @param new_context 254 * The new context to set for the same outstanding query. 255 * 256 * @discussion 257 * This function must be called to update the the query context if the new one invalidates the old one. 258 */ 259 void dso_update_outstanding_query_context(dso_state_t *dso, const void *old_context, void *new_context); 260 261 uint32_t dso_connections_reset_outstanding_query_context(const void *context); 262 bool dso_make_message(dso_message_t *state, uint8_t *outbuf, size_t outbuf_size, dso_state_t *dso, 263 bool unidirectional, bool response, uint16_t xid, int rcode, void *callback_state); 264 size_t dso_message_length(dso_message_t *state); 265 void dso_retry_delay(dso_state_t *dso, const DNSMessageHeader *header); 266 void dso_keepalive(dso_state_t *dso, const DNSMessageHeader *header, bool response); 267 void dso_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length, void *context); 268 void dns_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length, void *context); 269 270 const char *dso_event_type_to_string(dso_event_type_t dso_event_type); 271 272 // Provided by DSO transport implementation for use by dso.c: 273 int32_t dso_transport_idle(void *context, int32_t now, int32_t next_timer_event); 274 bool dso_send_simple_response(dso_state_t *dso, int rcode, const DNSMessageHeader *header, const char *pres); 275 bool dso_send_not_implemented(dso_state_t *dso, const DNSMessageHeader *header); 276 bool dso_send_refused(dso_state_t *dso, const DNSMessageHeader *header); 277 bool dso_send_formerr(dso_state_t *dso, const DNSMessageHeader *header); 278 bool dso_send_servfail(dso_state_t *dso, const DNSMessageHeader *header); 279 bool dso_send_name_error(dso_state_t *dso, const DNSMessageHeader *header); 280 bool dso_send_no_error(dso_state_t *dso, const DNSMessageHeader *header); 281 #endif // !defined(__DSO_H) 282 283 // Local Variables: 284 // mode: C 285 // tab-width: 4 286 // c-file-style: "bsd" 287 // c-basic-offset: 4 288 // fill-column: 108 289 // indent-tabs-mode: nil 290 // End: 291