1 /* MIT License 2 * 3 * Copyright (c) 2024 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26 #ifndef __ARES_CONN_H 27 #define __ARES_CONN_H 28 29 #include "ares_socket.h" 30 31 struct ares_conn; 32 typedef struct ares_conn ares_conn_t; 33 34 struct ares_server; 35 typedef struct ares_server ares_server_t; 36 37 typedef enum { 38 /*! No flags */ 39 ARES_CONN_FLAG_NONE = 0, 40 /*! TCP connection, not UDP */ 41 ARES_CONN_FLAG_TCP = 1 << 0, 42 /*! TCP Fast Open is enabled and being used if supported by the OS */ 43 ARES_CONN_FLAG_TFO = 1 << 1, 44 /*! TCP Fast Open has not yet sent its first packet. Gets unset on first 45 * write to a connection */ 46 ARES_CONN_FLAG_TFO_INITIAL = 1 << 2 47 } ares_conn_flags_t; 48 49 typedef enum { 50 ARES_CONN_STATE_NONE = 0, 51 ARES_CONN_STATE_READ = 1 << 0, 52 ARES_CONN_STATE_WRITE = 1 << 1, 53 ARES_CONN_STATE_CONNECTED = 1 << 2, /* This doesn't get a callback */ 54 ARES_CONN_STATE_CBFLAGS = ARES_CONN_STATE_READ | ARES_CONN_STATE_WRITE 55 } ares_conn_state_flags_t; 56 57 struct ares_conn { 58 ares_server_t *server; 59 ares_socket_t fd; 60 struct ares_addr self_ip; 61 ares_conn_flags_t flags; 62 ares_conn_state_flags_t state_flags; 63 64 /*! Outbound buffered data that is not yet sent. Exists as one contiguous 65 * stream in TCP format (big endian 16bit length prefix followed by DNS 66 * wire-format message). For TCP this can be sent as-is, UDP this must 67 * be sent per-packet (stripping the length prefix) */ 68 ares_buf_t *out_buf; 69 70 /*! Inbound buffered data that is not yet parsed. Exists as one contiguous 71 * stream in TCP format (big endian 16bit length prefix followed by DNS 72 * wire-format message). TCP may have partial data and this needs to be 73 * handled gracefully, but UDP will always have a full message */ 74 ares_buf_t *in_buf; 75 76 /* total number of queries run on this connection since it was established */ 77 size_t total_queries; 78 79 /* list of outstanding queries to this connection */ 80 ares_llist_t *queries_to_conn; 81 }; 82 83 /*! Various buckets for grouping history */ 84 typedef enum { 85 ARES_METRIC_1MINUTE = 0, /*!< Bucket for tracking over the last minute */ 86 ARES_METRIC_15MINUTES, /*!< Bucket for tracking over the last 15 minutes */ 87 ARES_METRIC_1HOUR, /*!< Bucket for tracking over the last hour */ 88 ARES_METRIC_1DAY, /*!< Bucket for tracking over the last day */ 89 ARES_METRIC_INCEPTION, /*!< Bucket for tracking since inception */ 90 ARES_METRIC_COUNT /*!< Count of buckets, not a real bucket */ 91 } ares_server_bucket_t; 92 93 /*! Data metrics collected for each bucket */ 94 typedef struct { 95 time_t ts; /*!< Timestamp divided by bucket divisor */ 96 unsigned int latency_min_ms; /*!< Minimum latency for queries */ 97 unsigned int latency_max_ms; /*!< Maximum latency for queries */ 98 ares_uint64_t total_ms; /*!< Cumulative query time for bucket */ 99 ares_uint64_t total_count; /*!< Number of queries for bucket */ 100 101 time_t prev_ts; /*!< Previous period bucket timestamp */ 102 ares_uint64_t 103 prev_total_ms; /*!< Previous period bucket cumulative query time */ 104 ares_uint64_t prev_total_count; /*!< Previous period bucket query count */ 105 } ares_server_metrics_t; 106 107 typedef enum { 108 ARES_COOKIE_INITIAL = 0, 109 ARES_COOKIE_GENERATED = 1, 110 ARES_COOKIE_SUPPORTED = 2, 111 ARES_COOKIE_UNSUPPORTED = 3 112 } ares_cookie_state_t; 113 114 /*! Structure holding tracking data for RFC 7873/9018 DNS cookies. 115 * Implementation plan for this feature is here: 116 * https://github.com/c-ares/c-ares/issues/620 117 */ 118 typedef struct { 119 /*! starts at INITIAL, transitions as needed. */ 120 ares_cookie_state_t state; 121 /*! randomly-generate client cookie */ 122 unsigned char client[8]; 123 /*! timestamp client cookie was generated, used for rotation purposes */ 124 ares_timeval_t client_ts; 125 /*! IP address last used for client to connect to server. If this changes 126 * The client cookie gets invalidated */ 127 struct ares_addr client_ip; 128 /*! Server Cookie last received, 8-32 bytes in length */ 129 unsigned char server[32]; 130 /*! Length of server cookie on file. */ 131 size_t server_len; 132 /*! Timestamp of last attempt to use cookies, but it was determined that the 133 * server didn't support them */ 134 ares_timeval_t unsupported_ts; 135 } ares_cookie_t; 136 137 struct ares_server { 138 /* Configuration */ 139 size_t idx; /* index for server in system configuration */ 140 struct ares_addr addr; 141 unsigned short udp_port; /* host byte order */ 142 unsigned short tcp_port; /* host byte order */ 143 char ll_iface[64]; /* IPv6 Link Local Interface */ 144 unsigned int ll_scope; /* IPv6 Link Local Scope */ 145 146 size_t consec_failures; /* Consecutive query failure count 147 * can be hard errors or timeouts 148 */ 149 ares_bool_t probe_pending; /* Whether a probe is pending for this 150 * server due to prior failures */ 151 ares_llist_t *connections; 152 ares_conn_t *tcp_conn; 153 154 /* The next time when we will retry this server if it has hit failures */ 155 ares_timeval_t next_retry_time; 156 157 /*! Buckets for collecting metrics about the server */ 158 ares_server_metrics_t metrics[ARES_METRIC_COUNT]; 159 160 /*! RFC 7873/9018 DNS Cookies */ 161 ares_cookie_t cookie; 162 163 /* Link back to owning channel */ 164 ares_channel_t *channel; 165 }; 166 167 void ares_close_connection(ares_conn_t *conn, ares_status_t requeue_status); 168 void ares_close_sockets(ares_server_t *server); 169 void ares_check_cleanup_conns(const ares_channel_t *channel); 170 171 void ares_destroy_servers_state(ares_channel_t *channel); 172 ares_status_t ares_open_connection(ares_conn_t **conn_out, 173 ares_channel_t *channel, 174 ares_server_t *server, ares_bool_t is_tcp); 175 176 ares_conn_err_t ares_conn_write(ares_conn_t *conn, const void *data, size_t len, 177 size_t *written); 178 ares_status_t ares_conn_flush(ares_conn_t *conn); 179 ares_conn_err_t ares_conn_read(ares_conn_t *conn, void *data, size_t len, 180 size_t *read_bytes); 181 ares_conn_t *ares_conn_from_fd(const ares_channel_t *channel, ares_socket_t fd); 182 void ares_conn_sock_state_cb_update(ares_conn_t *conn, 183 ares_conn_state_flags_t flags); 184 ares_conn_err_t ares_socket_recv(ares_channel_t *channel, ares_socket_t s, 185 ares_bool_t is_tcp, void *data, 186 size_t data_len, size_t *read_bytes); 187 ares_conn_err_t ares_socket_recvfrom(ares_channel_t *channel, ares_socket_t s, 188 ares_bool_t is_tcp, void *data, 189 size_t data_len, int flags, 190 struct sockaddr *from, 191 ares_socklen_t *from_len, 192 size_t *read_bytes); 193 194 void ares_destroy_server(ares_server_t *server); 195 196 #endif 197