11//NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
22#define _GNU_SOURCE // needed for having accept4()
33
4+ #include <arpa/inet.h>
45#include <errno.h>
56#include <fcntl.h>
7+ #include <stdlib.h>
8+ #include <string.h>
9+ #include <sys/socket.h>
610#include <unistd.h>
711
8- #include "dns_server_tcp.h"
12+ #include "dns_common.h"
13+ #include "dns_listener_tcp.h"
914#include "logging.h"
1015
1116// Platform compatibility
@@ -33,8 +38,10 @@ enum {
3338 TCP_DNS_MAX_PAYLOAD = UINT16_MAX - sizeof (uint16_t ), // Max after 2-byte length prefix
3439};
3540
41+ typedef struct dns_listener_tcp_s dns_listener_tcp_t ;
42+
3643struct tcp_client_s {
37- struct dns_server_tcp_s * d ;
44+ dns_listener_tcp_t * d ;
3845
3946 uint64_t id ;
4047 int sock ;
@@ -52,10 +59,12 @@ struct tcp_client_s {
5259 struct tcp_client_s * next ;
5360} __attribute__((packed )) __attribute__((aligned (128 ))) ;
5461
55- struct dns_server_tcp_s {
62+ struct dns_listener_tcp_s {
63+ dns_listener_t base ;
64+
5665 struct ev_loop * loop ;
5766
58- dns_req_received_cb cb ;
67+ dns_request_fn cb ;
5968 void * cb_data ;
6069
6170 int sock ;
@@ -70,7 +79,7 @@ struct dns_server_tcp_s {
7079
7180
7281static void remove_client (struct tcp_client_s * client ) {
73- dns_server_tcp_t * d = client -> d ;
82+ dns_listener_tcp_t * d = client -> d ;
7483
7584 DLOG_CLIENT ("Removing client, socket %d" , client -> sock );
7685
@@ -114,7 +123,7 @@ static int get_dns_request(struct tcp_client_s *client,
114123 return 0 ; // Partial request
115124 }
116125 // copy whole request
117- * dns_req = (char * )malloc (* req_size ); // To free buffer after https request is complete.
126+ * dns_req = (char * )malloc (* req_size ); // freed when DoH request completes
118127 if (* dns_req == NULL ) {
119128 FLOG_CLIENT ("Out of mem" );
120129 }
@@ -128,7 +137,7 @@ static int get_dns_request(struct tcp_client_s *client,
128137static void read_cb (struct ev_loop __attribute__((unused )) * loop ,
129138 ev_io * w , int __attribute__((unused )) revents ) {
130139 struct tcp_client_s * client = (struct tcp_client_s * )w -> data ;
131- dns_server_tcp_t * d = client -> d ;
140+ dns_listener_tcp_t * d = client -> d ;
132141
133142 // Receive data
134143 char buf [DNS_REQUEST_BUFFER_SIZE ]; // if there would be more data, callback will be called again
@@ -191,7 +200,7 @@ static void read_cb(struct ev_loop __attribute__((unused)) *loop,
191200 return ;
192201 }
193202
194- d -> cb (d , 1 , d -> cb_data , (struct sockaddr * )& client -> raddr , dns_req , req_size );
203+ d -> cb (d -> cb_data , & d -> base , (struct sockaddr * )& client -> raddr , dns_req , req_size );
195204 request_received = 1 ;
196205 }
197206
@@ -209,7 +218,7 @@ static void timer_cb(struct ev_loop __attribute__((unused)) *loop,
209218
210219static void accept_cb (struct ev_loop __attribute__((unused )) * loop ,
211220 ev_io * w , int __attribute__((unused )) revents ) {
212- dns_server_tcp_t * d = (dns_server_tcp_t * )w -> data ;
221+ dns_listener_tcp_t * d = (dns_listener_tcp_t * )w -> data ;
213222
214223 struct sockaddr_storage client_addr ;
215224 socklen_t client_addr_len = sizeof (client_addr );
@@ -258,7 +267,7 @@ static void accept_cb(struct ev_loop __attribute__((unused)) *loop,
258267 DLOG_CLIENT ("Accepted client %u of %u, socket %d" , d -> client_count , d -> client_limit , client -> sock );
259268}
260269
261- // Creates and bind a listening non-blocking TCP socket for incoming requests.
270+ // Creates and binds a listening non-blocking TCP socket for incoming requests.
262271static int get_tcp_listen_sock (struct addrinfo * listen_addrinfo ) {
263272 int sock = socket (listen_addrinfo -> ai_family , SOCK_STREAM , 0 );
264273 if (sock < 0 ) {
@@ -308,33 +317,12 @@ static int get_tcp_listen_sock(struct addrinfo *listen_addrinfo) {
308317 return sock ;
309318}
310319
311- dns_server_tcp_t * dns_server_tcp_create (
312- struct ev_loop * loop , struct addrinfo * listen_addrinfo ,
313- dns_req_received_cb cb , void * data , uint16_t tcp_client_limit ) {
314- dns_server_tcp_t * d = (dns_server_tcp_t * ) malloc (sizeof (dns_server_tcp_t ));
315- if (d == NULL ) {
316- FLOG ("Out of mem" );
317- }
318- d -> loop = loop ;
319- d -> cb = cb ;
320- d -> cb_data = data ;
321- d -> sock = get_tcp_listen_sock (listen_addrinfo );
322- d -> addrlen = listen_addrinfo -> ai_addrlen ;
323- d -> client_id = 0 ;
324- d -> client_count = 0 ;
325- d -> client_limit = tcp_client_limit ;
326- d -> clients = NULL ;
327-
328- ev_io_init (& d -> accept_watcher , accept_cb , d -> sock , EV_READ );
329- d -> accept_watcher .data = d ;
330- ev_io_start (d -> loop , & d -> accept_watcher );
331-
332- return d ;
333- }
320+ static void tcp_respond (dns_listener_t * self , struct sockaddr * raddr ,
321+ const char __attribute__((unused )) * dns_req ,
322+ size_t __attribute__((unused )) dns_req_len ,
323+ char * resp , size_t resp_len ) {
324+ dns_listener_tcp_t * d = (dns_listener_tcp_t * )self ;
334325
335- void dns_server_tcp_respond (dns_server_tcp_t * d ,
336- struct sockaddr * raddr , char * resp , size_t resp_len )
337- {
338326 // Limit response size to prevent overflow when accounting for the 2-byte
339327 // length prefix. The total on-wire size would be resp_len + sizeof(uint16_t).
340328 if (resp_len < DNS_HEADER_LENGTH || resp_len > TCP_DNS_MAX_PAYLOAD ) {
@@ -402,13 +390,42 @@ void dns_server_tcp_respond(dns_server_tcp_t *d,
402390 ev_timer_again (d -> loop , & client -> timer_watcher );
403391}
404392
405- void dns_server_tcp_stop (dns_server_tcp_t * d ) {
393+ static void tcp_stop (dns_listener_t * self ) {
394+ dns_listener_tcp_t * d = (dns_listener_tcp_t * )self ;
406395 while (d -> clients ) {
407396 remove_client (d -> clients ); //NOLINT(clang-analyzer-unix.Malloc) false use after free detection
408397 }
409398 ev_io_stop (d -> loop , & d -> accept_watcher );
410399}
411400
412- void dns_server_tcp_cleanup (dns_server_tcp_t * d ) {
401+ static void tcp_destroy (dns_listener_t * self ) {
402+ dns_listener_tcp_t * d = (dns_listener_tcp_t * )self ;
413403 close (d -> sock );
404+ free (d );
405+ }
406+
407+ dns_listener_t * dns_tcp_listener_create (struct ev_loop * loop ,
408+ struct addrinfo * listen_addrinfo ,
409+ uint16_t client_limit ,
410+ dns_request_fn cb , void * ctx ) {
411+ dns_listener_tcp_t * d = (dns_listener_tcp_t * )calloc (1 , sizeof (dns_listener_tcp_t ));
412+ if (d == NULL ) {
413+ FLOG ("Out of mem" );
414+ }
415+ d -> base .respond = tcp_respond ;
416+ d -> base .stop = tcp_stop ;
417+ d -> base .destroy = tcp_destroy ;
418+ d -> base .transport = DNS_TRANSPORT_TCP ;
419+ d -> loop = loop ;
420+ d -> cb = cb ;
421+ d -> cb_data = ctx ;
422+ d -> sock = get_tcp_listen_sock (listen_addrinfo );
423+ d -> addrlen = listen_addrinfo -> ai_addrlen ;
424+ d -> client_limit = client_limit ;
425+
426+ ev_io_init (& d -> accept_watcher , accept_cb , d -> sock , EV_READ );
427+ d -> accept_watcher .data = d ;
428+ ev_io_start (d -> loop , & d -> accept_watcher );
429+
430+ return & d -> base ;
414431}
0 commit comments