Home | History | Annotate | Line # | Download | only in DSO
      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