1*be771a7bSCy Schubert /* 2*be771a7bSCy Schubert * testcode/doqclient.c - debug program. Perform multiple DNS queries using DoQ. 3*be771a7bSCy Schubert * 4*be771a7bSCy Schubert * Copyright (c) 2022, NLnet Labs. All rights reserved. 5*be771a7bSCy Schubert * 6*be771a7bSCy Schubert * This software is open source. 7*be771a7bSCy Schubert * 8*be771a7bSCy Schubert * Redistribution and use in source and binary forms, with or without 9*be771a7bSCy Schubert * modification, are permitted provided that the following conditions 10*be771a7bSCy Schubert * are met: 11*be771a7bSCy Schubert * 12*be771a7bSCy Schubert * Redistributions of source code must retain the above copyright notice, 13*be771a7bSCy Schubert * this list of conditions and the following disclaimer. 14*be771a7bSCy Schubert * 15*be771a7bSCy Schubert * Redistributions in binary form must reproduce the above copyright notice, 16*be771a7bSCy Schubert * this list of conditions and the following disclaimer in the documentation 17*be771a7bSCy Schubert * and/or other materials provided with the distribution. 18*be771a7bSCy Schubert * 19*be771a7bSCy Schubert * Neither the name of the NLNET LABS nor the names of its contributors may 20*be771a7bSCy Schubert * be used to endorse or promote products derived from this software without 21*be771a7bSCy Schubert * specific prior written permission. 22*be771a7bSCy Schubert * 23*be771a7bSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*be771a7bSCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25*be771a7bSCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26*be771a7bSCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27*be771a7bSCy Schubert * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28*be771a7bSCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29*be771a7bSCy Schubert * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30*be771a7bSCy Schubert * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31*be771a7bSCy Schubert * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32*be771a7bSCy Schubert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33*be771a7bSCy Schubert * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34*be771a7bSCy Schubert */ 35*be771a7bSCy Schubert 36*be771a7bSCy Schubert /** 37*be771a7bSCy Schubert * \file 38*be771a7bSCy Schubert * 39*be771a7bSCy Schubert * Simple DNS-over-QUIC client. For testing and debugging purposes. 40*be771a7bSCy Schubert * No authentication of TLS cert. 41*be771a7bSCy Schubert */ 42*be771a7bSCy Schubert 43*be771a7bSCy Schubert #include "config.h" 44*be771a7bSCy Schubert #ifdef HAVE_GETOPT_H 45*be771a7bSCy Schubert #include <getopt.h> 46*be771a7bSCy Schubert #endif 47*be771a7bSCy Schubert 48*be771a7bSCy Schubert #ifdef HAVE_NGTCP2 49*be771a7bSCy Schubert #include <ngtcp2/ngtcp2.h> 50*be771a7bSCy Schubert #include <ngtcp2/ngtcp2_crypto.h> 51*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_NGTCP2_CRYPTO_QUICTLS_H 52*be771a7bSCy Schubert #include <ngtcp2/ngtcp2_crypto_quictls.h> 53*be771a7bSCy Schubert #else 54*be771a7bSCy Schubert #include <ngtcp2/ngtcp2_crypto_openssl.h> 55*be771a7bSCy Schubert #endif 56*be771a7bSCy Schubert #include <openssl/ssl.h> 57*be771a7bSCy Schubert #include <openssl/rand.h> 58*be771a7bSCy Schubert #ifdef HAVE_TIME_H 59*be771a7bSCy Schubert #include <time.h> 60*be771a7bSCy Schubert #endif 61*be771a7bSCy Schubert #include <sys/time.h> 62*be771a7bSCy Schubert #include "util/locks.h" 63*be771a7bSCy Schubert #include "util/net_help.h" 64*be771a7bSCy Schubert #include "sldns/sbuffer.h" 65*be771a7bSCy Schubert #include "sldns/str2wire.h" 66*be771a7bSCy Schubert #include "sldns/wire2str.h" 67*be771a7bSCy Schubert #include "util/data/msgreply.h" 68*be771a7bSCy Schubert #include "util/data/msgencode.h" 69*be771a7bSCy Schubert #include "util/data/msgparse.h" 70*be771a7bSCy Schubert #include "util/data/dname.h" 71*be771a7bSCy Schubert #include "util/random.h" 72*be771a7bSCy Schubert #include "util/ub_event.h" 73*be771a7bSCy Schubert struct doq_client_stream_list; 74*be771a7bSCy Schubert struct doq_client_stream; 75*be771a7bSCy Schubert 76*be771a7bSCy Schubert /** the local client data for the DoQ connection */ 77*be771a7bSCy Schubert struct doq_client_data { 78*be771a7bSCy Schubert /** file descriptor */ 79*be771a7bSCy Schubert int fd; 80*be771a7bSCy Schubert /** the event base for the events */ 81*be771a7bSCy Schubert struct ub_event_base* base; 82*be771a7bSCy Schubert /** the ub event */ 83*be771a7bSCy Schubert struct ub_event* ev; 84*be771a7bSCy Schubert /** the expiry timer */ 85*be771a7bSCy Schubert struct ub_event* expire_timer; 86*be771a7bSCy Schubert /** is the expire_timer added */ 87*be771a7bSCy Schubert int expire_timer_added; 88*be771a7bSCy Schubert /** the ngtcp2 connection information */ 89*be771a7bSCy Schubert struct ngtcp2_conn* conn; 90*be771a7bSCy Schubert /** random state */ 91*be771a7bSCy Schubert struct ub_randstate* rnd; 92*be771a7bSCy Schubert /** server connected to as a string */ 93*be771a7bSCy Schubert const char* svr; 94*be771a7bSCy Schubert /** the static secret */ 95*be771a7bSCy Schubert uint8_t* static_secret_data; 96*be771a7bSCy Schubert /** the static secret size */ 97*be771a7bSCy Schubert size_t static_secret_size; 98*be771a7bSCy Schubert /** destination address sockaddr */ 99*be771a7bSCy Schubert struct sockaddr_storage dest_addr; 100*be771a7bSCy Schubert /** length of dest addr */ 101*be771a7bSCy Schubert socklen_t dest_addr_len; 102*be771a7bSCy Schubert /** local address sockaddr */ 103*be771a7bSCy Schubert struct sockaddr_storage local_addr; 104*be771a7bSCy Schubert /** length of local addr */ 105*be771a7bSCy Schubert socklen_t local_addr_len; 106*be771a7bSCy Schubert /** SSL context */ 107*be771a7bSCy Schubert SSL_CTX* ctx; 108*be771a7bSCy Schubert /** SSL object */ 109*be771a7bSCy Schubert SSL* ssl; 110*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 111*be771a7bSCy Schubert /** the connection reference for ngtcp2_conn and userdata in ssl */ 112*be771a7bSCy Schubert struct ngtcp2_crypto_conn_ref conn_ref; 113*be771a7bSCy Schubert #endif 114*be771a7bSCy Schubert /** the quic version to use */ 115*be771a7bSCy Schubert uint32_t quic_version; 116*be771a7bSCy Schubert /** the last error */ 117*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 118*be771a7bSCy Schubert struct ngtcp2_ccerr ccerr; 119*be771a7bSCy Schubert #else 120*be771a7bSCy Schubert struct ngtcp2_connection_close_error last_error; 121*be771a7bSCy Schubert #endif 122*be771a7bSCy Schubert /** the recent tls alert error code */ 123*be771a7bSCy Schubert uint8_t tls_alert; 124*be771a7bSCy Schubert /** the buffer for packet operations */ 125*be771a7bSCy Schubert struct sldns_buffer* pkt_buf; 126*be771a7bSCy Schubert /** The list of queries to start. They have no stream associated. 127*be771a7bSCy Schubert * Once they do, they move to the send list. */ 128*be771a7bSCy Schubert struct doq_client_stream_list* query_list_start; 129*be771a7bSCy Schubert /** The list of queries to send. They have a stream, and they are 130*be771a7bSCy Schubert * sending data. Data could also be received, like errors. */ 131*be771a7bSCy Schubert struct doq_client_stream_list* query_list_send; 132*be771a7bSCy Schubert /** The list of queries to receive. They have a stream, and the 133*be771a7bSCy Schubert * send is done, it is possible to read data. */ 134*be771a7bSCy Schubert struct doq_client_stream_list* query_list_receive; 135*be771a7bSCy Schubert /** The list of queries that are stopped. They have no stream 136*be771a7bSCy Schubert * active any more. Write and read are done. The query is done, 137*be771a7bSCy Schubert * and it may be in error and then have no answer or partial answer. */ 138*be771a7bSCy Schubert struct doq_client_stream_list* query_list_stop; 139*be771a7bSCy Schubert /** is there a blocked packet in the blocked_pkt buffer */ 140*be771a7bSCy Schubert int have_blocked_pkt; 141*be771a7bSCy Schubert /** store blocked packet, a packet that could not be sent on the 142*be771a7bSCy Schubert * nonblocking socket. */ 143*be771a7bSCy Schubert struct sldns_buffer* blocked_pkt; 144*be771a7bSCy Schubert /** ecn info for the blocked packet */ 145*be771a7bSCy Schubert struct ngtcp2_pkt_info blocked_pkt_pi; 146*be771a7bSCy Schubert /** the congestion control algorithm */ 147*be771a7bSCy Schubert ngtcp2_cc_algo cc_algo; 148*be771a7bSCy Schubert /** the transport parameters file, for early data transmission */ 149*be771a7bSCy Schubert const char* transport_file; 150*be771a7bSCy Schubert /** the tls session file, for session resumption */ 151*be771a7bSCy Schubert const char* session_file; 152*be771a7bSCy Schubert /** if early data is enabled for the connection */ 153*be771a7bSCy Schubert int early_data_enabled; 154*be771a7bSCy Schubert /** how quiet is the output */ 155*be771a7bSCy Schubert int quiet; 156*be771a7bSCy Schubert /** the configured port for the destination */ 157*be771a7bSCy Schubert int port; 158*be771a7bSCy Schubert }; 159*be771a7bSCy Schubert 160*be771a7bSCy Schubert /** the local client stream list, for appending streams to */ 161*be771a7bSCy Schubert struct doq_client_stream_list { 162*be771a7bSCy Schubert /** first and last members of the list */ 163*be771a7bSCy Schubert struct doq_client_stream* first, *last; 164*be771a7bSCy Schubert }; 165*be771a7bSCy Schubert 166*be771a7bSCy Schubert /** the local client data for a DoQ stream */ 167*be771a7bSCy Schubert struct doq_client_stream { 168*be771a7bSCy Schubert /** next stream in list, and prev in list */ 169*be771a7bSCy Schubert struct doq_client_stream* next, *prev; 170*be771a7bSCy Schubert /** the data buffer */ 171*be771a7bSCy Schubert uint8_t* data; 172*be771a7bSCy Schubert /** length of the data buffer */ 173*be771a7bSCy Schubert size_t data_len; 174*be771a7bSCy Schubert /** if the client query has a stream, that is active, associated with 175*be771a7bSCy Schubert * it. The stream_id is in stream_id. */ 176*be771a7bSCy Schubert int has_stream; 177*be771a7bSCy Schubert /** the stream id */ 178*be771a7bSCy Schubert int64_t stream_id; 179*be771a7bSCy Schubert /** data written position */ 180*be771a7bSCy Schubert size_t nwrite; 181*be771a7bSCy Schubert /** the data length for write, in network format */ 182*be771a7bSCy Schubert uint16_t data_tcplen; 183*be771a7bSCy Schubert /** if the write of the query data is done. That means the 184*be771a7bSCy Schubert * write channel has FIN, is closed for writing. */ 185*be771a7bSCy Schubert int write_is_done; 186*be771a7bSCy Schubert /** data read position */ 187*be771a7bSCy Schubert size_t nread; 188*be771a7bSCy Schubert /** the answer length, in network byte order */ 189*be771a7bSCy Schubert uint16_t answer_len; 190*be771a7bSCy Schubert /** the answer buffer */ 191*be771a7bSCy Schubert struct sldns_buffer* answer; 192*be771a7bSCy Schubert /** the answer is complete */ 193*be771a7bSCy Schubert int answer_is_complete; 194*be771a7bSCy Schubert /** the query has an error, it has no answer, or no complete answer */ 195*be771a7bSCy Schubert int query_has_error; 196*be771a7bSCy Schubert /** if the query is done */ 197*be771a7bSCy Schubert int query_is_done; 198*be771a7bSCy Schubert }; 199*be771a7bSCy Schubert 200*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 201*be771a7bSCy Schubert /** the quic method struct, must remain valid during the QUIC connection. */ 202*be771a7bSCy Schubert static SSL_QUIC_METHOD quic_method; 203*be771a7bSCy Schubert #endif 204*be771a7bSCy Schubert 205*be771a7bSCy Schubert /** Get the connection ngtcp2_conn from the ssl app data 206*be771a7bSCy Schubert * ngtcp2_crypto_conn_ref */ 207*be771a7bSCy Schubert static ngtcp2_conn* conn_ref_get_conn(ngtcp2_crypto_conn_ref* conn_ref) 208*be771a7bSCy Schubert { 209*be771a7bSCy Schubert struct doq_client_data* data = (struct doq_client_data*) 210*be771a7bSCy Schubert conn_ref->user_data; 211*be771a7bSCy Schubert return data->conn; 212*be771a7bSCy Schubert } 213*be771a7bSCy Schubert 214*be771a7bSCy Schubert static void 215*be771a7bSCy Schubert set_app_data(SSL* ssl, struct doq_client_data* data) 216*be771a7bSCy Schubert { 217*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 218*be771a7bSCy Schubert data->conn_ref.get_conn = &conn_ref_get_conn; 219*be771a7bSCy Schubert data->conn_ref.user_data = data; 220*be771a7bSCy Schubert SSL_set_app_data(ssl, &data->conn_ref); 221*be771a7bSCy Schubert #else 222*be771a7bSCy Schubert SSL_set_app_data(ssl, data); 223*be771a7bSCy Schubert #endif 224*be771a7bSCy Schubert } 225*be771a7bSCy Schubert 226*be771a7bSCy Schubert static struct doq_client_data* 227*be771a7bSCy Schubert get_app_data(SSL* ssl) 228*be771a7bSCy Schubert { 229*be771a7bSCy Schubert struct doq_client_data* data; 230*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 231*be771a7bSCy Schubert data = (struct doq_client_data*)((struct ngtcp2_crypto_conn_ref*) 232*be771a7bSCy Schubert SSL_get_app_data(ssl))->user_data; 233*be771a7bSCy Schubert #else 234*be771a7bSCy Schubert data = (struct doq_client_data*) SSL_get_app_data(ssl); 235*be771a7bSCy Schubert #endif 236*be771a7bSCy Schubert return data; 237*be771a7bSCy Schubert } 238*be771a7bSCy Schubert 239*be771a7bSCy Schubert 240*be771a7bSCy Schubert 241*be771a7bSCy Schubert /** write handle routine */ 242*be771a7bSCy Schubert static void on_write(struct doq_client_data* data); 243*be771a7bSCy Schubert /** update the timer */ 244*be771a7bSCy Schubert static void update_timer(struct doq_client_data* data); 245*be771a7bSCy Schubert /** disconnect we are done */ 246*be771a7bSCy Schubert static void disconnect(struct doq_client_data* data); 247*be771a7bSCy Schubert /** fetch and write the transport file */ 248*be771a7bSCy Schubert static void early_data_write_transport(struct doq_client_data* data); 249*be771a7bSCy Schubert 250*be771a7bSCy Schubert /** usage of doqclient */ 251*be771a7bSCy Schubert static void usage(char* argv[]) 252*be771a7bSCy Schubert { 253*be771a7bSCy Schubert printf("usage: %s [options] name type class ...\n", argv[0]); 254*be771a7bSCy Schubert printf(" sends the name-type-class queries over " 255*be771a7bSCy Schubert "DNS-over-QUIC.\n"); 256*be771a7bSCy Schubert printf("-s server IP address to send the queries to, " 257*be771a7bSCy Schubert "default: 127.0.0.1\n"); 258*be771a7bSCy Schubert printf("-p Port to connect to, default: %d\n", 259*be771a7bSCy Schubert UNBOUND_DNS_OVER_QUIC_PORT); 260*be771a7bSCy Schubert printf("-v verbose output\n"); 261*be771a7bSCy Schubert printf("-q quiet, short output of answer\n"); 262*be771a7bSCy Schubert printf("-x file transport file, for read/write of transport parameters.\n\t\tIf it exists, it is used to send early data. It is then\n\t\twritten to contain the last used transport parameters.\n\t\tAlso -y must be enabled for early data to succeed.\n"); 263*be771a7bSCy Schubert printf("-y file session file, for read/write of TLS session. If it exists,\n\t\tit is used for TLS session resumption. It is then written\n\t\tto contain the last session used.\n\t\tOn its own, without also -x, resumes TLS session.\n"); 264*be771a7bSCy Schubert printf("-h This help text\n"); 265*be771a7bSCy Schubert exit(1); 266*be771a7bSCy Schubert } 267*be771a7bSCy Schubert 268*be771a7bSCy Schubert /** get the dest address */ 269*be771a7bSCy Schubert static void 270*be771a7bSCy Schubert get_dest_addr(struct doq_client_data* data, const char* svr, int port) 271*be771a7bSCy Schubert { 272*be771a7bSCy Schubert if(!ipstrtoaddr(svr, port, &data->dest_addr, &data->dest_addr_len)) { 273*be771a7bSCy Schubert printf("fatal: bad server specs '%s'\n", svr); 274*be771a7bSCy Schubert exit(1); 275*be771a7bSCy Schubert } 276*be771a7bSCy Schubert } 277*be771a7bSCy Schubert 278*be771a7bSCy Schubert /** open UDP socket to svr */ 279*be771a7bSCy Schubert static int 280*be771a7bSCy Schubert open_svr_udp(struct doq_client_data* data) 281*be771a7bSCy Schubert { 282*be771a7bSCy Schubert int fd = -1; 283*be771a7bSCy Schubert int r; 284*be771a7bSCy Schubert fd = socket(addr_is_ip6(&data->dest_addr, data->dest_addr_len)? 285*be771a7bSCy Schubert PF_INET6:PF_INET, SOCK_DGRAM, 0); 286*be771a7bSCy Schubert if(fd == -1) { 287*be771a7bSCy Schubert perror("socket() error"); 288*be771a7bSCy Schubert exit(1); 289*be771a7bSCy Schubert } 290*be771a7bSCy Schubert r = connect(fd, (struct sockaddr*)&data->dest_addr, 291*be771a7bSCy Schubert data->dest_addr_len); 292*be771a7bSCy Schubert if(r < 0 && r != EINPROGRESS) { 293*be771a7bSCy Schubert perror("connect() error"); 294*be771a7bSCy Schubert exit(1); 295*be771a7bSCy Schubert } 296*be771a7bSCy Schubert fd_set_nonblock(fd); 297*be771a7bSCy Schubert return fd; 298*be771a7bSCy Schubert } 299*be771a7bSCy Schubert 300*be771a7bSCy Schubert /** get the local address of the connection */ 301*be771a7bSCy Schubert static void 302*be771a7bSCy Schubert get_local_addr(struct doq_client_data* data) 303*be771a7bSCy Schubert { 304*be771a7bSCy Schubert memset(&data->local_addr, 0, sizeof(data->local_addr)); 305*be771a7bSCy Schubert data->local_addr_len = (socklen_t)sizeof(data->local_addr); 306*be771a7bSCy Schubert if(getsockname(data->fd, (struct sockaddr*)&data->local_addr, 307*be771a7bSCy Schubert &data->local_addr_len) == -1) { 308*be771a7bSCy Schubert perror("getsockname() error"); 309*be771a7bSCy Schubert exit(1); 310*be771a7bSCy Schubert } 311*be771a7bSCy Schubert log_addr(1, "local_addr", &data->local_addr, data->local_addr_len); 312*be771a7bSCy Schubert log_addr(1, "dest_addr", &data->dest_addr, data->dest_addr_len); 313*be771a7bSCy Schubert } 314*be771a7bSCy Schubert 315*be771a7bSCy Schubert static sldns_buffer* 316*be771a7bSCy Schubert make_query(char* qname, char* qtype, char* qclass) 317*be771a7bSCy Schubert { 318*be771a7bSCy Schubert struct query_info qinfo; 319*be771a7bSCy Schubert struct edns_data edns; 320*be771a7bSCy Schubert sldns_buffer* buf = sldns_buffer_new(65553); 321*be771a7bSCy Schubert if(!buf) fatal_exit("out of memory"); 322*be771a7bSCy Schubert qinfo.qname = sldns_str2wire_dname(qname, &qinfo.qname_len); 323*be771a7bSCy Schubert if(!qinfo.qname) { 324*be771a7bSCy Schubert printf("cannot parse query name: '%s'\n", qname); 325*be771a7bSCy Schubert exit(1); 326*be771a7bSCy Schubert } 327*be771a7bSCy Schubert 328*be771a7bSCy Schubert qinfo.qtype = sldns_get_rr_type_by_name(qtype); 329*be771a7bSCy Schubert qinfo.qclass = sldns_get_rr_class_by_name(qclass); 330*be771a7bSCy Schubert qinfo.local_alias = NULL; 331*be771a7bSCy Schubert 332*be771a7bSCy Schubert qinfo_query_encode(buf, &qinfo); /* flips buffer */ 333*be771a7bSCy Schubert free(qinfo.qname); 334*be771a7bSCy Schubert sldns_buffer_write_u16_at(buf, 0, 0x0000); 335*be771a7bSCy Schubert sldns_buffer_write_u16_at(buf, 2, BIT_RD); 336*be771a7bSCy Schubert memset(&edns, 0, sizeof(edns)); 337*be771a7bSCy Schubert edns.edns_present = 1; 338*be771a7bSCy Schubert edns.bits = EDNS_DO; 339*be771a7bSCy Schubert edns.udp_size = 4096; 340*be771a7bSCy Schubert if(sldns_buffer_capacity(buf) >= 341*be771a7bSCy Schubert sldns_buffer_limit(buf)+calc_edns_field_size(&edns)) 342*be771a7bSCy Schubert attach_edns_record(buf, &edns); 343*be771a7bSCy Schubert return buf; 344*be771a7bSCy Schubert } 345*be771a7bSCy Schubert 346*be771a7bSCy Schubert /** create client stream structure */ 347*be771a7bSCy Schubert static struct doq_client_stream* 348*be771a7bSCy Schubert client_stream_create(struct sldns_buffer* query_data) 349*be771a7bSCy Schubert { 350*be771a7bSCy Schubert struct doq_client_stream* str = calloc(1, sizeof(*str)); 351*be771a7bSCy Schubert if(!str) 352*be771a7bSCy Schubert fatal_exit("calloc failed: out of memory"); 353*be771a7bSCy Schubert str->data = memdup(sldns_buffer_begin(query_data), 354*be771a7bSCy Schubert sldns_buffer_limit(query_data)); 355*be771a7bSCy Schubert if(!str->data) 356*be771a7bSCy Schubert fatal_exit("alloc data failed: out of memory"); 357*be771a7bSCy Schubert str->data_len = sldns_buffer_limit(query_data); 358*be771a7bSCy Schubert str->stream_id = -1; 359*be771a7bSCy Schubert return str; 360*be771a7bSCy Schubert } 361*be771a7bSCy Schubert 362*be771a7bSCy Schubert /** free client stream structure */ 363*be771a7bSCy Schubert static void 364*be771a7bSCy Schubert client_stream_free(struct doq_client_stream* str) 365*be771a7bSCy Schubert { 366*be771a7bSCy Schubert if(!str) 367*be771a7bSCy Schubert return; 368*be771a7bSCy Schubert free(str->data); 369*be771a7bSCy Schubert sldns_buffer_free(str->answer); 370*be771a7bSCy Schubert free(str); 371*be771a7bSCy Schubert } 372*be771a7bSCy Schubert 373*be771a7bSCy Schubert /** setup the stream to start the write process */ 374*be771a7bSCy Schubert static void 375*be771a7bSCy Schubert client_stream_start_setup(struct doq_client_stream* str, int64_t stream_id) 376*be771a7bSCy Schubert { 377*be771a7bSCy Schubert str->has_stream = 1; 378*be771a7bSCy Schubert str->stream_id = stream_id; 379*be771a7bSCy Schubert str->nwrite = 0; 380*be771a7bSCy Schubert str->nread = 0; 381*be771a7bSCy Schubert str->answer_len = 0; 382*be771a7bSCy Schubert str->query_is_done = 0; 383*be771a7bSCy Schubert str->answer_is_complete = 0; 384*be771a7bSCy Schubert str->query_has_error = 0; 385*be771a7bSCy Schubert if(str->answer) { 386*be771a7bSCy Schubert sldns_buffer_free(str->answer); 387*be771a7bSCy Schubert str->answer = NULL; 388*be771a7bSCy Schubert } 389*be771a7bSCy Schubert } 390*be771a7bSCy Schubert 391*be771a7bSCy Schubert /** Return string for log purposes with query name. */ 392*be771a7bSCy Schubert static char* 393*be771a7bSCy Schubert client_stream_string(struct doq_client_stream* str) 394*be771a7bSCy Schubert { 395*be771a7bSCy Schubert char* s; 396*be771a7bSCy Schubert size_t dname_len; 397*be771a7bSCy Schubert char dname[256], tpstr[32], result[256+32+16]; 398*be771a7bSCy Schubert uint16_t tp; 399*be771a7bSCy Schubert if(str->data_len <= LDNS_HEADER_SIZE) { 400*be771a7bSCy Schubert s = strdup("query_with_no_question"); 401*be771a7bSCy Schubert if(!s) 402*be771a7bSCy Schubert fatal_exit("strdup failed: out of memory"); 403*be771a7bSCy Schubert return s; 404*be771a7bSCy Schubert } 405*be771a7bSCy Schubert dname_len = dname_valid(str->data+LDNS_HEADER_SIZE, 406*be771a7bSCy Schubert str->data_len-LDNS_HEADER_SIZE); 407*be771a7bSCy Schubert if(!dname_len) { 408*be771a7bSCy Schubert s = strdup("query_dname_not_valid"); 409*be771a7bSCy Schubert if(!s) 410*be771a7bSCy Schubert fatal_exit("strdup failed: out of memory"); 411*be771a7bSCy Schubert return s; 412*be771a7bSCy Schubert } 413*be771a7bSCy Schubert (void)sldns_wire2str_dname_buf(str->data+LDNS_HEADER_SIZE, dname_len, 414*be771a7bSCy Schubert dname, sizeof(dname)); 415*be771a7bSCy Schubert tp = sldns_wirerr_get_type(str->data+LDNS_HEADER_SIZE, 416*be771a7bSCy Schubert str->data_len-LDNS_HEADER_SIZE, dname_len); 417*be771a7bSCy Schubert (void)sldns_wire2str_type_buf(tp, tpstr, sizeof(tpstr)); 418*be771a7bSCy Schubert snprintf(result, sizeof(result), "%s %s", dname, tpstr); 419*be771a7bSCy Schubert s = strdup(result); 420*be771a7bSCy Schubert if(!s) 421*be771a7bSCy Schubert fatal_exit("strdup failed: out of memory"); 422*be771a7bSCy Schubert return s; 423*be771a7bSCy Schubert } 424*be771a7bSCy Schubert 425*be771a7bSCy Schubert /** create query stream list */ 426*be771a7bSCy Schubert static struct doq_client_stream_list* 427*be771a7bSCy Schubert stream_list_create(void) 428*be771a7bSCy Schubert { 429*be771a7bSCy Schubert struct doq_client_stream_list* list = calloc(1, sizeof(*list)); 430*be771a7bSCy Schubert if(!list) 431*be771a7bSCy Schubert fatal_exit("calloc failed: out of memory"); 432*be771a7bSCy Schubert return list; 433*be771a7bSCy Schubert } 434*be771a7bSCy Schubert 435*be771a7bSCy Schubert /** free the query stream list */ 436*be771a7bSCy Schubert static void 437*be771a7bSCy Schubert stream_list_free(struct doq_client_stream_list* list) 438*be771a7bSCy Schubert { 439*be771a7bSCy Schubert struct doq_client_stream* str; 440*be771a7bSCy Schubert if(!list) 441*be771a7bSCy Schubert return; 442*be771a7bSCy Schubert str = list->first; 443*be771a7bSCy Schubert while(str) { 444*be771a7bSCy Schubert struct doq_client_stream* next = str->next; 445*be771a7bSCy Schubert client_stream_free(str); 446*be771a7bSCy Schubert str = next; 447*be771a7bSCy Schubert } 448*be771a7bSCy Schubert free(list); 449*be771a7bSCy Schubert } 450*be771a7bSCy Schubert 451*be771a7bSCy Schubert /** append item to list */ 452*be771a7bSCy Schubert static void 453*be771a7bSCy Schubert stream_list_append(struct doq_client_stream_list* list, 454*be771a7bSCy Schubert struct doq_client_stream* str) 455*be771a7bSCy Schubert { 456*be771a7bSCy Schubert if(list->last) { 457*be771a7bSCy Schubert str->prev = list->last; 458*be771a7bSCy Schubert list->last->next = str; 459*be771a7bSCy Schubert } else { 460*be771a7bSCy Schubert str->prev = NULL; 461*be771a7bSCy Schubert list->first = str; 462*be771a7bSCy Schubert } 463*be771a7bSCy Schubert str->next = NULL; 464*be771a7bSCy Schubert list->last = str; 465*be771a7bSCy Schubert } 466*be771a7bSCy Schubert 467*be771a7bSCy Schubert /** delete the item from the list */ 468*be771a7bSCy Schubert static void 469*be771a7bSCy Schubert stream_list_delete(struct doq_client_stream_list* list, 470*be771a7bSCy Schubert struct doq_client_stream* str) 471*be771a7bSCy Schubert { 472*be771a7bSCy Schubert if(str->next) { 473*be771a7bSCy Schubert str->next->prev = str->prev; 474*be771a7bSCy Schubert } else { 475*be771a7bSCy Schubert list->last = str->prev; 476*be771a7bSCy Schubert } 477*be771a7bSCy Schubert if(str->prev) { 478*be771a7bSCy Schubert str->prev->next = str->next; 479*be771a7bSCy Schubert } else { 480*be771a7bSCy Schubert list->first = str->next; 481*be771a7bSCy Schubert } 482*be771a7bSCy Schubert str->prev = NULL; 483*be771a7bSCy Schubert str->next = NULL; 484*be771a7bSCy Schubert } 485*be771a7bSCy Schubert 486*be771a7bSCy Schubert /** move the item from list1 to list2 */ 487*be771a7bSCy Schubert static void 488*be771a7bSCy Schubert stream_list_move(struct doq_client_stream* str, 489*be771a7bSCy Schubert struct doq_client_stream_list* list1, 490*be771a7bSCy Schubert struct doq_client_stream_list* list2) 491*be771a7bSCy Schubert { 492*be771a7bSCy Schubert stream_list_delete(list1, str); 493*be771a7bSCy Schubert stream_list_append(list2, str); 494*be771a7bSCy Schubert } 495*be771a7bSCy Schubert 496*be771a7bSCy Schubert /** allocate stream data buffer, then answer length is complete */ 497*be771a7bSCy Schubert static void 498*be771a7bSCy Schubert client_stream_datalen_complete(struct doq_client_stream* str) 499*be771a7bSCy Schubert { 500*be771a7bSCy Schubert verbose(1, "answer length %d", (int)ntohs(str->answer_len)); 501*be771a7bSCy Schubert str->answer = sldns_buffer_new(ntohs(str->answer_len)); 502*be771a7bSCy Schubert if(!str->answer) 503*be771a7bSCy Schubert fatal_exit("sldns_buffer_new failed: out of memory"); 504*be771a7bSCy Schubert sldns_buffer_set_limit(str->answer, ntohs(str->answer_len)); 505*be771a7bSCy Schubert } 506*be771a7bSCy Schubert 507*be771a7bSCy Schubert /** print the answer rrs */ 508*be771a7bSCy Schubert static void 509*be771a7bSCy Schubert print_answer_rrs(uint8_t* pkt, size_t pktlen) 510*be771a7bSCy Schubert { 511*be771a7bSCy Schubert char buf[65535]; 512*be771a7bSCy Schubert char* str; 513*be771a7bSCy Schubert size_t str_len; 514*be771a7bSCy Schubert int i, qdcount, ancount; 515*be771a7bSCy Schubert uint8_t* data = pkt; 516*be771a7bSCy Schubert size_t data_len = pktlen; 517*be771a7bSCy Schubert int comprloop = 0; 518*be771a7bSCy Schubert if(data_len < LDNS_HEADER_SIZE) 519*be771a7bSCy Schubert return; 520*be771a7bSCy Schubert qdcount = LDNS_QDCOUNT(data); 521*be771a7bSCy Schubert ancount = LDNS_ANCOUNT(data); 522*be771a7bSCy Schubert data += LDNS_HEADER_SIZE; 523*be771a7bSCy Schubert data_len -= LDNS_HEADER_SIZE; 524*be771a7bSCy Schubert 525*be771a7bSCy Schubert for(i=0; i<qdcount; i++) { 526*be771a7bSCy Schubert str = buf; 527*be771a7bSCy Schubert str_len = sizeof(buf); 528*be771a7bSCy Schubert (void)sldns_wire2str_rrquestion_scan(&data, &data_len, 529*be771a7bSCy Schubert &str, &str_len, pkt, pktlen, &comprloop); 530*be771a7bSCy Schubert } 531*be771a7bSCy Schubert for(i=0; i<ancount; i++) { 532*be771a7bSCy Schubert str = buf; 533*be771a7bSCy Schubert str_len = sizeof(buf); 534*be771a7bSCy Schubert (void)sldns_wire2str_rr_scan(&data, &data_len, &str, &str_len, 535*be771a7bSCy Schubert pkt, pktlen, &comprloop); 536*be771a7bSCy Schubert /* terminate string */ 537*be771a7bSCy Schubert if(str_len == 0) 538*be771a7bSCy Schubert buf[sizeof(buf)-1] = 0; 539*be771a7bSCy Schubert else *str = 0; 540*be771a7bSCy Schubert printf("%s", buf); 541*be771a7bSCy Schubert } 542*be771a7bSCy Schubert } 543*be771a7bSCy Schubert 544*be771a7bSCy Schubert /** short output of answer, short error or rcode or answer section RRs. */ 545*be771a7bSCy Schubert static void 546*be771a7bSCy Schubert client_stream_print_short(struct doq_client_stream* str) 547*be771a7bSCy Schubert { 548*be771a7bSCy Schubert int rcode, ancount; 549*be771a7bSCy Schubert if(str->query_has_error) { 550*be771a7bSCy Schubert char* logs = client_stream_string(str); 551*be771a7bSCy Schubert printf("%s has error, there is no answer\n", logs); 552*be771a7bSCy Schubert free(logs); 553*be771a7bSCy Schubert return; 554*be771a7bSCy Schubert } 555*be771a7bSCy Schubert if(sldns_buffer_limit(str->answer) < LDNS_HEADER_SIZE) { 556*be771a7bSCy Schubert char* logs = client_stream_string(str); 557*be771a7bSCy Schubert printf("%s received short packet, smaller than header\n", 558*be771a7bSCy Schubert logs); 559*be771a7bSCy Schubert free(logs); 560*be771a7bSCy Schubert return; 561*be771a7bSCy Schubert } 562*be771a7bSCy Schubert rcode = LDNS_RCODE_WIRE(sldns_buffer_begin(str->answer)); 563*be771a7bSCy Schubert if(rcode != 0) { 564*be771a7bSCy Schubert char* logs = client_stream_string(str); 565*be771a7bSCy Schubert char rc[16]; 566*be771a7bSCy Schubert (void)sldns_wire2str_rcode_buf(rcode, rc, sizeof(rc)); 567*be771a7bSCy Schubert printf("%s rcode %s\n", logs, rc); 568*be771a7bSCy Schubert free(logs); 569*be771a7bSCy Schubert return; 570*be771a7bSCy Schubert } 571*be771a7bSCy Schubert ancount = LDNS_ANCOUNT(sldns_buffer_begin(str->answer)); 572*be771a7bSCy Schubert if(ancount == 0) { 573*be771a7bSCy Schubert char* logs = client_stream_string(str); 574*be771a7bSCy Schubert printf("%s nodata answer\n", logs); 575*be771a7bSCy Schubert free(logs); 576*be771a7bSCy Schubert return; 577*be771a7bSCy Schubert } 578*be771a7bSCy Schubert print_answer_rrs(sldns_buffer_begin(str->answer), 579*be771a7bSCy Schubert sldns_buffer_limit(str->answer)); 580*be771a7bSCy Schubert } 581*be771a7bSCy Schubert 582*be771a7bSCy Schubert /** print the stream output answer */ 583*be771a7bSCy Schubert static void 584*be771a7bSCy Schubert client_stream_print_long(struct doq_client_data* data, 585*be771a7bSCy Schubert struct doq_client_stream* str) 586*be771a7bSCy Schubert { 587*be771a7bSCy Schubert char* s; 588*be771a7bSCy Schubert if(str->query_has_error) { 589*be771a7bSCy Schubert char* logs = client_stream_string(str); 590*be771a7bSCy Schubert printf("%s has error, there is no answer\n", logs); 591*be771a7bSCy Schubert free(logs); 592*be771a7bSCy Schubert return; 593*be771a7bSCy Schubert } 594*be771a7bSCy Schubert s = sldns_wire2str_pkt(sldns_buffer_begin(str->answer), 595*be771a7bSCy Schubert sldns_buffer_limit(str->answer)); 596*be771a7bSCy Schubert printf("%s", (s?s:";sldns_wire2str_pkt failed\n")); 597*be771a7bSCy Schubert printf(";; SERVER: %s %d\n", data->svr, data->port); 598*be771a7bSCy Schubert free(s); 599*be771a7bSCy Schubert } 600*be771a7bSCy Schubert 601*be771a7bSCy Schubert /** the stream has completed the data */ 602*be771a7bSCy Schubert static void 603*be771a7bSCy Schubert client_stream_data_complete(struct doq_client_stream* str) 604*be771a7bSCy Schubert { 605*be771a7bSCy Schubert verbose(1, "received all answer content"); 606*be771a7bSCy Schubert if(verbosity > 0) { 607*be771a7bSCy Schubert char* logs = client_stream_string(str); 608*be771a7bSCy Schubert char* s; 609*be771a7bSCy Schubert log_buf(1, "received answer", str->answer); 610*be771a7bSCy Schubert s = sldns_wire2str_pkt(sldns_buffer_begin(str->answer), 611*be771a7bSCy Schubert sldns_buffer_limit(str->answer)); 612*be771a7bSCy Schubert if(!s) verbose(1, "could not sldns_wire2str_pkt"); 613*be771a7bSCy Schubert else verbose(1, "query %s received:\n%s", logs, s); 614*be771a7bSCy Schubert free(s); 615*be771a7bSCy Schubert free(logs); 616*be771a7bSCy Schubert } 617*be771a7bSCy Schubert str->answer_is_complete = 1; 618*be771a7bSCy Schubert } 619*be771a7bSCy Schubert 620*be771a7bSCy Schubert /** the stream has completed but with an error */ 621*be771a7bSCy Schubert static void 622*be771a7bSCy Schubert client_stream_answer_error(struct doq_client_stream* str) 623*be771a7bSCy Schubert { 624*be771a7bSCy Schubert if(verbosity > 0) { 625*be771a7bSCy Schubert char* logs = client_stream_string(str); 626*be771a7bSCy Schubert if(str->answer) 627*be771a7bSCy Schubert verbose(1, "query %s has an error. received %d/%d bytes.", 628*be771a7bSCy Schubert logs, (int)sldns_buffer_position(str->answer), 629*be771a7bSCy Schubert (int)sldns_buffer_limit(str->answer)); 630*be771a7bSCy Schubert else 631*be771a7bSCy Schubert verbose(1, "query %s has an error. received no data.", 632*be771a7bSCy Schubert logs); 633*be771a7bSCy Schubert free(logs); 634*be771a7bSCy Schubert } 635*be771a7bSCy Schubert str->query_has_error = 1; 636*be771a7bSCy Schubert } 637*be771a7bSCy Schubert 638*be771a7bSCy Schubert /** receive data for a stream */ 639*be771a7bSCy Schubert static void 640*be771a7bSCy Schubert client_stream_recv_data(struct doq_client_stream* str, const uint8_t* data, 641*be771a7bSCy Schubert size_t datalen) 642*be771a7bSCy Schubert { 643*be771a7bSCy Schubert int got_data = 0; 644*be771a7bSCy Schubert /* read the tcplength uint16_t at the start of the DNS message */ 645*be771a7bSCy Schubert if(str->nread < 2) { 646*be771a7bSCy Schubert size_t to_move = datalen; 647*be771a7bSCy Schubert if(datalen > 2-str->nread) 648*be771a7bSCy Schubert to_move = 2-str->nread; 649*be771a7bSCy Schubert memmove(((uint8_t*)&str->answer_len)+str->nread, data, 650*be771a7bSCy Schubert to_move); 651*be771a7bSCy Schubert str->nread += to_move; 652*be771a7bSCy Schubert data += to_move; 653*be771a7bSCy Schubert datalen -= to_move; 654*be771a7bSCy Schubert if(str->nread == 2) { 655*be771a7bSCy Schubert /* we can allocate the data buffer */ 656*be771a7bSCy Schubert client_stream_datalen_complete(str); 657*be771a7bSCy Schubert } 658*be771a7bSCy Schubert } 659*be771a7bSCy Schubert /* if we have data bytes */ 660*be771a7bSCy Schubert if(datalen > 0) { 661*be771a7bSCy Schubert size_t to_write = datalen; 662*be771a7bSCy Schubert if(datalen > sldns_buffer_remaining(str->answer)) 663*be771a7bSCy Schubert to_write = sldns_buffer_remaining(str->answer); 664*be771a7bSCy Schubert if(to_write > 0) { 665*be771a7bSCy Schubert sldns_buffer_write(str->answer, data, to_write); 666*be771a7bSCy Schubert str->nread += to_write; 667*be771a7bSCy Schubert data += to_write; 668*be771a7bSCy Schubert datalen -= to_write; 669*be771a7bSCy Schubert got_data = 1; 670*be771a7bSCy Schubert } 671*be771a7bSCy Schubert } 672*be771a7bSCy Schubert /* extra received bytes after end? */ 673*be771a7bSCy Schubert if(datalen > 0) { 674*be771a7bSCy Schubert verbose(1, "extra bytes after end of DNS length"); 675*be771a7bSCy Schubert if(verbosity > 0) 676*be771a7bSCy Schubert log_hex("extradata", (void*)data, datalen); 677*be771a7bSCy Schubert } 678*be771a7bSCy Schubert /* are we done with it? */ 679*be771a7bSCy Schubert if(got_data && str->nread >= (size_t)(ntohs(str->answer_len))+2) { 680*be771a7bSCy Schubert client_stream_data_complete(str); 681*be771a7bSCy Schubert } 682*be771a7bSCy Schubert } 683*be771a7bSCy Schubert 684*be771a7bSCy Schubert /** receive FIN from remote end on client stream, no more data to be 685*be771a7bSCy Schubert * received on the stream. */ 686*be771a7bSCy Schubert static void 687*be771a7bSCy Schubert client_stream_recv_fin(struct doq_client_data* data, 688*be771a7bSCy Schubert struct doq_client_stream* str, int is_fin) 689*be771a7bSCy Schubert { 690*be771a7bSCy Schubert if(verbosity > 0) { 691*be771a7bSCy Schubert char* logs = client_stream_string(str); 692*be771a7bSCy Schubert if(is_fin) 693*be771a7bSCy Schubert verbose(1, "query %s: received FIN from remote", logs); 694*be771a7bSCy Schubert else 695*be771a7bSCy Schubert verbose(1, "query %s: stream reset from remote", logs); 696*be771a7bSCy Schubert free(logs); 697*be771a7bSCy Schubert } 698*be771a7bSCy Schubert if(str->write_is_done) 699*be771a7bSCy Schubert stream_list_move(str, data->query_list_receive, 700*be771a7bSCy Schubert data->query_list_stop); 701*be771a7bSCy Schubert else 702*be771a7bSCy Schubert stream_list_move(str, data->query_list_send, 703*be771a7bSCy Schubert data->query_list_stop); 704*be771a7bSCy Schubert if(!str->answer_is_complete) { 705*be771a7bSCy Schubert client_stream_answer_error(str); 706*be771a7bSCy Schubert } 707*be771a7bSCy Schubert str->query_is_done = 1; 708*be771a7bSCy Schubert if(data->quiet) 709*be771a7bSCy Schubert client_stream_print_short(str); 710*be771a7bSCy Schubert else client_stream_print_long(data, str); 711*be771a7bSCy Schubert if(data->query_list_send->first==NULL && 712*be771a7bSCy Schubert data->query_list_receive->first==NULL) 713*be771a7bSCy Schubert disconnect(data); 714*be771a7bSCy Schubert } 715*be771a7bSCy Schubert 716*be771a7bSCy Schubert /** fill a buffer with random data */ 717*be771a7bSCy Schubert static void fill_rand(struct ub_randstate* rnd, uint8_t* buf, size_t len) 718*be771a7bSCy Schubert { 719*be771a7bSCy Schubert if(RAND_bytes(buf, len) != 1) { 720*be771a7bSCy Schubert size_t i; 721*be771a7bSCy Schubert for(i=0; i<len; i++) 722*be771a7bSCy Schubert buf[i] = ub_random(rnd)&0xff; 723*be771a7bSCy Schubert } 724*be771a7bSCy Schubert } 725*be771a7bSCy Schubert 726*be771a7bSCy Schubert /** create the static secret */ 727*be771a7bSCy Schubert static void generate_static_secret(struct doq_client_data* data, size_t len) 728*be771a7bSCy Schubert { 729*be771a7bSCy Schubert data->static_secret_data = malloc(len); 730*be771a7bSCy Schubert if(!data->static_secret_data) 731*be771a7bSCy Schubert fatal_exit("malloc failed: out of memory"); 732*be771a7bSCy Schubert data->static_secret_size = len; 733*be771a7bSCy Schubert fill_rand(data->rnd, data->static_secret_data, len); 734*be771a7bSCy Schubert } 735*be771a7bSCy Schubert 736*be771a7bSCy Schubert /** fill cid structure with random data */ 737*be771a7bSCy Schubert static void cid_randfill(struct ngtcp2_cid* cid, size_t datalen, 738*be771a7bSCy Schubert struct ub_randstate* rnd) 739*be771a7bSCy Schubert { 740*be771a7bSCy Schubert uint8_t buf[32]; 741*be771a7bSCy Schubert if(datalen > sizeof(buf)) 742*be771a7bSCy Schubert datalen = sizeof(buf); 743*be771a7bSCy Schubert fill_rand(rnd, buf, datalen); 744*be771a7bSCy Schubert ngtcp2_cid_init(cid, buf, datalen); 745*be771a7bSCy Schubert } 746*be771a7bSCy Schubert 747*be771a7bSCy Schubert /** send buf on the client stream */ 748*be771a7bSCy Schubert static int 749*be771a7bSCy Schubert client_bidi_stream(struct doq_client_data* data, int64_t* ret_stream_id, 750*be771a7bSCy Schubert void* stream_user_data) 751*be771a7bSCy Schubert { 752*be771a7bSCy Schubert int64_t stream_id; 753*be771a7bSCy Schubert int rv; 754*be771a7bSCy Schubert 755*be771a7bSCy Schubert /* open new bidirectional stream */ 756*be771a7bSCy Schubert rv = ngtcp2_conn_open_bidi_stream(data->conn, &stream_id, 757*be771a7bSCy Schubert stream_user_data); 758*be771a7bSCy Schubert if(rv != 0) { 759*be771a7bSCy Schubert if(rv == NGTCP2_ERR_STREAM_ID_BLOCKED) { 760*be771a7bSCy Schubert /* no bidi stream count for this new stream */ 761*be771a7bSCy Schubert return 0; 762*be771a7bSCy Schubert } 763*be771a7bSCy Schubert fatal_exit("could not ngtcp2_conn_open_bidi_stream: %s", 764*be771a7bSCy Schubert ngtcp2_strerror(rv)); 765*be771a7bSCy Schubert } 766*be771a7bSCy Schubert *ret_stream_id = stream_id; 767*be771a7bSCy Schubert return 1; 768*be771a7bSCy Schubert } 769*be771a7bSCy Schubert 770*be771a7bSCy Schubert /** See if we can start query streams, by creating bidirectional streams 771*be771a7bSCy Schubert * on the QUIC transport for them. */ 772*be771a7bSCy Schubert static void 773*be771a7bSCy Schubert query_streams_start(struct doq_client_data* data) 774*be771a7bSCy Schubert { 775*be771a7bSCy Schubert while(data->query_list_start->first) { 776*be771a7bSCy Schubert struct doq_client_stream* str = data->query_list_start->first; 777*be771a7bSCy Schubert int64_t stream_id = 0; 778*be771a7bSCy Schubert if(!client_bidi_stream(data, &stream_id, str)) { 779*be771a7bSCy Schubert /* no more bidi streams allowed */ 780*be771a7bSCy Schubert break; 781*be771a7bSCy Schubert } 782*be771a7bSCy Schubert if(verbosity > 0) { 783*be771a7bSCy Schubert char* logs = client_stream_string(str); 784*be771a7bSCy Schubert verbose(1, "query %s start on bidi stream id %lld", 785*be771a7bSCy Schubert logs, (long long int)stream_id); 786*be771a7bSCy Schubert free(logs); 787*be771a7bSCy Schubert } 788*be771a7bSCy Schubert /* setup the stream to start */ 789*be771a7bSCy Schubert client_stream_start_setup(str, stream_id); 790*be771a7bSCy Schubert /* move the query entry to the send list to write it */ 791*be771a7bSCy Schubert stream_list_move(str, data->query_list_start, 792*be771a7bSCy Schubert data->query_list_send); 793*be771a7bSCy Schubert } 794*be771a7bSCy Schubert } 795*be771a7bSCy Schubert 796*be771a7bSCy Schubert /** the rand callback routine from ngtcp2 */ 797*be771a7bSCy Schubert static void rand_cb(uint8_t* dest, size_t destlen, 798*be771a7bSCy Schubert const ngtcp2_rand_ctx* rand_ctx) 799*be771a7bSCy Schubert { 800*be771a7bSCy Schubert struct ub_randstate* rnd = (struct ub_randstate*) 801*be771a7bSCy Schubert rand_ctx->native_handle; 802*be771a7bSCy Schubert fill_rand(rnd, dest, destlen); 803*be771a7bSCy Schubert } 804*be771a7bSCy Schubert 805*be771a7bSCy Schubert /** the get_new_connection_id callback routine from ngtcp2 */ 806*be771a7bSCy Schubert static int get_new_connection_id_cb(struct ngtcp2_conn* ATTR_UNUSED(conn), 807*be771a7bSCy Schubert struct ngtcp2_cid* cid, uint8_t* token, size_t cidlen, void* user_data) 808*be771a7bSCy Schubert { 809*be771a7bSCy Schubert struct doq_client_data* data = (struct doq_client_data*)user_data; 810*be771a7bSCy Schubert cid_randfill(cid, cidlen, data->rnd); 811*be771a7bSCy Schubert if(ngtcp2_crypto_generate_stateless_reset_token(token, 812*be771a7bSCy Schubert data->static_secret_data, data->static_secret_size, cid) != 0) 813*be771a7bSCy Schubert return NGTCP2_ERR_CALLBACK_FAILURE; 814*be771a7bSCy Schubert return 0; 815*be771a7bSCy Schubert } 816*be771a7bSCy Schubert 817*be771a7bSCy Schubert /** handle that early data is rejected */ 818*be771a7bSCy Schubert static void 819*be771a7bSCy Schubert early_data_is_rejected(struct doq_client_data* data) 820*be771a7bSCy Schubert { 821*be771a7bSCy Schubert int rv; 822*be771a7bSCy Schubert verbose(1, "early data was rejected by the server"); 823*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_TLS_EARLY_DATA_REJECTED 824*be771a7bSCy Schubert rv = ngtcp2_conn_tls_early_data_rejected(data->conn); 825*be771a7bSCy Schubert #else 826*be771a7bSCy Schubert rv = ngtcp2_conn_early_data_rejected(data->conn); 827*be771a7bSCy Schubert #endif 828*be771a7bSCy Schubert if(rv != 0) { 829*be771a7bSCy Schubert log_err("ngtcp2_conn_early_data_rejected failed: %s", 830*be771a7bSCy Schubert ngtcp2_strerror(rv)); 831*be771a7bSCy Schubert return; 832*be771a7bSCy Schubert } 833*be771a7bSCy Schubert /* move the streams back to the start state */ 834*be771a7bSCy Schubert while(data->query_list_send->first) { 835*be771a7bSCy Schubert struct doq_client_stream* str = data->query_list_send->first; 836*be771a7bSCy Schubert /* move it back to the start list */ 837*be771a7bSCy Schubert stream_list_move(str, data->query_list_send, 838*be771a7bSCy Schubert data->query_list_start); 839*be771a7bSCy Schubert str->has_stream = 0; 840*be771a7bSCy Schubert /* remove stream id */ 841*be771a7bSCy Schubert str->stream_id = 0; 842*be771a7bSCy Schubert /* initialise other members, in case they are altered, 843*be771a7bSCy Schubert * but unlikely, because early streams are rejected. */ 844*be771a7bSCy Schubert str->nwrite = 0; 845*be771a7bSCy Schubert str->nread = 0; 846*be771a7bSCy Schubert str->answer_len = 0; 847*be771a7bSCy Schubert str->query_is_done = 0; 848*be771a7bSCy Schubert str->answer_is_complete = 0; 849*be771a7bSCy Schubert str->query_has_error = 0; 850*be771a7bSCy Schubert if(str->answer) { 851*be771a7bSCy Schubert sldns_buffer_free(str->answer); 852*be771a7bSCy Schubert str->answer = NULL; 853*be771a7bSCy Schubert } 854*be771a7bSCy Schubert } 855*be771a7bSCy Schubert } 856*be771a7bSCy Schubert 857*be771a7bSCy Schubert /** the handshake completed callback from ngtcp2 */ 858*be771a7bSCy Schubert static int 859*be771a7bSCy Schubert handshake_completed(ngtcp2_conn* ATTR_UNUSED(conn), void* user_data) 860*be771a7bSCy Schubert { 861*be771a7bSCy Schubert struct doq_client_data* data = (struct doq_client_data*)user_data; 862*be771a7bSCy Schubert verbose(1, "handshake_completed callback"); 863*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_max_data_left is %d", 864*be771a7bSCy Schubert (int)ngtcp2_conn_get_max_data_left(data->conn)); 865*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI 866*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d", 867*be771a7bSCy Schubert (int)ngtcp2_conn_get_max_local_streams_uni(data->conn)); 868*be771a7bSCy Schubert #endif 869*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_streams_uni_left is %d", 870*be771a7bSCy Schubert (int)ngtcp2_conn_get_streams_uni_left(data->conn)); 871*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d", 872*be771a7bSCy Schubert (int)ngtcp2_conn_get_streams_bidi_left(data->conn)); 873*be771a7bSCy Schubert verbose(1, "negotiated cipher name is %s", 874*be771a7bSCy Schubert SSL_get_cipher_name(data->ssl)); 875*be771a7bSCy Schubert if(verbosity > 0) { 876*be771a7bSCy Schubert const unsigned char* alpn = NULL; 877*be771a7bSCy Schubert unsigned int alpnlen = 0; 878*be771a7bSCy Schubert char alpnstr[128]; 879*be771a7bSCy Schubert SSL_get0_alpn_selected(data->ssl, &alpn, &alpnlen); 880*be771a7bSCy Schubert if(alpnlen > sizeof(alpnstr)-1) 881*be771a7bSCy Schubert alpnlen = sizeof(alpnstr)-1; 882*be771a7bSCy Schubert memmove(alpnstr, alpn, alpnlen); 883*be771a7bSCy Schubert alpnstr[alpnlen]=0; 884*be771a7bSCy Schubert verbose(1, "negotiated ALPN is '%s'", alpnstr); 885*be771a7bSCy Schubert } 886*be771a7bSCy Schubert /* The SSL_get_early_data_status call works after the handshake 887*be771a7bSCy Schubert * completes. */ 888*be771a7bSCy Schubert if(data->early_data_enabled) { 889*be771a7bSCy Schubert if(SSL_get_early_data_status(data->ssl) != 890*be771a7bSCy Schubert SSL_EARLY_DATA_ACCEPTED) { 891*be771a7bSCy Schubert early_data_is_rejected(data); 892*be771a7bSCy Schubert } else { 893*be771a7bSCy Schubert verbose(1, "early data was accepted by the server"); 894*be771a7bSCy Schubert } 895*be771a7bSCy Schubert } 896*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 897*be771a7bSCy Schubert if(data->transport_file) { 898*be771a7bSCy Schubert early_data_write_transport(data); 899*be771a7bSCy Schubert } 900*be771a7bSCy Schubert #endif 901*be771a7bSCy Schubert return 0; 902*be771a7bSCy Schubert } 903*be771a7bSCy Schubert 904*be771a7bSCy Schubert /** the extend_max_local_streams_bidi callback from ngtcp2 */ 905*be771a7bSCy Schubert static int 906*be771a7bSCy Schubert extend_max_local_streams_bidi(ngtcp2_conn* ATTR_UNUSED(conn), 907*be771a7bSCy Schubert uint64_t max_streams, void* user_data) 908*be771a7bSCy Schubert { 909*be771a7bSCy Schubert struct doq_client_data* data = (struct doq_client_data*)user_data; 910*be771a7bSCy Schubert verbose(1, "extend_max_local_streams_bidi callback, %d max_streams", 911*be771a7bSCy Schubert (int)max_streams); 912*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_max_data_left is %d", 913*be771a7bSCy Schubert (int)ngtcp2_conn_get_max_data_left(data->conn)); 914*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI 915*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d", 916*be771a7bSCy Schubert (int)ngtcp2_conn_get_max_local_streams_uni(data->conn)); 917*be771a7bSCy Schubert #endif 918*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_streams_uni_left is %d", 919*be771a7bSCy Schubert (int)ngtcp2_conn_get_streams_uni_left(data->conn)); 920*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d", 921*be771a7bSCy Schubert (int)ngtcp2_conn_get_streams_bidi_left(data->conn)); 922*be771a7bSCy Schubert query_streams_start(data); 923*be771a7bSCy Schubert return 0; 924*be771a7bSCy Schubert } 925*be771a7bSCy Schubert 926*be771a7bSCy Schubert /** the recv_stream_data callback from ngtcp2 */ 927*be771a7bSCy Schubert static int 928*be771a7bSCy Schubert recv_stream_data(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags, 929*be771a7bSCy Schubert int64_t stream_id, uint64_t offset, const uint8_t* data, 930*be771a7bSCy Schubert size_t datalen, void* user_data, void* stream_user_data) 931*be771a7bSCy Schubert { 932*be771a7bSCy Schubert struct doq_client_data* doqdata = (struct doq_client_data*)user_data; 933*be771a7bSCy Schubert struct doq_client_stream* str = (struct doq_client_stream*) 934*be771a7bSCy Schubert stream_user_data; 935*be771a7bSCy Schubert verbose(1, "recv_stream_data stream %d offset %d datalen %d%s%s", 936*be771a7bSCy Schubert (int)stream_id, (int)offset, (int)datalen, 937*be771a7bSCy Schubert ((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0?" FIN":""), 938*be771a7bSCy Schubert #ifdef NGTCP2_STREAM_DATA_FLAG_0RTT 939*be771a7bSCy Schubert ((flags&NGTCP2_STREAM_DATA_FLAG_0RTT)!=0?" 0RTT":"") 940*be771a7bSCy Schubert #else 941*be771a7bSCy Schubert ((flags&NGTCP2_STREAM_DATA_FLAG_EARLY)!=0?" EARLY":"") 942*be771a7bSCy Schubert #endif 943*be771a7bSCy Schubert ); 944*be771a7bSCy Schubert if(verbosity > 0) 945*be771a7bSCy Schubert log_hex("data", (void*)data, datalen); 946*be771a7bSCy Schubert if(verbosity > 0) { 947*be771a7bSCy Schubert char* logs = client_stream_string(str); 948*be771a7bSCy Schubert verbose(1, "the stream_user_data is %s stream id %d, nread %d", 949*be771a7bSCy Schubert logs, (int)str->stream_id, (int)str->nread); 950*be771a7bSCy Schubert free(logs); 951*be771a7bSCy Schubert } 952*be771a7bSCy Schubert 953*be771a7bSCy Schubert /* append the data, if there is data */ 954*be771a7bSCy Schubert if(datalen > 0) { 955*be771a7bSCy Schubert client_stream_recv_data(str, data, datalen); 956*be771a7bSCy Schubert } 957*be771a7bSCy Schubert if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) { 958*be771a7bSCy Schubert client_stream_recv_fin(doqdata, str, 1); 959*be771a7bSCy Schubert } 960*be771a7bSCy Schubert ngtcp2_conn_extend_max_stream_offset(doqdata->conn, stream_id, datalen); 961*be771a7bSCy Schubert ngtcp2_conn_extend_max_offset(doqdata->conn, datalen); 962*be771a7bSCy Schubert return 0; 963*be771a7bSCy Schubert } 964*be771a7bSCy Schubert 965*be771a7bSCy Schubert /** the stream reset callback from ngtcp2 */ 966*be771a7bSCy Schubert static int 967*be771a7bSCy Schubert stream_reset(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id, 968*be771a7bSCy Schubert uint64_t final_size, uint64_t app_error_code, void* user_data, 969*be771a7bSCy Schubert void* stream_user_data) 970*be771a7bSCy Schubert { 971*be771a7bSCy Schubert struct doq_client_data* doqdata = (struct doq_client_data*)user_data; 972*be771a7bSCy Schubert struct doq_client_stream* str = (struct doq_client_stream*) 973*be771a7bSCy Schubert stream_user_data; 974*be771a7bSCy Schubert verbose(1, "stream reset for stream %d final size %d app error code %d", 975*be771a7bSCy Schubert (int)stream_id, (int)final_size, (int)app_error_code); 976*be771a7bSCy Schubert client_stream_recv_fin(doqdata, str, 0); 977*be771a7bSCy Schubert return 0; 978*be771a7bSCy Schubert } 979*be771a7bSCy Schubert 980*be771a7bSCy Schubert /** copy sockaddr into ngtcp2 addr */ 981*be771a7bSCy Schubert static void 982*be771a7bSCy Schubert copy_ngaddr(struct ngtcp2_addr* ngaddr, struct sockaddr_storage* addr, 983*be771a7bSCy Schubert socklen_t addrlen) 984*be771a7bSCy Schubert { 985*be771a7bSCy Schubert if(addr_is_ip6(addr, addrlen)) { 986*be771a7bSCy Schubert #if defined(NGTCP2_USE_GENERIC_SOCKADDR) || defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR) 987*be771a7bSCy Schubert struct sockaddr_in* i6 = (struct sockaddr_in6*)addr; 988*be771a7bSCy Schubert struct ngtcp2_sockaddr_in6 a6; 989*be771a7bSCy Schubert ngaddr->addr = calloc(1, sizeof(a6)); 990*be771a7bSCy Schubert if(!ngaddr->addr) fatal_exit("calloc failed: out of memory"); 991*be771a7bSCy Schubert ngaddr->addrlen = sizeof(a6); 992*be771a7bSCy Schubert memset(&a6, 0, sizeof(a6)); 993*be771a7bSCy Schubert a6.sin6_family = i6->sin6_family; 994*be771a7bSCy Schubert a6.sin6_port = i6->sin6_port; 995*be771a7bSCy Schubert a6.sin6_flowinfo = i6->sin6_flowinfo; 996*be771a7bSCy Schubert memmove(&a6.sin6_addr, i6->sin6_addr, sizeof(a6.sin6_addr); 997*be771a7bSCy Schubert a6.sin6_scope_id = i6->sin6_scope_id; 998*be771a7bSCy Schubert memmove(ngaddr->addr, &a6, sizeof(a6)); 999*be771a7bSCy Schubert #else 1000*be771a7bSCy Schubert ngaddr->addr = (ngtcp2_sockaddr*)addr; 1001*be771a7bSCy Schubert ngaddr->addrlen = addrlen; 1002*be771a7bSCy Schubert #endif 1003*be771a7bSCy Schubert } else { 1004*be771a7bSCy Schubert #ifdef NGTCP2_USE_GENERIC_SOCKADDR 1005*be771a7bSCy Schubert struct sockaddr_in* i4 = (struct sockaddr_in*)addr; 1006*be771a7bSCy Schubert struct ngtcp2_sockaddr_in a4; 1007*be771a7bSCy Schubert ngaddr->addr = calloc(1, sizeof(a4)); 1008*be771a7bSCy Schubert if(!ngaddr->addr) fatal_exit("calloc failed: out of memory"); 1009*be771a7bSCy Schubert ngaddr->addrlen = sizeof(a4); 1010*be771a7bSCy Schubert memset(&a4, 0, sizeof(a4)); 1011*be771a7bSCy Schubert a4.sin_family = i4->sin_family; 1012*be771a7bSCy Schubert a4.sin_port = i4->sin_port; 1013*be771a7bSCy Schubert memmove(&a4.sin_addr, i4->sin_addr, sizeof(a4.sin_addr); 1014*be771a7bSCy Schubert memmove(ngaddr->addr, &a4, sizeof(a4)); 1015*be771a7bSCy Schubert #else 1016*be771a7bSCy Schubert ngaddr->addr = (ngtcp2_sockaddr*)addr; 1017*be771a7bSCy Schubert ngaddr->addrlen = addrlen; 1018*be771a7bSCy Schubert #endif 1019*be771a7bSCy Schubert } 1020*be771a7bSCy Schubert } 1021*be771a7bSCy Schubert 1022*be771a7bSCy Schubert /** debug log printf for ngtcp2 connections */ 1023*be771a7bSCy Schubert static void log_printf_for_doq(void* ATTR_UNUSED(user_data), 1024*be771a7bSCy Schubert const char* fmt, ...) 1025*be771a7bSCy Schubert { 1026*be771a7bSCy Schubert va_list ap; 1027*be771a7bSCy Schubert va_start(ap, fmt); 1028*be771a7bSCy Schubert fprintf(stderr, "libngtcp2: "); 1029*be771a7bSCy Schubert vfprintf(stderr, fmt, ap); 1030*be771a7bSCy Schubert va_end(ap); 1031*be771a7bSCy Schubert fprintf(stderr, "\n"); 1032*be771a7bSCy Schubert } 1033*be771a7bSCy Schubert 1034*be771a7bSCy Schubert /** get a timestamp in nanoseconds */ 1035*be771a7bSCy Schubert static ngtcp2_tstamp get_timestamp_nanosec(void) 1036*be771a7bSCy Schubert { 1037*be771a7bSCy Schubert #ifdef CLOCK_REALTIME 1038*be771a7bSCy Schubert struct timespec tp; 1039*be771a7bSCy Schubert memset(&tp, 0, sizeof(tp)); 1040*be771a7bSCy Schubert #ifdef CLOCK_MONOTONIC 1041*be771a7bSCy Schubert if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { 1042*be771a7bSCy Schubert #endif 1043*be771a7bSCy Schubert if(clock_gettime(CLOCK_REALTIME, &tp) == -1) { 1044*be771a7bSCy Schubert log_err("clock_gettime failed: %s", strerror(errno)); 1045*be771a7bSCy Schubert } 1046*be771a7bSCy Schubert #ifdef CLOCK_MONOTONIC 1047*be771a7bSCy Schubert } 1048*be771a7bSCy Schubert #endif 1049*be771a7bSCy Schubert return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) + 1050*be771a7bSCy Schubert ((uint64_t)tp.tv_nsec); 1051*be771a7bSCy Schubert #else 1052*be771a7bSCy Schubert struct timeval tv; 1053*be771a7bSCy Schubert if(gettimeofday(&tv, NULL) < 0) { 1054*be771a7bSCy Schubert log_err("gettimeofday failed: %s", strerror(errno)); 1055*be771a7bSCy Schubert } 1056*be771a7bSCy Schubert return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) + 1057*be771a7bSCy Schubert ((uint64_t)tv.tv_usec)*((uint64_t)1000); 1058*be771a7bSCy Schubert #endif /* CLOCK_REALTIME */ 1059*be771a7bSCy Schubert } 1060*be771a7bSCy Schubert 1061*be771a7bSCy Schubert /** create ngtcp2 client connection and set up. */ 1062*be771a7bSCy Schubert static struct ngtcp2_conn* conn_client_setup(struct doq_client_data* data) 1063*be771a7bSCy Schubert { 1064*be771a7bSCy Schubert struct ngtcp2_conn* conn = NULL; 1065*be771a7bSCy Schubert int rv; 1066*be771a7bSCy Schubert struct ngtcp2_cid dcid, scid; 1067*be771a7bSCy Schubert struct ngtcp2_path path; 1068*be771a7bSCy Schubert uint32_t client_chosen_version = NGTCP2_PROTO_VER_V1; 1069*be771a7bSCy Schubert struct ngtcp2_callbacks cbs; 1070*be771a7bSCy Schubert struct ngtcp2_settings settings; 1071*be771a7bSCy Schubert struct ngtcp2_transport_params params; 1072*be771a7bSCy Schubert 1073*be771a7bSCy Schubert memset(&cbs, 0, sizeof(cbs)); 1074*be771a7bSCy Schubert memset(&settings, 0, sizeof(settings)); 1075*be771a7bSCy Schubert memset(¶ms, 0, sizeof(params)); 1076*be771a7bSCy Schubert memset(&dcid, 0, sizeof(dcid)); 1077*be771a7bSCy Schubert memset(&scid, 0, sizeof(scid)); 1078*be771a7bSCy Schubert memset(&path, 0, sizeof(path)); 1079*be771a7bSCy Schubert 1080*be771a7bSCy Schubert data->quic_version = client_chosen_version; 1081*be771a7bSCy Schubert ngtcp2_settings_default(&settings); 1082*be771a7bSCy Schubert if(str_is_ip6(data->svr)) { 1083*be771a7bSCy Schubert #ifdef HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE 1084*be771a7bSCy Schubert settings.max_tx_udp_payload_size = 1232; 1085*be771a7bSCy Schubert #else 1086*be771a7bSCy Schubert settings.max_udp_payload_size = 1232; 1087*be771a7bSCy Schubert #endif 1088*be771a7bSCy Schubert } 1089*be771a7bSCy Schubert settings.rand_ctx.native_handle = data->rnd; 1090*be771a7bSCy Schubert if(verbosity > 0) { 1091*be771a7bSCy Schubert /* make debug logs */ 1092*be771a7bSCy Schubert settings.log_printf = log_printf_for_doq; 1093*be771a7bSCy Schubert } 1094*be771a7bSCy Schubert settings.initial_ts = get_timestamp_nanosec(); 1095*be771a7bSCy Schubert ngtcp2_transport_params_default(¶ms); 1096*be771a7bSCy Schubert params.initial_max_stream_data_bidi_local = 256*1024; 1097*be771a7bSCy Schubert params.initial_max_stream_data_bidi_remote = 256*1024; 1098*be771a7bSCy Schubert params.initial_max_stream_data_uni = 256*1024; 1099*be771a7bSCy Schubert params.initial_max_data = 1024*1024; 1100*be771a7bSCy Schubert params.initial_max_streams_bidi = 0; 1101*be771a7bSCy Schubert params.initial_max_streams_uni = 100; 1102*be771a7bSCy Schubert params.max_idle_timeout = 30*NGTCP2_SECONDS; 1103*be771a7bSCy Schubert params.active_connection_id_limit = 7; 1104*be771a7bSCy Schubert cid_randfill(&dcid, 16, data->rnd); 1105*be771a7bSCy Schubert cid_randfill(&scid, 16, data->rnd); 1106*be771a7bSCy Schubert cbs.client_initial = ngtcp2_crypto_client_initial_cb; 1107*be771a7bSCy Schubert cbs.recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb; 1108*be771a7bSCy Schubert cbs.encrypt = ngtcp2_crypto_encrypt_cb; 1109*be771a7bSCy Schubert cbs.decrypt = ngtcp2_crypto_decrypt_cb; 1110*be771a7bSCy Schubert cbs.hp_mask = ngtcp2_crypto_hp_mask_cb; 1111*be771a7bSCy Schubert cbs.recv_retry = ngtcp2_crypto_recv_retry_cb; 1112*be771a7bSCy Schubert cbs.update_key = ngtcp2_crypto_update_key_cb; 1113*be771a7bSCy Schubert cbs.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb; 1114*be771a7bSCy Schubert cbs.delete_crypto_cipher_ctx = 1115*be771a7bSCy Schubert ngtcp2_crypto_delete_crypto_cipher_ctx_cb; 1116*be771a7bSCy Schubert cbs.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb; 1117*be771a7bSCy Schubert cbs.version_negotiation = ngtcp2_crypto_version_negotiation_cb; 1118*be771a7bSCy Schubert cbs.get_new_connection_id = get_new_connection_id_cb; 1119*be771a7bSCy Schubert cbs.handshake_completed = handshake_completed; 1120*be771a7bSCy Schubert cbs.extend_max_local_streams_bidi = extend_max_local_streams_bidi; 1121*be771a7bSCy Schubert cbs.rand = rand_cb; 1122*be771a7bSCy Schubert cbs.recv_stream_data = recv_stream_data; 1123*be771a7bSCy Schubert cbs.stream_reset = stream_reset; 1124*be771a7bSCy Schubert copy_ngaddr(&path.local, &data->local_addr, data->local_addr_len); 1125*be771a7bSCy Schubert copy_ngaddr(&path.remote, &data->dest_addr, data->dest_addr_len); 1126*be771a7bSCy Schubert 1127*be771a7bSCy Schubert rv = ngtcp2_conn_client_new(&conn, &dcid, &scid, &path, 1128*be771a7bSCy Schubert client_chosen_version, &cbs, &settings, ¶ms, 1129*be771a7bSCy Schubert NULL, /* ngtcp2_mem allocator, use default */ 1130*be771a7bSCy Schubert data /* callback argument */); 1131*be771a7bSCy Schubert if(!conn) fatal_exit("could not ngtcp2_conn_client_new: %s", 1132*be771a7bSCy Schubert ngtcp2_strerror(rv)); 1133*be771a7bSCy Schubert data->cc_algo = settings.cc_algo; 1134*be771a7bSCy Schubert return conn; 1135*be771a7bSCy Schubert } 1136*be771a7bSCy Schubert 1137*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS 1138*be771a7bSCy Schubert /** write the transport file */ 1139*be771a7bSCy Schubert static void 1140*be771a7bSCy Schubert transport_file_write(const char* file, struct ngtcp2_transport_params* params) 1141*be771a7bSCy Schubert { 1142*be771a7bSCy Schubert FILE* out; 1143*be771a7bSCy Schubert out = fopen(file, "w"); 1144*be771a7bSCy Schubert if(!out) { 1145*be771a7bSCy Schubert perror(file); 1146*be771a7bSCy Schubert return; 1147*be771a7bSCy Schubert } 1148*be771a7bSCy Schubert fprintf(out, "initial_max_streams_bidi=%u\n", 1149*be771a7bSCy Schubert (unsigned)params->initial_max_streams_bidi); 1150*be771a7bSCy Schubert fprintf(out, "initial_max_streams_uni=%u\n", 1151*be771a7bSCy Schubert (unsigned)params->initial_max_streams_uni); 1152*be771a7bSCy Schubert fprintf(out, "initial_max_stream_data_bidi_local=%u\n", 1153*be771a7bSCy Schubert (unsigned)params->initial_max_stream_data_bidi_local); 1154*be771a7bSCy Schubert fprintf(out, "initial_max_stream_data_bidi_remote=%u\n", 1155*be771a7bSCy Schubert (unsigned)params->initial_max_stream_data_bidi_remote); 1156*be771a7bSCy Schubert fprintf(out, "initial_max_stream_data_uni=%u\n", 1157*be771a7bSCy Schubert (unsigned)params->initial_max_stream_data_uni); 1158*be771a7bSCy Schubert fprintf(out, "initial_max_data=%u\n", 1159*be771a7bSCy Schubert (unsigned)params->initial_max_data); 1160*be771a7bSCy Schubert fprintf(out, "active_connection_id_limit=%u\n", 1161*be771a7bSCy Schubert (unsigned)params->active_connection_id_limit); 1162*be771a7bSCy Schubert fprintf(out, "max_datagram_frame_size=%u\n", 1163*be771a7bSCy Schubert (unsigned)params->max_datagram_frame_size); 1164*be771a7bSCy Schubert if(ferror(out)) { 1165*be771a7bSCy Schubert verbose(1, "There was an error writing %s: %s", 1166*be771a7bSCy Schubert file, strerror(errno)); 1167*be771a7bSCy Schubert fclose(out); 1168*be771a7bSCy Schubert return; 1169*be771a7bSCy Schubert } 1170*be771a7bSCy Schubert fclose(out); 1171*be771a7bSCy Schubert } 1172*be771a7bSCy Schubert #endif /* HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS */ 1173*be771a7bSCy Schubert 1174*be771a7bSCy Schubert /** fetch and write the transport file */ 1175*be771a7bSCy Schubert static void 1176*be771a7bSCy Schubert early_data_write_transport(struct doq_client_data* data) 1177*be771a7bSCy Schubert { 1178*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS 1179*be771a7bSCy Schubert FILE* out; 1180*be771a7bSCy Schubert uint8_t buf[1024]; 1181*be771a7bSCy Schubert ngtcp2_ssize len = ngtcp2_conn_encode_0rtt_transport_params(data->conn, 1182*be771a7bSCy Schubert buf, sizeof(buf)); 1183*be771a7bSCy Schubert if(len < 0) { 1184*be771a7bSCy Schubert log_err("ngtcp2_conn_encode_0rtt_transport_params failed: %s", 1185*be771a7bSCy Schubert ngtcp2_strerror(len)); 1186*be771a7bSCy Schubert return; 1187*be771a7bSCy Schubert } 1188*be771a7bSCy Schubert out = fopen(data->transport_file, "w"); 1189*be771a7bSCy Schubert if(!out) { 1190*be771a7bSCy Schubert perror(data->transport_file); 1191*be771a7bSCy Schubert return; 1192*be771a7bSCy Schubert } 1193*be771a7bSCy Schubert if(fwrite(buf, 1, len, out) != (size_t)len) { 1194*be771a7bSCy Schubert log_err("fwrite %s failed: %s", data->transport_file, 1195*be771a7bSCy Schubert strerror(errno)); 1196*be771a7bSCy Schubert } 1197*be771a7bSCy Schubert if(ferror(out)) { 1198*be771a7bSCy Schubert verbose(1, "There was an error writing %s: %s", 1199*be771a7bSCy Schubert data->transport_file, strerror(errno)); 1200*be771a7bSCy Schubert } 1201*be771a7bSCy Schubert fclose(out); 1202*be771a7bSCy Schubert #else 1203*be771a7bSCy Schubert struct ngtcp2_transport_params params; 1204*be771a7bSCy Schubert memset(¶ms, 0, sizeof(params)); 1205*be771a7bSCy Schubert ngtcp2_conn_get_remote_transport_params(data->conn, ¶ms); 1206*be771a7bSCy Schubert transport_file_write(data->transport_file, ¶ms); 1207*be771a7bSCy Schubert #endif 1208*be771a7bSCy Schubert } 1209*be771a7bSCy Schubert 1210*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 1211*be771a7bSCy Schubert /** applicatation rx key callback, this is where the rx key is set, 1212*be771a7bSCy Schubert * and streams can be opened, like http3 unidirectional streams, like 1213*be771a7bSCy Schubert * the http3 control and http3 qpack encode and decoder streams. */ 1214*be771a7bSCy Schubert static int 1215*be771a7bSCy Schubert application_rx_key_cb(struct doq_client_data* data) 1216*be771a7bSCy Schubert { 1217*be771a7bSCy Schubert verbose(1, "application_rx_key_cb callback"); 1218*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_max_data_left is %d", 1219*be771a7bSCy Schubert (int)ngtcp2_conn_get_max_data_left(data->conn)); 1220*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI 1221*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d", 1222*be771a7bSCy Schubert (int)ngtcp2_conn_get_max_local_streams_uni(data->conn)); 1223*be771a7bSCy Schubert #endif 1224*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_streams_uni_left is %d", 1225*be771a7bSCy Schubert (int)ngtcp2_conn_get_streams_uni_left(data->conn)); 1226*be771a7bSCy Schubert verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d", 1227*be771a7bSCy Schubert (int)ngtcp2_conn_get_streams_bidi_left(data->conn)); 1228*be771a7bSCy Schubert if(data->transport_file) { 1229*be771a7bSCy Schubert early_data_write_transport(data); 1230*be771a7bSCy Schubert } 1231*be771a7bSCy Schubert return 1; 1232*be771a7bSCy Schubert } 1233*be771a7bSCy Schubert 1234*be771a7bSCy Schubert /** quic_method set_encryption_secrets function */ 1235*be771a7bSCy Schubert static int 1236*be771a7bSCy Schubert set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, 1237*be771a7bSCy Schubert const uint8_t *read_secret, const uint8_t *write_secret, 1238*be771a7bSCy Schubert size_t secret_len) 1239*be771a7bSCy Schubert { 1240*be771a7bSCy Schubert struct doq_client_data* data = get_app_data(ssl); 1241*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL 1242*be771a7bSCy Schubert ngtcp2_encryption_level 1243*be771a7bSCy Schubert #else 1244*be771a7bSCy Schubert ngtcp2_crypto_level 1245*be771a7bSCy Schubert #endif 1246*be771a7bSCy Schubert level = 1247*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL 1248*be771a7bSCy Schubert ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); 1249*be771a7bSCy Schubert #else 1250*be771a7bSCy Schubert ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); 1251*be771a7bSCy Schubert #endif 1252*be771a7bSCy Schubert 1253*be771a7bSCy Schubert if(read_secret) { 1254*be771a7bSCy Schubert if(ngtcp2_crypto_derive_and_install_rx_key(data->conn, NULL, 1255*be771a7bSCy Schubert NULL, NULL, level, read_secret, secret_len) != 0) { 1256*be771a7bSCy Schubert log_err("ngtcp2_crypto_derive_and_install_rx_key failed"); 1257*be771a7bSCy Schubert return 0; 1258*be771a7bSCy Schubert } 1259*be771a7bSCy Schubert if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) { 1260*be771a7bSCy Schubert if(!application_rx_key_cb(data)) 1261*be771a7bSCy Schubert return 0; 1262*be771a7bSCy Schubert } 1263*be771a7bSCy Schubert } 1264*be771a7bSCy Schubert 1265*be771a7bSCy Schubert if(write_secret) { 1266*be771a7bSCy Schubert if(ngtcp2_crypto_derive_and_install_tx_key(data->conn, NULL, 1267*be771a7bSCy Schubert NULL, NULL, level, write_secret, secret_len) != 0) { 1268*be771a7bSCy Schubert log_err("ngtcp2_crypto_derive_and_install_tx_key failed"); 1269*be771a7bSCy Schubert return 0; 1270*be771a7bSCy Schubert } 1271*be771a7bSCy Schubert } 1272*be771a7bSCy Schubert return 1; 1273*be771a7bSCy Schubert } 1274*be771a7bSCy Schubert 1275*be771a7bSCy Schubert /** quic_method add_handshake_data function */ 1276*be771a7bSCy Schubert static int 1277*be771a7bSCy Schubert add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, 1278*be771a7bSCy Schubert const uint8_t *data, size_t len) 1279*be771a7bSCy Schubert { 1280*be771a7bSCy Schubert struct doq_client_data* doqdata = get_app_data(ssl); 1281*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL 1282*be771a7bSCy Schubert ngtcp2_encryption_level 1283*be771a7bSCy Schubert #else 1284*be771a7bSCy Schubert ngtcp2_crypto_level 1285*be771a7bSCy Schubert #endif 1286*be771a7bSCy Schubert level = 1287*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL 1288*be771a7bSCy Schubert ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level); 1289*be771a7bSCy Schubert #else 1290*be771a7bSCy Schubert ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); 1291*be771a7bSCy Schubert #endif 1292*be771a7bSCy Schubert int rv; 1293*be771a7bSCy Schubert 1294*be771a7bSCy Schubert rv = ngtcp2_conn_submit_crypto_data(doqdata->conn, level, data, len); 1295*be771a7bSCy Schubert if(rv != 0) { 1296*be771a7bSCy Schubert log_err("ngtcp2_conn_submit_crypto_data failed: %s", 1297*be771a7bSCy Schubert ngtcp2_strerror(rv)); 1298*be771a7bSCy Schubert ngtcp2_conn_set_tls_error(doqdata->conn, rv); 1299*be771a7bSCy Schubert return 0; 1300*be771a7bSCy Schubert } 1301*be771a7bSCy Schubert return 1; 1302*be771a7bSCy Schubert } 1303*be771a7bSCy Schubert 1304*be771a7bSCy Schubert /** quic_method flush_flight function */ 1305*be771a7bSCy Schubert static int 1306*be771a7bSCy Schubert flush_flight(SSL* ATTR_UNUSED(ssl)) 1307*be771a7bSCy Schubert { 1308*be771a7bSCy Schubert return 1; 1309*be771a7bSCy Schubert } 1310*be771a7bSCy Schubert 1311*be771a7bSCy Schubert /** quic_method send_alert function */ 1312*be771a7bSCy Schubert static int 1313*be771a7bSCy Schubert send_alert(SSL *ssl, enum ssl_encryption_level_t ATTR_UNUSED(level), 1314*be771a7bSCy Schubert uint8_t alert) 1315*be771a7bSCy Schubert { 1316*be771a7bSCy Schubert struct doq_client_data* data = get_app_data(ssl); 1317*be771a7bSCy Schubert data->tls_alert = alert; 1318*be771a7bSCy Schubert return 1; 1319*be771a7bSCy Schubert } 1320*be771a7bSCy Schubert #endif /* HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT */ 1321*be771a7bSCy Schubert 1322*be771a7bSCy Schubert /** new session callback. We can write it to file for resumption later. */ 1323*be771a7bSCy Schubert static int 1324*be771a7bSCy Schubert new_session_cb(SSL* ssl, SSL_SESSION* session) 1325*be771a7bSCy Schubert { 1326*be771a7bSCy Schubert struct doq_client_data* data = get_app_data(ssl); 1327*be771a7bSCy Schubert BIO *f; 1328*be771a7bSCy Schubert log_assert(data->session_file); 1329*be771a7bSCy Schubert verbose(1, "new session cb: the ssl session max_early_data_size is %u", 1330*be771a7bSCy Schubert (unsigned)SSL_SESSION_get_max_early_data(session)); 1331*be771a7bSCy Schubert f = BIO_new_file(data->session_file, "w"); 1332*be771a7bSCy Schubert if(!f) { 1333*be771a7bSCy Schubert log_err("Could not open %s: %s", data->session_file, 1334*be771a7bSCy Schubert strerror(errno)); 1335*be771a7bSCy Schubert return 0; 1336*be771a7bSCy Schubert } 1337*be771a7bSCy Schubert PEM_write_bio_SSL_SESSION(f, session); 1338*be771a7bSCy Schubert BIO_free(f); 1339*be771a7bSCy Schubert verbose(1, "written tls session to %s", data->session_file); 1340*be771a7bSCy Schubert return 0; 1341*be771a7bSCy Schubert } 1342*be771a7bSCy Schubert 1343*be771a7bSCy Schubert /** setup the TLS context */ 1344*be771a7bSCy Schubert static SSL_CTX* 1345*be771a7bSCy Schubert ctx_client_setup(void) 1346*be771a7bSCy Schubert { 1347*be771a7bSCy Schubert SSL_CTX* ctx = SSL_CTX_new(TLS_client_method()); 1348*be771a7bSCy Schubert if(!ctx) { 1349*be771a7bSCy Schubert log_crypto_err("Could not SSL_CTX_new"); 1350*be771a7bSCy Schubert exit(1); 1351*be771a7bSCy Schubert } 1352*be771a7bSCy Schubert SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); 1353*be771a7bSCy Schubert SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); 1354*be771a7bSCy Schubert SSL_CTX_set_default_verify_paths(ctx); 1355*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT 1356*be771a7bSCy Schubert if(ngtcp2_crypto_quictls_configure_client_context(ctx) != 0) { 1357*be771a7bSCy Schubert log_err("ngtcp2_crypto_quictls_configure_client_context failed"); 1358*be771a7bSCy Schubert exit(1); 1359*be771a7bSCy Schubert } 1360*be771a7bSCy Schubert #else 1361*be771a7bSCy Schubert memset(&quic_method, 0, sizeof(quic_method)); 1362*be771a7bSCy Schubert quic_method.set_encryption_secrets = &set_encryption_secrets; 1363*be771a7bSCy Schubert quic_method.add_handshake_data = &add_handshake_data; 1364*be771a7bSCy Schubert quic_method.flush_flight = &flush_flight; 1365*be771a7bSCy Schubert quic_method.send_alert = &send_alert; 1366*be771a7bSCy Schubert SSL_CTX_set_quic_method(ctx, &quic_method); 1367*be771a7bSCy Schubert #endif 1368*be771a7bSCy Schubert return ctx; 1369*be771a7bSCy Schubert } 1370*be771a7bSCy Schubert 1371*be771a7bSCy Schubert 1372*be771a7bSCy Schubert /* setup the TLS object */ 1373*be771a7bSCy Schubert static SSL* 1374*be771a7bSCy Schubert ssl_client_setup(struct doq_client_data* data) 1375*be771a7bSCy Schubert { 1376*be771a7bSCy Schubert SSL* ssl = SSL_new(data->ctx); 1377*be771a7bSCy Schubert if(!ssl) { 1378*be771a7bSCy Schubert log_crypto_err("Could not SSL_new"); 1379*be771a7bSCy Schubert exit(1); 1380*be771a7bSCy Schubert } 1381*be771a7bSCy Schubert set_app_data(ssl, data); 1382*be771a7bSCy Schubert SSL_set_connect_state(ssl); 1383*be771a7bSCy Schubert if(!SSL_set_fd(ssl, data->fd)) { 1384*be771a7bSCy Schubert log_crypto_err("Could not SSL_set_fd"); 1385*be771a7bSCy Schubert exit(1); 1386*be771a7bSCy Schubert } 1387*be771a7bSCy Schubert if((data->quic_version & 0xff000000) == 0xff000000) { 1388*be771a7bSCy Schubert SSL_set_quic_use_legacy_codepoint(ssl, 1); 1389*be771a7bSCy Schubert } else { 1390*be771a7bSCy Schubert SSL_set_quic_use_legacy_codepoint(ssl, 0); 1391*be771a7bSCy Schubert } 1392*be771a7bSCy Schubert SSL_set_alpn_protos(ssl, (const unsigned char *)"\x03""doq", 4); 1393*be771a7bSCy Schubert /* send the SNI host name */ 1394*be771a7bSCy Schubert SSL_set_tlsext_host_name(ssl, "localhost"); 1395*be771a7bSCy Schubert return ssl; 1396*be771a7bSCy Schubert } 1397*be771a7bSCy Schubert 1398*be771a7bSCy Schubert /** get packet ecn information */ 1399*be771a7bSCy Schubert static uint32_t 1400*be771a7bSCy Schubert msghdr_get_ecn(struct msghdr* msg, int family) 1401*be771a7bSCy Schubert { 1402*be771a7bSCy Schubert #ifndef S_SPLINT_S 1403*be771a7bSCy Schubert struct cmsghdr* cmsg; 1404*be771a7bSCy Schubert if(family == AF_INET6) { 1405*be771a7bSCy Schubert for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 1406*be771a7bSCy Schubert cmsg = CMSG_NXTHDR(msg, cmsg)) { 1407*be771a7bSCy Schubert if(cmsg->cmsg_level == IPPROTO_IPV6 && 1408*be771a7bSCy Schubert cmsg->cmsg_type == IPV6_TCLASS && 1409*be771a7bSCy Schubert cmsg->cmsg_len != 0) { 1410*be771a7bSCy Schubert uint8_t* ecn = (uint8_t*)CMSG_DATA(cmsg); 1411*be771a7bSCy Schubert return *ecn; 1412*be771a7bSCy Schubert } 1413*be771a7bSCy Schubert } 1414*be771a7bSCy Schubert return 0; 1415*be771a7bSCy Schubert } 1416*be771a7bSCy Schubert for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 1417*be771a7bSCy Schubert cmsg = CMSG_NXTHDR(msg, cmsg)) { 1418*be771a7bSCy Schubert if(cmsg->cmsg_level == IPPROTO_IP && 1419*be771a7bSCy Schubert cmsg->cmsg_type == IP_TOS && 1420*be771a7bSCy Schubert cmsg->cmsg_len != 0) { 1421*be771a7bSCy Schubert uint8_t* ecn = (uint8_t*)CMSG_DATA(cmsg); 1422*be771a7bSCy Schubert return *ecn; 1423*be771a7bSCy Schubert } 1424*be771a7bSCy Schubert } 1425*be771a7bSCy Schubert return 0; 1426*be771a7bSCy Schubert #endif /* S_SPLINT_S */ 1427*be771a7bSCy Schubert } 1428*be771a7bSCy Schubert 1429*be771a7bSCy Schubert /** set the ecn on the transmission */ 1430*be771a7bSCy Schubert static void 1431*be771a7bSCy Schubert set_ecn(int fd, int family, uint32_t ecn) 1432*be771a7bSCy Schubert { 1433*be771a7bSCy Schubert unsigned int val = ecn; 1434*be771a7bSCy Schubert if(family == AF_INET6) { 1435*be771a7bSCy Schubert if(setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &val, 1436*be771a7bSCy Schubert (socklen_t)sizeof(val)) == -1) { 1437*be771a7bSCy Schubert log_err("setsockopt(.. IPV6_TCLASS ..): %s", 1438*be771a7bSCy Schubert strerror(errno)); 1439*be771a7bSCy Schubert } 1440*be771a7bSCy Schubert return; 1441*be771a7bSCy Schubert } 1442*be771a7bSCy Schubert if(setsockopt(fd, IPPROTO_IP, IP_TOS, &val, 1443*be771a7bSCy Schubert (socklen_t)sizeof(val)) == -1) { 1444*be771a7bSCy Schubert log_err("setsockopt(.. IP_TOS ..): %s", 1445*be771a7bSCy Schubert strerror(errno)); 1446*be771a7bSCy Schubert } 1447*be771a7bSCy Schubert } 1448*be771a7bSCy Schubert 1449*be771a7bSCy Schubert /** send a packet */ 1450*be771a7bSCy Schubert static int 1451*be771a7bSCy Schubert doq_client_send_pkt(struct doq_client_data* data, uint32_t ecn, uint8_t* buf, 1452*be771a7bSCy Schubert size_t buf_len, int is_blocked_pkt, int* send_is_blocked) 1453*be771a7bSCy Schubert { 1454*be771a7bSCy Schubert struct msghdr msg; 1455*be771a7bSCy Schubert struct iovec iov[1]; 1456*be771a7bSCy Schubert ssize_t ret; 1457*be771a7bSCy Schubert iov[0].iov_base = buf; 1458*be771a7bSCy Schubert iov[0].iov_len = buf_len; 1459*be771a7bSCy Schubert memset(&msg, 0, sizeof(msg)); 1460*be771a7bSCy Schubert msg.msg_name = (void*)&data->dest_addr; 1461*be771a7bSCy Schubert msg.msg_namelen = data->dest_addr_len; 1462*be771a7bSCy Schubert msg.msg_iov = iov; 1463*be771a7bSCy Schubert msg.msg_iovlen = 1; 1464*be771a7bSCy Schubert set_ecn(data->fd, data->dest_addr.ss_family, ecn); 1465*be771a7bSCy Schubert 1466*be771a7bSCy Schubert for(;;) { 1467*be771a7bSCy Schubert ret = sendmsg(data->fd, &msg, MSG_DONTWAIT); 1468*be771a7bSCy Schubert if(ret == -1 && errno == EINTR) 1469*be771a7bSCy Schubert continue; 1470*be771a7bSCy Schubert break; 1471*be771a7bSCy Schubert } 1472*be771a7bSCy Schubert if(ret == -1) { 1473*be771a7bSCy Schubert if(errno == EAGAIN) { 1474*be771a7bSCy Schubert if(buf_len > 1475*be771a7bSCy Schubert sldns_buffer_capacity(data->blocked_pkt)) 1476*be771a7bSCy Schubert return 0; /* Cannot store it, but the buffers 1477*be771a7bSCy Schubert are equal length and large enough, so this 1478*be771a7bSCy Schubert should not happen. */ 1479*be771a7bSCy Schubert data->have_blocked_pkt = 1; 1480*be771a7bSCy Schubert if(send_is_blocked) 1481*be771a7bSCy Schubert *send_is_blocked = 1; 1482*be771a7bSCy Schubert /* If we already send the previously blocked packet, 1483*be771a7bSCy Schubert * no need to copy it, otherwise store the packet for 1484*be771a7bSCy Schubert * later. */ 1485*be771a7bSCy Schubert if(!is_blocked_pkt) { 1486*be771a7bSCy Schubert data->blocked_pkt_pi.ecn = ecn; 1487*be771a7bSCy Schubert sldns_buffer_clear(data->blocked_pkt); 1488*be771a7bSCy Schubert sldns_buffer_write(data->blocked_pkt, buf, 1489*be771a7bSCy Schubert buf_len); 1490*be771a7bSCy Schubert sldns_buffer_flip(data->blocked_pkt); 1491*be771a7bSCy Schubert } 1492*be771a7bSCy Schubert return 0; 1493*be771a7bSCy Schubert } 1494*be771a7bSCy Schubert log_err("doq sendmsg: %s", strerror(errno)); 1495*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1496*be771a7bSCy Schubert ngtcp2_ccerr_set_application_error(&data->ccerr, -1, NULL, 0); 1497*be771a7bSCy Schubert #else 1498*be771a7bSCy Schubert ngtcp2_connection_close_error_set_application_error(&data->last_error, -1, NULL, 0); 1499*be771a7bSCy Schubert #endif 1500*be771a7bSCy Schubert return 0; 1501*be771a7bSCy Schubert } 1502*be771a7bSCy Schubert return 1; 1503*be771a7bSCy Schubert } 1504*be771a7bSCy Schubert 1505*be771a7bSCy Schubert /** change event write on fd to when we have data or when congested */ 1506*be771a7bSCy Schubert static void 1507*be771a7bSCy Schubert event_change_write(struct doq_client_data* data, int do_write) 1508*be771a7bSCy Schubert { 1509*be771a7bSCy Schubert ub_event_del(data->ev); 1510*be771a7bSCy Schubert if(do_write) { 1511*be771a7bSCy Schubert ub_event_add_bits(data->ev, UB_EV_WRITE); 1512*be771a7bSCy Schubert } else { 1513*be771a7bSCy Schubert ub_event_del_bits(data->ev, UB_EV_WRITE); 1514*be771a7bSCy Schubert } 1515*be771a7bSCy Schubert if(ub_event_add(data->ev, NULL) != 0) { 1516*be771a7bSCy Schubert fatal_exit("could not ub_event_add"); 1517*be771a7bSCy Schubert } 1518*be771a7bSCy Schubert } 1519*be771a7bSCy Schubert 1520*be771a7bSCy Schubert /** write the connection close, with possible error */ 1521*be771a7bSCy Schubert static void 1522*be771a7bSCy Schubert write_conn_close(struct doq_client_data* data) 1523*be771a7bSCy Schubert { 1524*be771a7bSCy Schubert struct ngtcp2_path_storage ps; 1525*be771a7bSCy Schubert struct ngtcp2_pkt_info pi; 1526*be771a7bSCy Schubert ngtcp2_ssize ret; 1527*be771a7bSCy Schubert if(!data->conn || 1528*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD 1529*be771a7bSCy Schubert ngtcp2_conn_in_closing_period(data->conn) || 1530*be771a7bSCy Schubert #else 1531*be771a7bSCy Schubert ngtcp2_conn_is_in_closing_period(data->conn) || 1532*be771a7bSCy Schubert #endif 1533*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD 1534*be771a7bSCy Schubert ngtcp2_conn_in_draining_period(data->conn) 1535*be771a7bSCy Schubert #else 1536*be771a7bSCy Schubert ngtcp2_conn_is_in_draining_period(data->conn) 1537*be771a7bSCy Schubert #endif 1538*be771a7bSCy Schubert ) 1539*be771a7bSCy Schubert return; 1540*be771a7bSCy Schubert /* Drop blocked packet if there is one, the connection is being 1541*be771a7bSCy Schubert * closed. And thus no further data traffic. */ 1542*be771a7bSCy Schubert data->have_blocked_pkt = 0; 1543*be771a7bSCy Schubert if( 1544*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1545*be771a7bSCy Schubert data->ccerr.type == NGTCP2_CCERR_TYPE_IDLE_CLOSE 1546*be771a7bSCy Schubert #else 1547*be771a7bSCy Schubert data->last_error.type == 1548*be771a7bSCy Schubert NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE 1549*be771a7bSCy Schubert #endif 1550*be771a7bSCy Schubert ) { 1551*be771a7bSCy Schubert /* do not call ngtcp2_conn_write_connection_close on the 1552*be771a7bSCy Schubert * connection because the ngtcp2_conn_handle_expiry call 1553*be771a7bSCy Schubert * has returned NGTCP2_ERR_IDLE_CLOSE. But continue to close 1554*be771a7bSCy Schubert * the connection. */ 1555*be771a7bSCy Schubert return; 1556*be771a7bSCy Schubert } 1557*be771a7bSCy Schubert verbose(1, "write connection close"); 1558*be771a7bSCy Schubert ngtcp2_path_storage_zero(&ps); 1559*be771a7bSCy Schubert sldns_buffer_clear(data->pkt_buf); 1560*be771a7bSCy Schubert ret = ngtcp2_conn_write_connection_close( 1561*be771a7bSCy Schubert data->conn, &ps.path, &pi, sldns_buffer_begin(data->pkt_buf), 1562*be771a7bSCy Schubert sldns_buffer_remaining(data->pkt_buf), 1563*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1564*be771a7bSCy Schubert &data->ccerr 1565*be771a7bSCy Schubert #else 1566*be771a7bSCy Schubert &data->last_error 1567*be771a7bSCy Schubert #endif 1568*be771a7bSCy Schubert , get_timestamp_nanosec()); 1569*be771a7bSCy Schubert if(ret < 0) { 1570*be771a7bSCy Schubert log_err("ngtcp2_conn_write_connection_close failed: %s", 1571*be771a7bSCy Schubert ngtcp2_strerror(ret)); 1572*be771a7bSCy Schubert return; 1573*be771a7bSCy Schubert } 1574*be771a7bSCy Schubert verbose(1, "write connection close packet length %d", (int)ret); 1575*be771a7bSCy Schubert if(ret == 0) 1576*be771a7bSCy Schubert return; 1577*be771a7bSCy Schubert doq_client_send_pkt(data, pi.ecn, sldns_buffer_begin(data->pkt_buf), 1578*be771a7bSCy Schubert ret, 0, NULL); 1579*be771a7bSCy Schubert } 1580*be771a7bSCy Schubert 1581*be771a7bSCy Schubert /** disconnect we are done */ 1582*be771a7bSCy Schubert static void 1583*be771a7bSCy Schubert disconnect(struct doq_client_data* data) 1584*be771a7bSCy Schubert { 1585*be771a7bSCy Schubert verbose(1, "disconnect"); 1586*be771a7bSCy Schubert write_conn_close(data); 1587*be771a7bSCy Schubert ub_event_base_loopexit(data->base); 1588*be771a7bSCy Schubert } 1589*be771a7bSCy Schubert 1590*be771a7bSCy Schubert /** the expire timer callback */ 1591*be771a7bSCy Schubert void doq_client_timer_cb(int ATTR_UNUSED(fd), 1592*be771a7bSCy Schubert short ATTR_UNUSED(bits), void* arg) 1593*be771a7bSCy Schubert { 1594*be771a7bSCy Schubert struct doq_client_data* data = (struct doq_client_data*)arg; 1595*be771a7bSCy Schubert ngtcp2_tstamp now = get_timestamp_nanosec(); 1596*be771a7bSCy Schubert int rv; 1597*be771a7bSCy Schubert 1598*be771a7bSCy Schubert verbose(1, "doq expire_timer"); 1599*be771a7bSCy Schubert data->expire_timer_added = 0; 1600*be771a7bSCy Schubert rv = ngtcp2_conn_handle_expiry(data->conn, now); 1601*be771a7bSCy Schubert if(rv != 0) { 1602*be771a7bSCy Schubert log_err("ngtcp2_conn_handle_expiry failed: %s", 1603*be771a7bSCy Schubert ngtcp2_strerror(rv)); 1604*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1605*be771a7bSCy Schubert ngtcp2_ccerr_set_liberr(&data->ccerr, rv, NULL, 0); 1606*be771a7bSCy Schubert #else 1607*be771a7bSCy Schubert ngtcp2_connection_close_error_set_transport_error_liberr( 1608*be771a7bSCy Schubert &data->last_error, rv, NULL, 0); 1609*be771a7bSCy Schubert #endif 1610*be771a7bSCy Schubert disconnect(data); 1611*be771a7bSCy Schubert return; 1612*be771a7bSCy Schubert } 1613*be771a7bSCy Schubert update_timer(data); 1614*be771a7bSCy Schubert on_write(data); 1615*be771a7bSCy Schubert } 1616*be771a7bSCy Schubert 1617*be771a7bSCy Schubert /** update the timers */ 1618*be771a7bSCy Schubert static void 1619*be771a7bSCy Schubert update_timer(struct doq_client_data* data) 1620*be771a7bSCy Schubert { 1621*be771a7bSCy Schubert ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(data->conn); 1622*be771a7bSCy Schubert ngtcp2_tstamp now = get_timestamp_nanosec(); 1623*be771a7bSCy Schubert ngtcp2_tstamp t; 1624*be771a7bSCy Schubert struct timeval tv; 1625*be771a7bSCy Schubert 1626*be771a7bSCy Schubert if(expiry <= now) { 1627*be771a7bSCy Schubert /* the timer has already expired, add with zero timeout */ 1628*be771a7bSCy Schubert t = 0; 1629*be771a7bSCy Schubert } else { 1630*be771a7bSCy Schubert t = expiry - now; 1631*be771a7bSCy Schubert } 1632*be771a7bSCy Schubert 1633*be771a7bSCy Schubert /* set the timer */ 1634*be771a7bSCy Schubert if(data->expire_timer_added) { 1635*be771a7bSCy Schubert ub_timer_del(data->expire_timer); 1636*be771a7bSCy Schubert data->expire_timer_added = 0; 1637*be771a7bSCy Schubert } 1638*be771a7bSCy Schubert memset(&tv, 0, sizeof(tv)); 1639*be771a7bSCy Schubert tv.tv_sec = t / NGTCP2_SECONDS; 1640*be771a7bSCy Schubert tv.tv_usec = (t / NGTCP2_MICROSECONDS)%1000000; 1641*be771a7bSCy Schubert verbose(1, "update_timer in %d.%6.6d secs", (int)tv.tv_sec, 1642*be771a7bSCy Schubert (int)tv.tv_usec); 1643*be771a7bSCy Schubert if(ub_timer_add(data->expire_timer, data->base, 1644*be771a7bSCy Schubert &doq_client_timer_cb, data, &tv) != 0) { 1645*be771a7bSCy Schubert log_err("timer_add failed: could not add expire timer"); 1646*be771a7bSCy Schubert return; 1647*be771a7bSCy Schubert } 1648*be771a7bSCy Schubert data->expire_timer_added = 1; 1649*be771a7bSCy Schubert } 1650*be771a7bSCy Schubert 1651*be771a7bSCy Schubert /** perform read operations on fd */ 1652*be771a7bSCy Schubert static void 1653*be771a7bSCy Schubert on_read(struct doq_client_data* data) 1654*be771a7bSCy Schubert { 1655*be771a7bSCy Schubert struct sockaddr_storage addr; 1656*be771a7bSCy Schubert struct iovec iov[1]; 1657*be771a7bSCy Schubert struct msghdr msg; 1658*be771a7bSCy Schubert union { 1659*be771a7bSCy Schubert struct cmsghdr hdr; 1660*be771a7bSCy Schubert char buf[256]; 1661*be771a7bSCy Schubert } ancil; 1662*be771a7bSCy Schubert int i; 1663*be771a7bSCy Schubert ssize_t rcv; 1664*be771a7bSCy Schubert ngtcp2_pkt_info pi; 1665*be771a7bSCy Schubert int rv; 1666*be771a7bSCy Schubert struct ngtcp2_path path; 1667*be771a7bSCy Schubert 1668*be771a7bSCy Schubert for(i=0; i<10; i++) { 1669*be771a7bSCy Schubert msg.msg_name = &addr; 1670*be771a7bSCy Schubert msg.msg_namelen = (socklen_t)sizeof(addr); 1671*be771a7bSCy Schubert iov[0].iov_base = sldns_buffer_begin(data->pkt_buf); 1672*be771a7bSCy Schubert iov[0].iov_len = sldns_buffer_remaining(data->pkt_buf); 1673*be771a7bSCy Schubert msg.msg_iov = iov; 1674*be771a7bSCy Schubert msg.msg_iovlen = 1; 1675*be771a7bSCy Schubert msg.msg_control = ancil.buf; 1676*be771a7bSCy Schubert #ifndef S_SPLINT_S 1677*be771a7bSCy Schubert msg.msg_controllen = sizeof(ancil.buf); 1678*be771a7bSCy Schubert #endif /* S_SPLINT_S */ 1679*be771a7bSCy Schubert msg.msg_flags = 0; 1680*be771a7bSCy Schubert 1681*be771a7bSCy Schubert rcv = recvmsg(data->fd, &msg, MSG_DONTWAIT); 1682*be771a7bSCy Schubert if(rcv == -1) { 1683*be771a7bSCy Schubert if(errno == EINTR || errno == EAGAIN) 1684*be771a7bSCy Schubert break; 1685*be771a7bSCy Schubert log_err_addr("doq recvmsg", strerror(errno), 1686*be771a7bSCy Schubert &data->dest_addr, sizeof(data->dest_addr_len)); 1687*be771a7bSCy Schubert break; 1688*be771a7bSCy Schubert } 1689*be771a7bSCy Schubert 1690*be771a7bSCy Schubert pi.ecn = msghdr_get_ecn(&msg, addr.ss_family); 1691*be771a7bSCy Schubert verbose(1, "recvmsg %d ecn=0x%x", (int)rcv, (int)pi.ecn); 1692*be771a7bSCy Schubert 1693*be771a7bSCy Schubert memset(&path, 0, sizeof(path)); 1694*be771a7bSCy Schubert path.local.addr = (void*)&data->local_addr; 1695*be771a7bSCy Schubert path.local.addrlen = data->local_addr_len; 1696*be771a7bSCy Schubert path.remote.addr = (void*)msg.msg_name; 1697*be771a7bSCy Schubert path.remote.addrlen = msg.msg_namelen; 1698*be771a7bSCy Schubert rv = ngtcp2_conn_read_pkt(data->conn, &path, &pi, 1699*be771a7bSCy Schubert iov[0].iov_base, rcv, get_timestamp_nanosec()); 1700*be771a7bSCy Schubert if(rv != 0) { 1701*be771a7bSCy Schubert log_err("ngtcp2_conn_read_pkt failed: %s", 1702*be771a7bSCy Schubert ngtcp2_strerror(rv)); 1703*be771a7bSCy Schubert if( 1704*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1705*be771a7bSCy Schubert data->ccerr.error_code == 0 1706*be771a7bSCy Schubert #else 1707*be771a7bSCy Schubert data->last_error.error_code == 0 1708*be771a7bSCy Schubert #endif 1709*be771a7bSCy Schubert ) { 1710*be771a7bSCy Schubert if(rv == NGTCP2_ERR_CRYPTO) { 1711*be771a7bSCy Schubert /* in picotls the tls alert may need 1712*be771a7bSCy Schubert * to be copied, but this is with 1713*be771a7bSCy Schubert * openssl. And we have the value 1714*be771a7bSCy Schubert * data.tls_alert. */ 1715*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1716*be771a7bSCy Schubert ngtcp2_ccerr_set_tls_alert( 1717*be771a7bSCy Schubert &data->ccerr, data->tls_alert, 1718*be771a7bSCy Schubert NULL, 0); 1719*be771a7bSCy Schubert #else 1720*be771a7bSCy Schubert ngtcp2_connection_close_error_set_transport_error_tls_alert( 1721*be771a7bSCy Schubert &data->last_error, 1722*be771a7bSCy Schubert data->tls_alert, NULL, 0); 1723*be771a7bSCy Schubert #endif 1724*be771a7bSCy Schubert } else { 1725*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1726*be771a7bSCy Schubert ngtcp2_ccerr_set_liberr(&data->ccerr, 1727*be771a7bSCy Schubert rv, NULL, 0); 1728*be771a7bSCy Schubert #else 1729*be771a7bSCy Schubert ngtcp2_connection_close_error_set_transport_error_liberr( 1730*be771a7bSCy Schubert &data->last_error, rv, NULL, 1731*be771a7bSCy Schubert 0); 1732*be771a7bSCy Schubert #endif 1733*be771a7bSCy Schubert } 1734*be771a7bSCy Schubert } 1735*be771a7bSCy Schubert disconnect(data); 1736*be771a7bSCy Schubert return; 1737*be771a7bSCy Schubert } 1738*be771a7bSCy Schubert } 1739*be771a7bSCy Schubert 1740*be771a7bSCy Schubert update_timer(data); 1741*be771a7bSCy Schubert } 1742*be771a7bSCy Schubert 1743*be771a7bSCy Schubert /** the write of this query has completed, it has spooled to packets, 1744*be771a7bSCy Schubert * set it to have the write done and move it to the list of receive streams. */ 1745*be771a7bSCy Schubert static void 1746*be771a7bSCy Schubert query_write_is_done(struct doq_client_data* data, 1747*be771a7bSCy Schubert struct doq_client_stream* str) 1748*be771a7bSCy Schubert { 1749*be771a7bSCy Schubert if(verbosity > 0) { 1750*be771a7bSCy Schubert char* logs = client_stream_string(str); 1751*be771a7bSCy Schubert verbose(1, "query %s write is done", logs); 1752*be771a7bSCy Schubert free(logs); 1753*be771a7bSCy Schubert } 1754*be771a7bSCy Schubert str->write_is_done = 1; 1755*be771a7bSCy Schubert stream_list_move(str, data->query_list_send, data->query_list_receive); 1756*be771a7bSCy Schubert } 1757*be771a7bSCy Schubert 1758*be771a7bSCy Schubert /** write the data streams, if possible */ 1759*be771a7bSCy Schubert static int 1760*be771a7bSCy Schubert write_streams(struct doq_client_data* data) 1761*be771a7bSCy Schubert { 1762*be771a7bSCy Schubert ngtcp2_path_storage ps; 1763*be771a7bSCy Schubert ngtcp2_tstamp ts = get_timestamp_nanosec(); 1764*be771a7bSCy Schubert struct doq_client_stream* str, *next; 1765*be771a7bSCy Schubert uint32_t flags; 1766*be771a7bSCy Schubert /* number of bytes that can be sent without packet pacing */ 1767*be771a7bSCy Schubert size_t send_quantum = ngtcp2_conn_get_send_quantum(data->conn); 1768*be771a7bSCy Schubert /* Overhead is the stream overhead of adding a header onto the data, 1769*be771a7bSCy Schubert * this make sure the number of bytes to send in data bytes plus 1770*be771a7bSCy Schubert * the overhead overshoots the target quantum by a smaller margin, 1771*be771a7bSCy Schubert * and then it stops sending more bytes. With zero it would overshoot 1772*be771a7bSCy Schubert * more, an accurate number would not overshoot. It is based on the 1773*be771a7bSCy Schubert * stream frame header size. */ 1774*be771a7bSCy Schubert size_t accumulated_send = 0, overhead_stream = 24, overhead_pkt = 60, 1775*be771a7bSCy Schubert max_packet_size = 1200; 1776*be771a7bSCy Schubert size_t num_packets = 0, max_packets = 65535; 1777*be771a7bSCy Schubert ngtcp2_path_storage_zero(&ps); 1778*be771a7bSCy Schubert str = data->query_list_send->first; 1779*be771a7bSCy Schubert 1780*be771a7bSCy Schubert if(data->cc_algo != NGTCP2_CC_ALGO_BBR 1781*be771a7bSCy Schubert #ifdef NGTCP2_CC_ALGO_BBR_V2 1782*be771a7bSCy Schubert && data->cc_algo != NGTCP2_CC_ALGO_BBR_V2 1783*be771a7bSCy Schubert #endif 1784*be771a7bSCy Schubert #ifdef NGTCP2_CC_ALGO_BBR2 1785*be771a7bSCy Schubert && data->cc_algo != NGTCP2_CC_ALGO_BBR2 1786*be771a7bSCy Schubert #endif 1787*be771a7bSCy Schubert ) { 1788*be771a7bSCy Schubert /* If we do not have a packet pacing congestion control 1789*be771a7bSCy Schubert * algorithm, limit the number of packets. */ 1790*be771a7bSCy Schubert max_packets = 10; 1791*be771a7bSCy Schubert } 1792*be771a7bSCy Schubert 1793*be771a7bSCy Schubert /* loop like this, because at the start, the send list is empty, 1794*be771a7bSCy Schubert * and we want to send handshake packets. But when there is a 1795*be771a7bSCy Schubert * send_list, loop through that. */ 1796*be771a7bSCy Schubert for(;;) { 1797*be771a7bSCy Schubert int64_t stream_id; 1798*be771a7bSCy Schubert ngtcp2_pkt_info pi; 1799*be771a7bSCy Schubert ngtcp2_vec datav[2]; 1800*be771a7bSCy Schubert size_t datav_count = 0; 1801*be771a7bSCy Schubert int fin; 1802*be771a7bSCy Schubert ngtcp2_ssize ret; 1803*be771a7bSCy Schubert ngtcp2_ssize ndatalen = 0; 1804*be771a7bSCy Schubert int send_is_blocked = 0; 1805*be771a7bSCy Schubert 1806*be771a7bSCy Schubert if(str) { 1807*be771a7bSCy Schubert /* pick up next in case this one is deleted */ 1808*be771a7bSCy Schubert next = str->next; 1809*be771a7bSCy Schubert if(verbosity > 0) { 1810*be771a7bSCy Schubert char* logs = client_stream_string(str); 1811*be771a7bSCy Schubert verbose(1, "query %s write stream", logs); 1812*be771a7bSCy Schubert free(logs); 1813*be771a7bSCy Schubert } 1814*be771a7bSCy Schubert stream_id = str->stream_id; 1815*be771a7bSCy Schubert fin = 1; 1816*be771a7bSCy Schubert if(str->nwrite < 2) { 1817*be771a7bSCy Schubert str->data_tcplen = htons(str->data_len); 1818*be771a7bSCy Schubert datav[0].base = ((uint8_t*)&str->data_tcplen)+str->nwrite; 1819*be771a7bSCy Schubert datav[0].len = 2-str->nwrite; 1820*be771a7bSCy Schubert datav[1].base = str->data; 1821*be771a7bSCy Schubert datav[1].len = str->data_len; 1822*be771a7bSCy Schubert datav_count = 2; 1823*be771a7bSCy Schubert } else { 1824*be771a7bSCy Schubert datav[0].base = str->data + (str->nwrite-2); 1825*be771a7bSCy Schubert datav[0].len = str->data_len - (str->nwrite-2); 1826*be771a7bSCy Schubert datav_count = 1; 1827*be771a7bSCy Schubert } 1828*be771a7bSCy Schubert } else { 1829*be771a7bSCy Schubert next = NULL; 1830*be771a7bSCy Schubert verbose(1, "write stream -1."); 1831*be771a7bSCy Schubert stream_id = -1; 1832*be771a7bSCy Schubert fin = 0; 1833*be771a7bSCy Schubert datav[0].base = NULL; 1834*be771a7bSCy Schubert datav[0].len = 0; 1835*be771a7bSCy Schubert datav_count = 1; 1836*be771a7bSCy Schubert } 1837*be771a7bSCy Schubert 1838*be771a7bSCy Schubert /* Does the first data entry fit into the send quantum? */ 1839*be771a7bSCy Schubert /* Check if the data size sent, with a max of one full packet, 1840*be771a7bSCy Schubert * with added stream header and packet header is allowed 1841*be771a7bSCy Schubert * within the send quantum number of bytes. If not, it does 1842*be771a7bSCy Schubert * not fit, and wait. */ 1843*be771a7bSCy Schubert if(accumulated_send == 0 && ((datav_count == 1 && 1844*be771a7bSCy Schubert (datav[0].len>max_packet_size?max_packet_size: 1845*be771a7bSCy Schubert datav[0].len)+overhead_stream+overhead_pkt > 1846*be771a7bSCy Schubert send_quantum) || 1847*be771a7bSCy Schubert (datav_count == 2 && 1848*be771a7bSCy Schubert (datav[0].len+datav[1].len>max_packet_size? 1849*be771a7bSCy Schubert max_packet_size:datav[0].len+datav[1].len) 1850*be771a7bSCy Schubert +overhead_stream+overhead_pkt > send_quantum))) { 1851*be771a7bSCy Schubert /* congestion limited */ 1852*be771a7bSCy Schubert ngtcp2_conn_update_pkt_tx_time(data->conn, ts); 1853*be771a7bSCy Schubert event_change_write(data, 0); 1854*be771a7bSCy Schubert /* update the timer to wait until it is possible to 1855*be771a7bSCy Schubert * write again */ 1856*be771a7bSCy Schubert update_timer(data); 1857*be771a7bSCy Schubert return 0; 1858*be771a7bSCy Schubert } 1859*be771a7bSCy Schubert flags = 0; 1860*be771a7bSCy Schubert if(str && str->next != NULL) { 1861*be771a7bSCy Schubert /* Coalesce more data from more streams into this 1862*be771a7bSCy Schubert * packet, if possible */ 1863*be771a7bSCy Schubert /* There is more than one data entry in this send 1864*be771a7bSCy Schubert * quantum, does the next one fit in the quantum? */ 1865*be771a7bSCy Schubert size_t this_send, possible_next_send; 1866*be771a7bSCy Schubert if(datav_count == 1) 1867*be771a7bSCy Schubert this_send = datav[0].len; 1868*be771a7bSCy Schubert else this_send = datav[0].len + datav[1].len; 1869*be771a7bSCy Schubert if(this_send > max_packet_size) 1870*be771a7bSCy Schubert this_send = max_packet_size; 1871*be771a7bSCy Schubert if(str->next->nwrite < 2) 1872*be771a7bSCy Schubert possible_next_send = (2-str->next->nwrite) + 1873*be771a7bSCy Schubert str->next->data_len; 1874*be771a7bSCy Schubert else possible_next_send = str->next->data_len - 1875*be771a7bSCy Schubert (str->next->nwrite - 2); 1876*be771a7bSCy Schubert if(possible_next_send > max_packet_size) 1877*be771a7bSCy Schubert possible_next_send = max_packet_size; 1878*be771a7bSCy Schubert /* Check if the data lengths that writev returned 1879*be771a7bSCy Schubert * with stream headers added up so far, in 1880*be771a7bSCy Schubert * accumulated_send, with added the data length 1881*be771a7bSCy Schubert * of this send, with a max of one full packet, and 1882*be771a7bSCy Schubert * the data length of the next possible send, with 1883*be771a7bSCy Schubert * a max of one full packet, with a stream header for 1884*be771a7bSCy Schubert * this_send and a stream header for the next possible 1885*be771a7bSCy Schubert * send and a packet header, fit in the send quantum 1886*be771a7bSCy Schubert * number of bytes. If so, ask to add more content 1887*be771a7bSCy Schubert * to the packet with the more flag. */ 1888*be771a7bSCy Schubert if(accumulated_send + this_send + possible_next_send 1889*be771a7bSCy Schubert +2*overhead_stream+ overhead_pkt < send_quantum) 1890*be771a7bSCy Schubert flags |= NGTCP2_WRITE_STREAM_FLAG_MORE; 1891*be771a7bSCy Schubert } 1892*be771a7bSCy Schubert if(fin) { 1893*be771a7bSCy Schubert /* This is the final part of data for this stream */ 1894*be771a7bSCy Schubert flags |= NGTCP2_WRITE_STREAM_FLAG_FIN; 1895*be771a7bSCy Schubert } 1896*be771a7bSCy Schubert sldns_buffer_clear(data->pkt_buf); 1897*be771a7bSCy Schubert ret = ngtcp2_conn_writev_stream(data->conn, &ps.path, &pi, 1898*be771a7bSCy Schubert sldns_buffer_begin(data->pkt_buf), 1899*be771a7bSCy Schubert sldns_buffer_remaining(data->pkt_buf), &ndatalen, 1900*be771a7bSCy Schubert flags, stream_id, datav, datav_count, ts); 1901*be771a7bSCy Schubert if(ret < 0) { 1902*be771a7bSCy Schubert if(ret == NGTCP2_ERR_WRITE_MORE) { 1903*be771a7bSCy Schubert if(str) { 1904*be771a7bSCy Schubert str->nwrite += ndatalen; 1905*be771a7bSCy Schubert if(str->nwrite >= str->data_len+2) 1906*be771a7bSCy Schubert query_write_is_done(data, str); 1907*be771a7bSCy Schubert str = next; 1908*be771a7bSCy Schubert accumulated_send += ndatalen + overhead_stream; 1909*be771a7bSCy Schubert continue; 1910*be771a7bSCy Schubert } 1911*be771a7bSCy Schubert } 1912*be771a7bSCy Schubert log_err("ngtcp2_conn_writev_stream failed: %s", 1913*be771a7bSCy Schubert ngtcp2_strerror(ret)); 1914*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 1915*be771a7bSCy Schubert ngtcp2_ccerr_set_liberr(&data->ccerr, ret, NULL, 0); 1916*be771a7bSCy Schubert #else 1917*be771a7bSCy Schubert ngtcp2_connection_close_error_set_transport_error_liberr( 1918*be771a7bSCy Schubert &data->last_error, ret, NULL, 0); 1919*be771a7bSCy Schubert #endif 1920*be771a7bSCy Schubert disconnect(data); 1921*be771a7bSCy Schubert return 0; 1922*be771a7bSCy Schubert } 1923*be771a7bSCy Schubert verbose(1, "writev_stream pkt size %d ndatawritten %d", 1924*be771a7bSCy Schubert (int)ret, (int)ndatalen); 1925*be771a7bSCy Schubert if(ndatalen >= 0 && str) { 1926*be771a7bSCy Schubert /* add the new write offset */ 1927*be771a7bSCy Schubert str->nwrite += ndatalen; 1928*be771a7bSCy Schubert if(str->nwrite >= str->data_len+2) 1929*be771a7bSCy Schubert query_write_is_done(data, str); 1930*be771a7bSCy Schubert } 1931*be771a7bSCy Schubert if(ret == 0) { 1932*be771a7bSCy Schubert /* congestion limited */ 1933*be771a7bSCy Schubert ngtcp2_conn_update_pkt_tx_time(data->conn, ts); 1934*be771a7bSCy Schubert event_change_write(data, 0); 1935*be771a7bSCy Schubert /* update the timer to wait until it is possible to 1936*be771a7bSCy Schubert * write again */ 1937*be771a7bSCy Schubert update_timer(data); 1938*be771a7bSCy Schubert return 0; 1939*be771a7bSCy Schubert } 1940*be771a7bSCy Schubert if(!doq_client_send_pkt(data, pi.ecn, 1941*be771a7bSCy Schubert sldns_buffer_begin(data->pkt_buf), ret, 0, 1942*be771a7bSCy Schubert &send_is_blocked)) { 1943*be771a7bSCy Schubert if(send_is_blocked) { 1944*be771a7bSCy Schubert /* Blocked packet, wait until it is possible 1945*be771a7bSCy Schubert * to write again and also set a timer. */ 1946*be771a7bSCy Schubert event_change_write(data, 1); 1947*be771a7bSCy Schubert update_timer(data); 1948*be771a7bSCy Schubert return 0; 1949*be771a7bSCy Schubert } 1950*be771a7bSCy Schubert /* Packet could not be sent. Like lost and timeout. */ 1951*be771a7bSCy Schubert ngtcp2_conn_update_pkt_tx_time(data->conn, ts); 1952*be771a7bSCy Schubert event_change_write(data, 0); 1953*be771a7bSCy Schubert update_timer(data); 1954*be771a7bSCy Schubert return 0; 1955*be771a7bSCy Schubert } 1956*be771a7bSCy Schubert /* continue */ 1957*be771a7bSCy Schubert if((size_t)ret >= send_quantum) 1958*be771a7bSCy Schubert break; 1959*be771a7bSCy Schubert send_quantum -= ret; 1960*be771a7bSCy Schubert accumulated_send = 0; 1961*be771a7bSCy Schubert str = next; 1962*be771a7bSCy Schubert if(str == NULL) 1963*be771a7bSCy Schubert break; 1964*be771a7bSCy Schubert if(++num_packets == max_packets) 1965*be771a7bSCy Schubert break; 1966*be771a7bSCy Schubert } 1967*be771a7bSCy Schubert ngtcp2_conn_update_pkt_tx_time(data->conn, ts); 1968*be771a7bSCy Schubert event_change_write(data, 1); 1969*be771a7bSCy Schubert return 1; 1970*be771a7bSCy Schubert } 1971*be771a7bSCy Schubert 1972*be771a7bSCy Schubert /** send the blocked packet now that the stream is writable again. */ 1973*be771a7bSCy Schubert static int 1974*be771a7bSCy Schubert send_blocked_pkt(struct doq_client_data* data) 1975*be771a7bSCy Schubert { 1976*be771a7bSCy Schubert ngtcp2_tstamp ts = get_timestamp_nanosec(); 1977*be771a7bSCy Schubert int send_is_blocked = 0; 1978*be771a7bSCy Schubert if(!doq_client_send_pkt(data, data->blocked_pkt_pi.ecn, 1979*be771a7bSCy Schubert sldns_buffer_begin(data->pkt_buf), 1980*be771a7bSCy Schubert sldns_buffer_limit(data->pkt_buf), 1, &send_is_blocked)) { 1981*be771a7bSCy Schubert if(send_is_blocked) { 1982*be771a7bSCy Schubert /* Send was blocked, again. Wait, again to retry. */ 1983*be771a7bSCy Schubert event_change_write(data, 1); 1984*be771a7bSCy Schubert /* make sure the timer is set while waiting */ 1985*be771a7bSCy Schubert update_timer(data); 1986*be771a7bSCy Schubert return 0; 1987*be771a7bSCy Schubert } 1988*be771a7bSCy Schubert /* The packed could not be sent. Like it was lost, timeout. */ 1989*be771a7bSCy Schubert data->have_blocked_pkt = 0; 1990*be771a7bSCy Schubert ngtcp2_conn_update_pkt_tx_time(data->conn, ts); 1991*be771a7bSCy Schubert event_change_write(data, 0); 1992*be771a7bSCy Schubert update_timer(data); 1993*be771a7bSCy Schubert return 0; 1994*be771a7bSCy Schubert } 1995*be771a7bSCy Schubert /* The blocked packet has been sent, the holding buffer can be 1996*be771a7bSCy Schubert * cleared. */ 1997*be771a7bSCy Schubert data->have_blocked_pkt = 0; 1998*be771a7bSCy Schubert ngtcp2_conn_update_pkt_tx_time(data->conn, ts); 1999*be771a7bSCy Schubert return 1; 2000*be771a7bSCy Schubert } 2001*be771a7bSCy Schubert 2002*be771a7bSCy Schubert /** perform write operations, if any, on fd */ 2003*be771a7bSCy Schubert static void 2004*be771a7bSCy Schubert on_write(struct doq_client_data* data) 2005*be771a7bSCy Schubert { 2006*be771a7bSCy Schubert if(data->have_blocked_pkt) { 2007*be771a7bSCy Schubert if(!send_blocked_pkt(data)) 2008*be771a7bSCy Schubert return; 2009*be771a7bSCy Schubert } 2010*be771a7bSCy Schubert if( 2011*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD 2012*be771a7bSCy Schubert ngtcp2_conn_in_closing_period(data->conn) 2013*be771a7bSCy Schubert #else 2014*be771a7bSCy Schubert ngtcp2_conn_is_in_closing_period(data->conn) 2015*be771a7bSCy Schubert #endif 2016*be771a7bSCy Schubert ) 2017*be771a7bSCy Schubert return; 2018*be771a7bSCy Schubert if(!write_streams(data)) 2019*be771a7bSCy Schubert return; 2020*be771a7bSCy Schubert update_timer(data); 2021*be771a7bSCy Schubert } 2022*be771a7bSCy Schubert 2023*be771a7bSCy Schubert /** callback for main listening file descriptor */ 2024*be771a7bSCy Schubert void 2025*be771a7bSCy Schubert doq_client_event_cb(int ATTR_UNUSED(fd), short bits, void* arg) 2026*be771a7bSCy Schubert { 2027*be771a7bSCy Schubert struct doq_client_data* data = (struct doq_client_data*)arg; 2028*be771a7bSCy Schubert verbose(1, "doq_client_event_cb %s%s%s", 2029*be771a7bSCy Schubert ((bits&UB_EV_READ)!=0?"EV_READ":""), 2030*be771a7bSCy Schubert ((bits&(UB_EV_READ|UB_EV_WRITE))==(UB_EV_READ|UB_EV_WRITE)? 2031*be771a7bSCy Schubert " ":""), 2032*be771a7bSCy Schubert ((bits&UB_EV_WRITE)!=0?"EV_WRITE":"")); 2033*be771a7bSCy Schubert if((bits&UB_EV_READ)) { 2034*be771a7bSCy Schubert on_read(data); 2035*be771a7bSCy Schubert } 2036*be771a7bSCy Schubert /* Perform the write operation anyway. The read operation may 2037*be771a7bSCy Schubert * have produced data, or there is content waiting and it is possible 2038*be771a7bSCy Schubert * to write that. */ 2039*be771a7bSCy Schubert on_write(data); 2040*be771a7bSCy Schubert } 2041*be771a7bSCy Schubert 2042*be771a7bSCy Schubert /** read the TLS session from file */ 2043*be771a7bSCy Schubert static int 2044*be771a7bSCy Schubert early_data_setup_session(struct doq_client_data* data) 2045*be771a7bSCy Schubert { 2046*be771a7bSCy Schubert SSL_SESSION* session; 2047*be771a7bSCy Schubert BIO* f = BIO_new_file(data->session_file, "r"); 2048*be771a7bSCy Schubert if(f == NULL) { 2049*be771a7bSCy Schubert if(errno == ENOENT) { 2050*be771a7bSCy Schubert verbose(1, "session file %s does not exist", 2051*be771a7bSCy Schubert data->session_file); 2052*be771a7bSCy Schubert return 0; 2053*be771a7bSCy Schubert } 2054*be771a7bSCy Schubert log_err("Could not read %s: %s", data->session_file, 2055*be771a7bSCy Schubert strerror(errno)); 2056*be771a7bSCy Schubert return 0; 2057*be771a7bSCy Schubert } 2058*be771a7bSCy Schubert session = PEM_read_bio_SSL_SESSION(f, NULL, 0, NULL); 2059*be771a7bSCy Schubert if(session == NULL) { 2060*be771a7bSCy Schubert log_crypto_err("Could not read session file with PEM_read_bio_SSL_SESSION"); 2061*be771a7bSCy Schubert BIO_free(f); 2062*be771a7bSCy Schubert return 0; 2063*be771a7bSCy Schubert } 2064*be771a7bSCy Schubert BIO_free(f); 2065*be771a7bSCy Schubert if(!SSL_set_session(data->ssl, session)) { 2066*be771a7bSCy Schubert log_crypto_err("Could not SSL_set_session"); 2067*be771a7bSCy Schubert SSL_SESSION_free(session); 2068*be771a7bSCy Schubert return 0; 2069*be771a7bSCy Schubert } 2070*be771a7bSCy Schubert if(SSL_SESSION_get_max_early_data(session) == 0) { 2071*be771a7bSCy Schubert log_err("TLS session early data is 0"); 2072*be771a7bSCy Schubert SSL_SESSION_free(session); 2073*be771a7bSCy Schubert return 0; 2074*be771a7bSCy Schubert } 2075*be771a7bSCy Schubert SSL_set_quic_early_data_enabled(data->ssl, 1); 2076*be771a7bSCy Schubert SSL_SESSION_free(session); 2077*be771a7bSCy Schubert return 1; 2078*be771a7bSCy Schubert } 2079*be771a7bSCy Schubert 2080*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS 2081*be771a7bSCy Schubert /** parse one line from the transport file */ 2082*be771a7bSCy Schubert static int 2083*be771a7bSCy Schubert transport_parse_line(struct ngtcp2_transport_params* params, char* line) 2084*be771a7bSCy Schubert { 2085*be771a7bSCy Schubert if(strncmp(line, "initial_max_streams_bidi=", 25) == 0) { 2086*be771a7bSCy Schubert params->initial_max_streams_bidi = atoi(line+25); 2087*be771a7bSCy Schubert return 1; 2088*be771a7bSCy Schubert } 2089*be771a7bSCy Schubert if(strncmp(line, "initial_max_streams_uni=", 24) == 0) { 2090*be771a7bSCy Schubert params->initial_max_streams_uni = atoi(line+24); 2091*be771a7bSCy Schubert return 1; 2092*be771a7bSCy Schubert } 2093*be771a7bSCy Schubert if(strncmp(line, "initial_max_stream_data_bidi_local=", 35) == 0) { 2094*be771a7bSCy Schubert params->initial_max_stream_data_bidi_local = atoi(line+35); 2095*be771a7bSCy Schubert return 1; 2096*be771a7bSCy Schubert } 2097*be771a7bSCy Schubert if(strncmp(line, "initial_max_stream_data_bidi_remote=", 36) == 0) { 2098*be771a7bSCy Schubert params->initial_max_stream_data_bidi_remote = atoi(line+36); 2099*be771a7bSCy Schubert return 1; 2100*be771a7bSCy Schubert } 2101*be771a7bSCy Schubert if(strncmp(line, "initial_max_stream_data_uni=", 28) == 0) { 2102*be771a7bSCy Schubert params->initial_max_stream_data_uni = atoi(line+28); 2103*be771a7bSCy Schubert return 1; 2104*be771a7bSCy Schubert } 2105*be771a7bSCy Schubert if(strncmp(line, "initial_max_data=", 17) == 0) { 2106*be771a7bSCy Schubert params->initial_max_data = atoi(line+17); 2107*be771a7bSCy Schubert return 1; 2108*be771a7bSCy Schubert } 2109*be771a7bSCy Schubert if(strncmp(line, "active_connection_id_limit=", 27) == 0) { 2110*be771a7bSCy Schubert params->active_connection_id_limit = atoi(line+27); 2111*be771a7bSCy Schubert return 1; 2112*be771a7bSCy Schubert } 2113*be771a7bSCy Schubert if(strncmp(line, "max_datagram_frame_size=", 24) == 0) { 2114*be771a7bSCy Schubert params->max_datagram_frame_size = atoi(line+24); 2115*be771a7bSCy Schubert return 1; 2116*be771a7bSCy Schubert } 2117*be771a7bSCy Schubert return 0; 2118*be771a7bSCy Schubert } 2119*be771a7bSCy Schubert #endif /* HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS */ 2120*be771a7bSCy Schubert 2121*be771a7bSCy Schubert /** setup the early data transport file and read it */ 2122*be771a7bSCy Schubert static int 2123*be771a7bSCy Schubert early_data_setup_transport(struct doq_client_data* data) 2124*be771a7bSCy Schubert { 2125*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS 2126*be771a7bSCy Schubert FILE* in; 2127*be771a7bSCy Schubert uint8_t buf[1024]; 2128*be771a7bSCy Schubert size_t len; 2129*be771a7bSCy Schubert int rv; 2130*be771a7bSCy Schubert in = fopen(data->transport_file, "r"); 2131*be771a7bSCy Schubert if(!in) { 2132*be771a7bSCy Schubert if(errno == ENOENT) { 2133*be771a7bSCy Schubert verbose(1, "transport file %s does not exist", 2134*be771a7bSCy Schubert data->transport_file); 2135*be771a7bSCy Schubert return 0; 2136*be771a7bSCy Schubert } 2137*be771a7bSCy Schubert perror(data->transport_file); 2138*be771a7bSCy Schubert return 0; 2139*be771a7bSCy Schubert } 2140*be771a7bSCy Schubert len = fread(buf, 1, sizeof(buf), in); 2141*be771a7bSCy Schubert if(ferror(in)) { 2142*be771a7bSCy Schubert log_err("%s: read failed: %s", data->transport_file, 2143*be771a7bSCy Schubert strerror(errno)); 2144*be771a7bSCy Schubert fclose(in); 2145*be771a7bSCy Schubert return 0; 2146*be771a7bSCy Schubert } 2147*be771a7bSCy Schubert fclose(in); 2148*be771a7bSCy Schubert rv = ngtcp2_conn_decode_and_set_0rtt_transport_params(data->conn, 2149*be771a7bSCy Schubert buf, len); 2150*be771a7bSCy Schubert if(rv != 0) { 2151*be771a7bSCy Schubert log_err("ngtcp2_conn_decode_and_set_0rtt_transport_params failed: %s", 2152*be771a7bSCy Schubert ngtcp2_strerror(rv)); 2153*be771a7bSCy Schubert return 0; 2154*be771a7bSCy Schubert } 2155*be771a7bSCy Schubert return 1; 2156*be771a7bSCy Schubert #else 2157*be771a7bSCy Schubert FILE* in; 2158*be771a7bSCy Schubert char buf[1024]; 2159*be771a7bSCy Schubert struct ngtcp2_transport_params params; 2160*be771a7bSCy Schubert memset(¶ms, 0, sizeof(params)); 2161*be771a7bSCy Schubert in = fopen(data->transport_file, "r"); 2162*be771a7bSCy Schubert if(!in) { 2163*be771a7bSCy Schubert if(errno == ENOENT) { 2164*be771a7bSCy Schubert verbose(1, "transport file %s does not exist", 2165*be771a7bSCy Schubert data->transport_file); 2166*be771a7bSCy Schubert return 0; 2167*be771a7bSCy Schubert } 2168*be771a7bSCy Schubert perror(data->transport_file); 2169*be771a7bSCy Schubert return 0; 2170*be771a7bSCy Schubert } 2171*be771a7bSCy Schubert while(!feof(in)) { 2172*be771a7bSCy Schubert if(!fgets(buf, sizeof(buf), in)) { 2173*be771a7bSCy Schubert log_err("%s: read failed: %s", data->transport_file, 2174*be771a7bSCy Schubert strerror(errno)); 2175*be771a7bSCy Schubert fclose(in); 2176*be771a7bSCy Schubert return 0; 2177*be771a7bSCy Schubert } 2178*be771a7bSCy Schubert if(!transport_parse_line(¶ms, buf)) { 2179*be771a7bSCy Schubert log_err("%s: could not parse line '%s'", 2180*be771a7bSCy Schubert data->transport_file, buf); 2181*be771a7bSCy Schubert fclose(in); 2182*be771a7bSCy Schubert return 0; 2183*be771a7bSCy Schubert } 2184*be771a7bSCy Schubert } 2185*be771a7bSCy Schubert fclose(in); 2186*be771a7bSCy Schubert ngtcp2_conn_set_early_remote_transport_params(data->conn, ¶ms); 2187*be771a7bSCy Schubert #endif 2188*be771a7bSCy Schubert return 1; 2189*be771a7bSCy Schubert } 2190*be771a7bSCy Schubert 2191*be771a7bSCy Schubert /** setup for early data, read the transport file and session file */ 2192*be771a7bSCy Schubert static void 2193*be771a7bSCy Schubert early_data_setup(struct doq_client_data* data) 2194*be771a7bSCy Schubert { 2195*be771a7bSCy Schubert if(!early_data_setup_session(data)) { 2196*be771a7bSCy Schubert verbose(1, "TLS session resumption failed, early data is disabled"); 2197*be771a7bSCy Schubert data->early_data_enabled = 0; 2198*be771a7bSCy Schubert return; 2199*be771a7bSCy Schubert } 2200*be771a7bSCy Schubert if(!early_data_setup_transport(data)) { 2201*be771a7bSCy Schubert verbose(1, "Transport parameters set failed, early data is disabled"); 2202*be771a7bSCy Schubert data->early_data_enabled = 0; 2203*be771a7bSCy Schubert return; 2204*be771a7bSCy Schubert } 2205*be771a7bSCy Schubert } 2206*be771a7bSCy Schubert 2207*be771a7bSCy Schubert /** start the early data transmission */ 2208*be771a7bSCy Schubert static void 2209*be771a7bSCy Schubert early_data_start(struct doq_client_data* data) 2210*be771a7bSCy Schubert { 2211*be771a7bSCy Schubert query_streams_start(data); 2212*be771a7bSCy Schubert on_write(data); 2213*be771a7bSCy Schubert } 2214*be771a7bSCy Schubert 2215*be771a7bSCy Schubert /** create doq_client_data */ 2216*be771a7bSCy Schubert static struct doq_client_data* 2217*be771a7bSCy Schubert create_doq_client_data(const char* svr, int port, struct ub_event_base* base, 2218*be771a7bSCy Schubert const char* transport_file, const char* session_file, int quiet) 2219*be771a7bSCy Schubert { 2220*be771a7bSCy Schubert struct doq_client_data* data; 2221*be771a7bSCy Schubert data = calloc(1, sizeof(*data)); 2222*be771a7bSCy Schubert if(!data) fatal_exit("calloc failed: out of memory"); 2223*be771a7bSCy Schubert data->base = base; 2224*be771a7bSCy Schubert data->rnd = ub_initstate(NULL); 2225*be771a7bSCy Schubert if(!data->rnd) fatal_exit("ub_initstate failed: out of memory"); 2226*be771a7bSCy Schubert data->svr = svr; 2227*be771a7bSCy Schubert get_dest_addr(data, svr, port); 2228*be771a7bSCy Schubert data->port = port; 2229*be771a7bSCy Schubert data->quiet = quiet; 2230*be771a7bSCy Schubert data->pkt_buf = sldns_buffer_new(65552); 2231*be771a7bSCy Schubert if(!data->pkt_buf) 2232*be771a7bSCy Schubert fatal_exit("sldns_buffer_new failed: out of memory"); 2233*be771a7bSCy Schubert data->blocked_pkt = sldns_buffer_new(65552); 2234*be771a7bSCy Schubert if(!data->blocked_pkt) 2235*be771a7bSCy Schubert fatal_exit("sldns_buffer_new failed: out of memory"); 2236*be771a7bSCy Schubert data->fd = open_svr_udp(data); 2237*be771a7bSCy Schubert get_local_addr(data); 2238*be771a7bSCy Schubert data->conn = conn_client_setup(data); 2239*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT 2240*be771a7bSCy Schubert ngtcp2_ccerr_default(&data->ccerr); 2241*be771a7bSCy Schubert #else 2242*be771a7bSCy Schubert ngtcp2_connection_close_error_default(&data->last_error); 2243*be771a7bSCy Schubert #endif 2244*be771a7bSCy Schubert data->transport_file = transport_file; 2245*be771a7bSCy Schubert data->session_file = session_file; 2246*be771a7bSCy Schubert if(data->transport_file && data->session_file) 2247*be771a7bSCy Schubert data->early_data_enabled = 1; 2248*be771a7bSCy Schubert 2249*be771a7bSCy Schubert generate_static_secret(data, 32); 2250*be771a7bSCy Schubert data->ctx = ctx_client_setup(); 2251*be771a7bSCy Schubert if(data->session_file) { 2252*be771a7bSCy Schubert SSL_CTX_set_session_cache_mode(data->ctx, 2253*be771a7bSCy Schubert SSL_SESS_CACHE_CLIENT | 2254*be771a7bSCy Schubert SSL_SESS_CACHE_NO_INTERNAL_STORE); 2255*be771a7bSCy Schubert SSL_CTX_sess_set_new_cb(data->ctx, new_session_cb); 2256*be771a7bSCy Schubert } 2257*be771a7bSCy Schubert data->ssl = ssl_client_setup(data); 2258*be771a7bSCy Schubert ngtcp2_conn_set_tls_native_handle(data->conn, data->ssl); 2259*be771a7bSCy Schubert if(data->early_data_enabled) 2260*be771a7bSCy Schubert early_data_setup(data); 2261*be771a7bSCy Schubert 2262*be771a7bSCy Schubert data->ev = ub_event_new(base, data->fd, UB_EV_READ | UB_EV_WRITE | 2263*be771a7bSCy Schubert UB_EV_PERSIST, doq_client_event_cb, data); 2264*be771a7bSCy Schubert if(!data->ev) { 2265*be771a7bSCy Schubert fatal_exit("could not ub_event_new"); 2266*be771a7bSCy Schubert } 2267*be771a7bSCy Schubert if(ub_event_add(data->ev, NULL) != 0) { 2268*be771a7bSCy Schubert fatal_exit("could not ub_event_add"); 2269*be771a7bSCy Schubert } 2270*be771a7bSCy Schubert data->expire_timer = ub_event_new(data->base, -1, 2271*be771a7bSCy Schubert UB_EV_TIMEOUT, &doq_client_timer_cb, data); 2272*be771a7bSCy Schubert if(!data->expire_timer) 2273*be771a7bSCy Schubert fatal_exit("could not ub_event_new"); 2274*be771a7bSCy Schubert data->query_list_start = stream_list_create(); 2275*be771a7bSCy Schubert data->query_list_send = stream_list_create(); 2276*be771a7bSCy Schubert data->query_list_receive = stream_list_create(); 2277*be771a7bSCy Schubert data->query_list_stop = stream_list_create(); 2278*be771a7bSCy Schubert return data; 2279*be771a7bSCy Schubert } 2280*be771a7bSCy Schubert 2281*be771a7bSCy Schubert /** delete doq_client_data */ 2282*be771a7bSCy Schubert static void 2283*be771a7bSCy Schubert delete_doq_client_data(struct doq_client_data* data) 2284*be771a7bSCy Schubert { 2285*be771a7bSCy Schubert if(!data) 2286*be771a7bSCy Schubert return; 2287*be771a7bSCy Schubert #if defined(NGTCP2_USE_GENERIC_SOCKADDR) || defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR) 2288*be771a7bSCy Schubert if(data->conn && data->dest_addr_len != 0) { 2289*be771a7bSCy Schubert if(addr_is_ip6(&data->dest_addr, data->dest_addr_len)) { 2290*be771a7bSCy Schubert # if defined(NGTCP2_USE_GENERIC_SOCKADDR) || defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR) 2291*be771a7bSCy Schubert const struct ngtcp2_path* path6 = ngtcp2_conn_get_path(data->conn); 2292*be771a7bSCy Schubert free(path6->local.addr); 2293*be771a7bSCy Schubert free(path6->remote.addr); 2294*be771a7bSCy Schubert # endif 2295*be771a7bSCy Schubert } else { 2296*be771a7bSCy Schubert # if defined(NGTCP2_USE_GENERIC_SOCKADDR) 2297*be771a7bSCy Schubert const struct ngtcp2_path* path = ngtcp2_conn_get_path(data->conn); 2298*be771a7bSCy Schubert free(path->local.addr); 2299*be771a7bSCy Schubert free(path->remote.addr); 2300*be771a7bSCy Schubert # endif 2301*be771a7bSCy Schubert } 2302*be771a7bSCy Schubert } 2303*be771a7bSCy Schubert #endif 2304*be771a7bSCy Schubert ngtcp2_conn_del(data->conn); 2305*be771a7bSCy Schubert SSL_free(data->ssl); 2306*be771a7bSCy Schubert sldns_buffer_free(data->pkt_buf); 2307*be771a7bSCy Schubert sldns_buffer_free(data->blocked_pkt); 2308*be771a7bSCy Schubert if(data->fd != -1) 2309*be771a7bSCy Schubert sock_close(data->fd); 2310*be771a7bSCy Schubert SSL_CTX_free(data->ctx); 2311*be771a7bSCy Schubert stream_list_free(data->query_list_start); 2312*be771a7bSCy Schubert stream_list_free(data->query_list_send); 2313*be771a7bSCy Schubert stream_list_free(data->query_list_receive); 2314*be771a7bSCy Schubert stream_list_free(data->query_list_stop); 2315*be771a7bSCy Schubert ub_randfree(data->rnd); 2316*be771a7bSCy Schubert if(data->ev) { 2317*be771a7bSCy Schubert ub_event_del(data->ev); 2318*be771a7bSCy Schubert ub_event_free(data->ev); 2319*be771a7bSCy Schubert } 2320*be771a7bSCy Schubert if(data->expire_timer_added) 2321*be771a7bSCy Schubert ub_timer_del(data->expire_timer); 2322*be771a7bSCy Schubert ub_event_free(data->expire_timer); 2323*be771a7bSCy Schubert free(data->static_secret_data); 2324*be771a7bSCy Schubert free(data); 2325*be771a7bSCy Schubert } 2326*be771a7bSCy Schubert 2327*be771a7bSCy Schubert /** create the event base that registers events and timers */ 2328*be771a7bSCy Schubert static struct ub_event_base* 2329*be771a7bSCy Schubert create_event_base(time_t* secs, struct timeval* now) 2330*be771a7bSCy Schubert { 2331*be771a7bSCy Schubert struct ub_event_base* base; 2332*be771a7bSCy Schubert const char *evnm="event", *evsys="", *evmethod=""; 2333*be771a7bSCy Schubert 2334*be771a7bSCy Schubert memset(now, 0, sizeof(*now)); 2335*be771a7bSCy Schubert base = ub_default_event_base(1, secs, now); 2336*be771a7bSCy Schubert if(!base) fatal_exit("could not create ub_event base"); 2337*be771a7bSCy Schubert 2338*be771a7bSCy Schubert ub_get_event_sys(base, &evnm, &evsys, &evmethod); 2339*be771a7bSCy Schubert if(verbosity) log_info("%s %s uses %s method", evnm, evsys, evmethod); 2340*be771a7bSCy Schubert 2341*be771a7bSCy Schubert return base; 2342*be771a7bSCy Schubert } 2343*be771a7bSCy Schubert 2344*be771a7bSCy Schubert /** enter a query into the query list */ 2345*be771a7bSCy Schubert static void 2346*be771a7bSCy Schubert client_enter_query_buf(struct doq_client_data* data, struct sldns_buffer* buf) 2347*be771a7bSCy Schubert { 2348*be771a7bSCy Schubert struct doq_client_stream* str; 2349*be771a7bSCy Schubert str = client_stream_create(buf); 2350*be771a7bSCy Schubert if(!str) 2351*be771a7bSCy Schubert fatal_exit("client_stream_create failed: out of memory"); 2352*be771a7bSCy Schubert stream_list_append(data->query_list_start, str); 2353*be771a7bSCy Schubert } 2354*be771a7bSCy Schubert 2355*be771a7bSCy Schubert /** enter the queries into the query list */ 2356*be771a7bSCy Schubert static void 2357*be771a7bSCy Schubert client_enter_queries(struct doq_client_data* data, char** qs, int count) 2358*be771a7bSCy Schubert { 2359*be771a7bSCy Schubert int i; 2360*be771a7bSCy Schubert for(i=0; i<count; i+=3) { 2361*be771a7bSCy Schubert struct sldns_buffer* buf = NULL; 2362*be771a7bSCy Schubert buf = make_query(qs[i], qs[i+1], qs[i+2]); 2363*be771a7bSCy Schubert if(verbosity > 0) { 2364*be771a7bSCy Schubert char* str; 2365*be771a7bSCy Schubert log_buf(1, "send query", buf); 2366*be771a7bSCy Schubert str = sldns_wire2str_pkt(sldns_buffer_begin(buf), 2367*be771a7bSCy Schubert sldns_buffer_limit(buf)); 2368*be771a7bSCy Schubert if(!str) verbose(1, "could not sldns_wire2str_pkt"); 2369*be771a7bSCy Schubert else verbose(1, "send query:\n%s", str); 2370*be771a7bSCy Schubert free(str); 2371*be771a7bSCy Schubert } 2372*be771a7bSCy Schubert client_enter_query_buf(data, buf); 2373*be771a7bSCy Schubert sldns_buffer_free(buf); 2374*be771a7bSCy Schubert } 2375*be771a7bSCy Schubert } 2376*be771a7bSCy Schubert 2377*be771a7bSCy Schubert /** run the dohclient queries */ 2378*be771a7bSCy Schubert static void run(const char* svr, int port, char** qs, int count, 2379*be771a7bSCy Schubert const char* transport_file, const char* session_file, int quiet) 2380*be771a7bSCy Schubert { 2381*be771a7bSCy Schubert time_t secs = 0; 2382*be771a7bSCy Schubert struct timeval now; 2383*be771a7bSCy Schubert struct ub_event_base* base; 2384*be771a7bSCy Schubert struct doq_client_data* data; 2385*be771a7bSCy Schubert 2386*be771a7bSCy Schubert /* setup */ 2387*be771a7bSCy Schubert base = create_event_base(&secs, &now); 2388*be771a7bSCy Schubert data = create_doq_client_data(svr, port, base, transport_file, 2389*be771a7bSCy Schubert session_file, quiet); 2390*be771a7bSCy Schubert client_enter_queries(data, qs, count); 2391*be771a7bSCy Schubert if(data->early_data_enabled) 2392*be771a7bSCy Schubert early_data_start(data); 2393*be771a7bSCy Schubert 2394*be771a7bSCy Schubert /* run the queries */ 2395*be771a7bSCy Schubert ub_event_base_dispatch(base); 2396*be771a7bSCy Schubert 2397*be771a7bSCy Schubert /* cleanup */ 2398*be771a7bSCy Schubert delete_doq_client_data(data); 2399*be771a7bSCy Schubert ub_event_base_free(base); 2400*be771a7bSCy Schubert } 2401*be771a7bSCy Schubert #endif /* HAVE_NGTCP2 */ 2402*be771a7bSCy Schubert 2403*be771a7bSCy Schubert #ifdef HAVE_NGTCP2 2404*be771a7bSCy Schubert /** getopt global, in case header files fail to declare it. */ 2405*be771a7bSCy Schubert extern int optind; 2406*be771a7bSCy Schubert /** getopt global, in case header files fail to declare it. */ 2407*be771a7bSCy Schubert extern char* optarg; 2408*be771a7bSCy Schubert int main(int ATTR_UNUSED(argc), char** ATTR_UNUSED(argv)) 2409*be771a7bSCy Schubert { 2410*be771a7bSCy Schubert int c; 2411*be771a7bSCy Schubert int port = UNBOUND_DNS_OVER_QUIC_PORT, quiet = 0; 2412*be771a7bSCy Schubert const char* svr = "127.0.0.1", *transport_file = NULL, 2413*be771a7bSCy Schubert *session_file = NULL; 2414*be771a7bSCy Schubert #ifdef USE_WINSOCK 2415*be771a7bSCy Schubert WSADATA wsa_data; 2416*be771a7bSCy Schubert if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) { 2417*be771a7bSCy Schubert printf("WSAStartup failed\n"); 2418*be771a7bSCy Schubert return 1; 2419*be771a7bSCy Schubert } 2420*be771a7bSCy Schubert #endif 2421*be771a7bSCy Schubert checklock_set_output_name("ublocktrace-doqclient"); 2422*be771a7bSCy Schubert checklock_start(); 2423*be771a7bSCy Schubert log_init(0, 0, 0); 2424*be771a7bSCy Schubert log_ident_set("doqclient"); 2425*be771a7bSCy Schubert 2426*be771a7bSCy Schubert while((c=getopt(argc, argv, "hp:qs:vx:y:")) != -1) { 2427*be771a7bSCy Schubert switch(c) { 2428*be771a7bSCy Schubert case 'p': 2429*be771a7bSCy Schubert if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) { 2430*be771a7bSCy Schubert printf("error parsing port, " 2431*be771a7bSCy Schubert "number expected: %s\n", optarg); 2432*be771a7bSCy Schubert return 1; 2433*be771a7bSCy Schubert } 2434*be771a7bSCy Schubert port = atoi(optarg); 2435*be771a7bSCy Schubert break; 2436*be771a7bSCy Schubert case 'q': 2437*be771a7bSCy Schubert quiet++; 2438*be771a7bSCy Schubert break; 2439*be771a7bSCy Schubert case 's': 2440*be771a7bSCy Schubert svr = optarg; 2441*be771a7bSCy Schubert break; 2442*be771a7bSCy Schubert case 'v': 2443*be771a7bSCy Schubert verbosity++; 2444*be771a7bSCy Schubert break; 2445*be771a7bSCy Schubert case 'x': 2446*be771a7bSCy Schubert transport_file = optarg; 2447*be771a7bSCy Schubert break; 2448*be771a7bSCy Schubert case 'y': 2449*be771a7bSCy Schubert session_file = optarg; 2450*be771a7bSCy Schubert break; 2451*be771a7bSCy Schubert case 'h': 2452*be771a7bSCy Schubert case '?': 2453*be771a7bSCy Schubert default: 2454*be771a7bSCy Schubert usage(argv); 2455*be771a7bSCy Schubert } 2456*be771a7bSCy Schubert } 2457*be771a7bSCy Schubert 2458*be771a7bSCy Schubert argc -= optind; 2459*be771a7bSCy Schubert argv += optind; 2460*be771a7bSCy Schubert 2461*be771a7bSCy Schubert if(argc%3!=0) { 2462*be771a7bSCy Schubert printf("Invalid input. Specify qname, qtype, and qclass.\n"); 2463*be771a7bSCy Schubert return 1; 2464*be771a7bSCy Schubert } 2465*be771a7bSCy Schubert if(port == 53) { 2466*be771a7bSCy Schubert printf("Error: port number 53 not for DNS over QUIC. Port number 53 is not allowed to be used with DNS over QUIC. It is used for DNS datagrams.\n"); 2467*be771a7bSCy Schubert return 1; 2468*be771a7bSCy Schubert } 2469*be771a7bSCy Schubert 2470*be771a7bSCy Schubert run(svr, port, argv, argc, transport_file, session_file, quiet); 2471*be771a7bSCy Schubert 2472*be771a7bSCy Schubert checklock_stop(); 2473*be771a7bSCy Schubert #ifdef USE_WINSOCK 2474*be771a7bSCy Schubert WSACleanup(); 2475*be771a7bSCy Schubert #endif 2476*be771a7bSCy Schubert return 0; 2477*be771a7bSCy Schubert } 2478*be771a7bSCy Schubert #else /* HAVE_NGTCP2 */ 2479*be771a7bSCy Schubert int main(int ATTR_UNUSED(argc), char** ATTR_UNUSED(argv)) 2480*be771a7bSCy Schubert { 2481*be771a7bSCy Schubert printf("Compiled without ngtcp2 for QUIC, cannot run doqclient.\n"); 2482*be771a7bSCy Schubert return 1; 2483*be771a7bSCy Schubert } 2484*be771a7bSCy Schubert #endif /* HAVE_NGTCP2 */ 2485*be771a7bSCy Schubert 2486*be771a7bSCy Schubert /***--- definitions to make fptr_wlist work. ---***/ 2487*be771a7bSCy Schubert /* These are callbacks, similar to smallapp callbacks, except the debug 2488*be771a7bSCy Schubert * tool callbacks are not in it */ 2489*be771a7bSCy Schubert struct tube; 2490*be771a7bSCy Schubert struct query_info; 2491*be771a7bSCy Schubert #include "util/data/packed_rrset.h" 2492*be771a7bSCy Schubert #include "daemon/worker.h" 2493*be771a7bSCy Schubert #include "daemon/remote.h" 2494*be771a7bSCy Schubert #include "util/fptr_wlist.h" 2495*be771a7bSCy Schubert #include "libunbound/context.h" 2496*be771a7bSCy Schubert 2497*be771a7bSCy Schubert void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 2498*be771a7bSCy Schubert uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 2499*be771a7bSCy Schubert int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 2500*be771a7bSCy Schubert { 2501*be771a7bSCy Schubert log_assert(0); 2502*be771a7bSCy Schubert } 2503*be771a7bSCy Schubert 2504*be771a7bSCy Schubert int worker_handle_request(struct comm_point* ATTR_UNUSED(c), 2505*be771a7bSCy Schubert void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2506*be771a7bSCy Schubert struct comm_reply* ATTR_UNUSED(repinfo)) 2507*be771a7bSCy Schubert { 2508*be771a7bSCy Schubert log_assert(0); 2509*be771a7bSCy Schubert return 0; 2510*be771a7bSCy Schubert } 2511*be771a7bSCy Schubert 2512*be771a7bSCy Schubert int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 2513*be771a7bSCy Schubert void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2514*be771a7bSCy Schubert struct comm_reply* ATTR_UNUSED(reply_info)) 2515*be771a7bSCy Schubert { 2516*be771a7bSCy Schubert log_assert(0); 2517*be771a7bSCy Schubert return 0; 2518*be771a7bSCy Schubert } 2519*be771a7bSCy Schubert 2520*be771a7bSCy Schubert int remote_accept_callback(struct comm_point* ATTR_UNUSED(c), 2521*be771a7bSCy Schubert void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2522*be771a7bSCy Schubert struct comm_reply* ATTR_UNUSED(repinfo)) 2523*be771a7bSCy Schubert { 2524*be771a7bSCy Schubert log_assert(0); 2525*be771a7bSCy Schubert return 0; 2526*be771a7bSCy Schubert } 2527*be771a7bSCy Schubert 2528*be771a7bSCy Schubert int remote_control_callback(struct comm_point* ATTR_UNUSED(c), 2529*be771a7bSCy Schubert void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2530*be771a7bSCy Schubert struct comm_reply* ATTR_UNUSED(repinfo)) 2531*be771a7bSCy Schubert { 2532*be771a7bSCy Schubert log_assert(0); 2533*be771a7bSCy Schubert return 0; 2534*be771a7bSCy Schubert } 2535*be771a7bSCy Schubert 2536*be771a7bSCy Schubert void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) 2537*be771a7bSCy Schubert { 2538*be771a7bSCy Schubert log_assert(0); 2539*be771a7bSCy Schubert } 2540*be771a7bSCy Schubert 2541*be771a7bSCy Schubert struct outbound_entry* worker_send_query( 2542*be771a7bSCy Schubert struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), 2543*be771a7bSCy Schubert int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 2544*be771a7bSCy Schubert int ATTR_UNUSED(nocaps), int ATTR_UNUSED(check_ratelimit), 2545*be771a7bSCy Schubert struct sockaddr_storage* ATTR_UNUSED(addr), 2546*be771a7bSCy Schubert socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), 2547*be771a7bSCy Schubert size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), 2548*be771a7bSCy Schubert int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), 2549*be771a7bSCy Schubert struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) 2550*be771a7bSCy Schubert { 2551*be771a7bSCy Schubert log_assert(0); 2552*be771a7bSCy Schubert return 0; 2553*be771a7bSCy Schubert } 2554*be771a7bSCy Schubert 2555*be771a7bSCy Schubert #ifdef UB_ON_WINDOWS 2556*be771a7bSCy Schubert void 2557*be771a7bSCy Schubert worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void* 2558*be771a7bSCy Schubert ATTR_UNUSED(arg)) { 2559*be771a7bSCy Schubert log_assert(0); 2560*be771a7bSCy Schubert } 2561*be771a7bSCy Schubert 2562*be771a7bSCy Schubert void 2563*be771a7bSCy Schubert wsvc_cron_cb(void* ATTR_UNUSED(arg)) 2564*be771a7bSCy Schubert { 2565*be771a7bSCy Schubert log_assert(0); 2566*be771a7bSCy Schubert } 2567*be771a7bSCy Schubert #endif /* UB_ON_WINDOWS */ 2568*be771a7bSCy Schubert 2569*be771a7bSCy Schubert void 2570*be771a7bSCy Schubert worker_alloc_cleanup(void* ATTR_UNUSED(arg)) 2571*be771a7bSCy Schubert { 2572*be771a7bSCy Schubert log_assert(0); 2573*be771a7bSCy Schubert } 2574*be771a7bSCy Schubert 2575*be771a7bSCy Schubert struct outbound_entry* libworker_send_query( 2576*be771a7bSCy Schubert struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), 2577*be771a7bSCy Schubert int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 2578*be771a7bSCy Schubert int ATTR_UNUSED(nocaps), int ATTR_UNUSED(check_ratelimit), 2579*be771a7bSCy Schubert struct sockaddr_storage* ATTR_UNUSED(addr), 2580*be771a7bSCy Schubert socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), 2581*be771a7bSCy Schubert size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), 2582*be771a7bSCy Schubert int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), 2583*be771a7bSCy Schubert struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) 2584*be771a7bSCy Schubert { 2585*be771a7bSCy Schubert log_assert(0); 2586*be771a7bSCy Schubert return 0; 2587*be771a7bSCy Schubert } 2588*be771a7bSCy Schubert 2589*be771a7bSCy Schubert int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 2590*be771a7bSCy Schubert void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2591*be771a7bSCy Schubert struct comm_reply* ATTR_UNUSED(reply_info)) 2592*be771a7bSCy Schubert { 2593*be771a7bSCy Schubert log_assert(0); 2594*be771a7bSCy Schubert return 0; 2595*be771a7bSCy Schubert } 2596*be771a7bSCy Schubert 2597*be771a7bSCy Schubert void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 2598*be771a7bSCy Schubert uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 2599*be771a7bSCy Schubert int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 2600*be771a7bSCy Schubert { 2601*be771a7bSCy Schubert log_assert(0); 2602*be771a7bSCy Schubert } 2603*be771a7bSCy Schubert 2604*be771a7bSCy Schubert void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 2605*be771a7bSCy Schubert struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 2606*be771a7bSCy Schubert char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2607*be771a7bSCy Schubert { 2608*be771a7bSCy Schubert log_assert(0); 2609*be771a7bSCy Schubert } 2610*be771a7bSCy Schubert 2611*be771a7bSCy Schubert void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 2612*be771a7bSCy Schubert struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 2613*be771a7bSCy Schubert char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2614*be771a7bSCy Schubert { 2615*be771a7bSCy Schubert log_assert(0); 2616*be771a7bSCy Schubert } 2617*be771a7bSCy Schubert 2618*be771a7bSCy Schubert void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 2619*be771a7bSCy Schubert struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 2620*be771a7bSCy Schubert char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2621*be771a7bSCy Schubert { 2622*be771a7bSCy Schubert log_assert(0); 2623*be771a7bSCy Schubert } 2624*be771a7bSCy Schubert 2625*be771a7bSCy Schubert int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 2626*be771a7bSCy Schubert { 2627*be771a7bSCy Schubert log_assert(0); 2628*be771a7bSCy Schubert return 0; 2629*be771a7bSCy Schubert } 2630*be771a7bSCy Schubert 2631*be771a7bSCy Schubert void worker_stat_timer_cb(void* ATTR_UNUSED(arg)) 2632*be771a7bSCy Schubert { 2633*be771a7bSCy Schubert log_assert(0); 2634*be771a7bSCy Schubert } 2635*be771a7bSCy Schubert 2636*be771a7bSCy Schubert void worker_probe_timer_cb(void* ATTR_UNUSED(arg)) 2637*be771a7bSCy Schubert { 2638*be771a7bSCy Schubert log_assert(0); 2639*be771a7bSCy Schubert } 2640*be771a7bSCy Schubert 2641*be771a7bSCy Schubert void worker_start_accept(void* ATTR_UNUSED(arg)) 2642*be771a7bSCy Schubert { 2643*be771a7bSCy Schubert log_assert(0); 2644*be771a7bSCy Schubert } 2645*be771a7bSCy Schubert 2646*be771a7bSCy Schubert void worker_stop_accept(void* ATTR_UNUSED(arg)) 2647*be771a7bSCy Schubert { 2648*be771a7bSCy Schubert log_assert(0); 2649*be771a7bSCy Schubert } 2650*be771a7bSCy Schubert 2651*be771a7bSCy Schubert /** keep track of lock id in lock-verify application */ 2652*be771a7bSCy Schubert struct order_id { 2653*be771a7bSCy Schubert /** the thread id that created it */ 2654*be771a7bSCy Schubert int thr; 2655*be771a7bSCy Schubert /** the instance number of creation */ 2656*be771a7bSCy Schubert int instance; 2657*be771a7bSCy Schubert }; 2658*be771a7bSCy Schubert 2659*be771a7bSCy Schubert int order_lock_cmp(const void* e1, const void* e2) 2660*be771a7bSCy Schubert { 2661*be771a7bSCy Schubert const struct order_id* o1 = e1; 2662*be771a7bSCy Schubert const struct order_id* o2 = e2; 2663*be771a7bSCy Schubert if(o1->thr < o2->thr) return -1; 2664*be771a7bSCy Schubert if(o1->thr > o2->thr) return 1; 2665*be771a7bSCy Schubert if(o1->instance < o2->instance) return -1; 2666*be771a7bSCy Schubert if(o1->instance > o2->instance) return 1; 2667*be771a7bSCy Schubert return 0; 2668*be771a7bSCy Schubert } 2669*be771a7bSCy Schubert 2670*be771a7bSCy Schubert int 2671*be771a7bSCy Schubert codeline_cmp(const void* a, const void* b) 2672*be771a7bSCy Schubert { 2673*be771a7bSCy Schubert return strcmp(a, b); 2674*be771a7bSCy Schubert } 2675*be771a7bSCy Schubert 2676*be771a7bSCy Schubert int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 2677*be771a7bSCy Schubert { 2678*be771a7bSCy Schubert log_assert(0); 2679*be771a7bSCy Schubert return 0; 2680*be771a7bSCy Schubert } 2681*be771a7bSCy Schubert 2682*be771a7bSCy Schubert void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg)) 2683*be771a7bSCy Schubert { 2684*be771a7bSCy Schubert log_assert(0); 2685*be771a7bSCy Schubert } 2686*be771a7bSCy Schubert 2687*be771a7bSCy Schubert #ifdef USE_DNSTAP 2688*be771a7bSCy Schubert void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 2689*be771a7bSCy Schubert void* ATTR_UNUSED(arg)) 2690*be771a7bSCy Schubert { 2691*be771a7bSCy Schubert log_assert(0); 2692*be771a7bSCy Schubert } 2693*be771a7bSCy Schubert #endif 2694*be771a7bSCy Schubert 2695*be771a7bSCy Schubert #ifdef USE_DNSTAP 2696*be771a7bSCy Schubert void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 2697*be771a7bSCy Schubert void* ATTR_UNUSED(arg)) 2698*be771a7bSCy Schubert { 2699*be771a7bSCy Schubert log_assert(0); 2700*be771a7bSCy Schubert } 2701*be771a7bSCy Schubert #endif 2702*be771a7bSCy Schubert 2703*be771a7bSCy Schubert void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 2704*be771a7bSCy Schubert void* ATTR_UNUSED(arg)) 2705*be771a7bSCy Schubert { 2706*be771a7bSCy Schubert log_assert(0); 2707*be771a7bSCy Schubert } 2708*be771a7bSCy Schubert 2709*be771a7bSCy Schubert int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c), 2710*be771a7bSCy Schubert void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2711*be771a7bSCy Schubert struct comm_reply* ATTR_UNUSED(repinfo)) 2712*be771a7bSCy Schubert { 2713*be771a7bSCy Schubert log_assert(0); 2714*be771a7bSCy Schubert return 0; 2715*be771a7bSCy Schubert } 2716