• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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