1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <stdlib.h>
3#include <stdio.h>
4#include <errno.h>
5#include <inttypes.h>
6#include <string.h>
7#include <sys/queue.h>
8#ifdef WIN32
9#include <Ws2tcpip.h>
10#else
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <netinet/in.h>
14#include <arpa/inet.h>
15#endif
16
17#include <openssl/ssl.h>
18#include <openssl/x509.h>
19
20#include "lsquic.h"
21#include "lsquic_types.h"
22#include "lsquic_int_types.h"
23#include "lsquic_packet_common.h"
24#include "lsquic_packet_in.h"
25#include "lsquic_packet_out.h"
26#include "lsquic_util.h"
27#include "lsquic_qlog.h"
28
29#define LSQUIC_LOGGER_MODULE LSQLM_QLOG
30#include "lsquic_logger.h"
31
32#define LSQUIC_LOG_CONN_ID cid
33#define LCID(...) LSQ_LOG2(LSQ_LOG_DEBUG, __VA_ARGS__)
34
35#define MAX_IP_LEN INET6_ADDRSTRLEN
36#define QLOG_PACKET_RAW_SZ 64
37
38
39void
40lsquic_qlog_create_connection (const lsquic_cid_t* cid,
41                                const struct sockaddr *local_sa,
42                                const struct sockaddr *peer_sa)
43{
44    uint32_t ip_version, srcport, dstport;
45    struct sockaddr_in *local4, *peer4;
46    struct sockaddr_in6 *local6, *peer6;
47    char srcip[MAX_IP_LEN], dstip[MAX_IP_LEN];
48
49    if (!local_sa || !peer_sa)
50        return;
51
52    if (local_sa->sa_family == AF_INET)
53    {
54        ip_version = 4;
55        local4 = (struct sockaddr_in *)local_sa;
56        peer4 = (struct sockaddr_in *)peer_sa;
57        srcport = ntohs(local4->sin_port);
58        dstport = ntohs(peer4->sin_port);
59        inet_ntop(local4->sin_family, &local4->sin_addr, srcip, MAX_IP_LEN);
60        inet_ntop(peer4->sin_family, &peer4->sin_addr, dstip, MAX_IP_LEN);
61    }
62    else if (local_sa->sa_family == AF_INET6)
63    {
64        ip_version = 6;
65        local6 = (struct sockaddr_in6 *)local_sa;
66        peer6 = (struct sockaddr_in6 *)peer_sa;
67        srcport = ntohs(local6->sin6_port);
68        dstport = ntohs(peer6->sin6_port);
69        inet_ntop(local6->sin6_family, &local6->sin6_addr, srcip, MAX_IP_LEN);
70        inet_ntop(peer6->sin6_family, &peer6->sin6_addr, dstip, MAX_IP_LEN);
71    }
72    else
73        return;
74
75    LCID("[%" PRIu64 ",\"CONNECTIVITY\",\"NEW_CONNECTION\",\"LINE\","
76            "{"
77                "\"ip_version\":\"%u\","
78                "\"srcip\":\"%s\","
79                "\"dstip\":\"%s\","
80                "\"srcport\":\"%u\","
81                "\"dstport\":\"%u\""
82            "}]",
83            lsquic_time_now(), ip_version, srcip, dstip, srcport, dstport);
84}
85
86
87#define QLOG_FRAME_DICT_PREFIX_COMMA ",{\"frame_type\":\""
88#define QLOG_FRAME_DICT_PREFIX "{\"frame_type\":\""
89#define QLOG_FRAME_DICT_SUFFIX "\"}"
90#define QLOG_FRAME_LIST_PREFIX ",\"frames\":["
91#define QLOG_FRAME_LIST_SUFFIX "]"
92#define QLOG_FRAME_LIST_MAX \
93    sizeof(QLOG_FRAME_LIST_PREFIX) + \
94    sizeof(QLOG_FRAME_LIST_SUFFIX) + \
95    lsquic_frame_types_str_sz + \
96    (N_QUIC_FRAMES * \
97    (sizeof(QLOG_FRAME_DICT_PREFIX_COMMA) + \
98     sizeof(QLOG_FRAME_DICT_SUFFIX)))
99
100void
101lsquic_qlog_packet_rx (const lsquic_cid_t* cid,
102                        const struct lsquic_packet_in *packet_in,
103                        const unsigned char *packet_in_data,
104                        size_t packet_in_size)
105{
106    int i, first, ret;
107    unsigned cur;
108    size_t raw_bytes_written;
109    char data[QLOG_PACKET_RAW_SZ];
110    char frame_list[QLOG_FRAME_LIST_MAX + 1];
111
112    if (!packet_in || !packet_in_data)
113        return;
114
115    if (packet_in->pi_frame_types)
116    {
117        memcpy(frame_list, QLOG_FRAME_LIST_PREFIX,
118                                            sizeof(QLOG_FRAME_LIST_PREFIX));
119        cur = sizeof(QLOG_FRAME_LIST_PREFIX) - 1;
120        for (i = 0, first = 0; i < N_QUIC_FRAMES; i++)
121            if (packet_in->pi_frame_types & (1 << i))
122            {
123                ret = snprintf(frame_list + cur,
124                                QLOG_FRAME_LIST_MAX - cur,
125                                /* prefix + FRAME_NAME + suffix */
126                                "%s%s%s",
127                                /* skip comma in prefix if first frame */
128                                (first++ ?
129                                    QLOG_FRAME_DICT_PREFIX_COMMA :
130                                    QLOG_FRAME_DICT_PREFIX),
131                                QUIC_FRAME_NAME(i),
132                                QLOG_FRAME_DICT_SUFFIX);
133                if (ret < 0 || (unsigned)ret > QLOG_FRAME_LIST_MAX - cur)
134                    break;
135                cur += ret;
136            }
137        if (cur + sizeof(QLOG_FRAME_LIST_SUFFIX) <= QLOG_FRAME_LIST_MAX)
138            memcpy(frame_list + cur, QLOG_FRAME_LIST_SUFFIX,
139                                        sizeof(QLOG_FRAME_LIST_SUFFIX));
140    }
141    else
142        frame_list[0] = '\0';
143
144    raw_bytes_written = lsquic_hex_encode(packet_in_data, packet_in_size,
145                                                    data, QLOG_PACKET_RAW_SZ);
146
147    LCID("[%" PRIu64 ",\"TRANSPORT\",\"PACKET_RX\",\"LINE\","
148            "{"
149                "\"raw\":\"%s%s\","
150                "\"header\":{"
151                    "\"type\":\"%s\","
152                    "\"payload_length\":\"%d\","
153                    "\"packet_number\":\"%" PRIu64 "\""
154                "}%s"
155            "}]",
156            packet_in->pi_received,
157            data, (raw_bytes_written < packet_in_size) ? "..." : "",
158            lsquic_hety2str[packet_in->pi_header_type],
159            packet_in->pi_data_sz,
160            packet_in->pi_packno,
161            frame_list);
162}
163
164
165void
166lsquic_qlog_hsk_completed (const lsquic_cid_t* cid)
167{
168    LCID("[%" PRIu64 ",\"CONNECTIVITY\",\"HANDSHAKE\",\"PACKET_RX\","
169            "{\"status\":\"complete\"}]", lsquic_time_now());
170}
171
172
173void
174lsquic_qlog_sess_resume (const lsquic_cid_t* cid)
175{
176    LCID("[%" PRIu64 ",\"RECOVERY\",\"RTT_UPDATE\",\"PACKET_RX\","
177            "{\"zero_rtt\":\"successful\"}]", lsquic_time_now());
178}
179
180
181void
182lsquic_qlog_check_certs (const lsquic_cid_t* cid, const lsquic_str_t **certs,
183                                                                size_t count)
184{
185    size_t i;
186    size_t buf_sz = 0;
187    char *buf = NULL;
188    char *new_buf;
189
190    for (i = 0; i < count; i++)
191    {
192        if (buf_sz < (lsquic_str_len(certs[i]) * 2) + 1)
193        {
194            buf_sz = (lsquic_str_len(certs[i]) * 2) + 1;
195            new_buf = realloc(buf, buf_sz);
196            if (!new_buf)
197                break;
198            buf = new_buf;
199        }
200        lsquic_hex_encode(lsquic_str_cstr(certs[i]), lsquic_str_len(certs[i]),
201                                                                buf, buf_sz);
202        LCID("[%" PRIu64 ",\"SECURITY\",\"CHECK_CERT\",\"CERTLOG\","
203                "{\"certificate\":\"%s\"}]", lsquic_time_now(), buf);
204    }
205    if (buf)
206        free(buf);
207}
208
209
210void
211lsquic_qlog_cert_chain (const lsquic_cid_t* cid, struct stack_st_X509 *chain)
212{
213    X509 *cert;
214    unsigned i;
215    unsigned char *buf;
216    char *hexbuf, *newbuf;
217    size_t hexbuf_sz;
218    int len;
219    lsquic_time_t now;
220
221    now = lsquic_time_now();
222    hexbuf = NULL;
223    hexbuf_sz = 0;
224    for (i = 0; i < sk_X509_num(chain); ++i)
225    {
226        cert = sk_X509_value(chain, i);
227        buf = NULL;
228        len = i2d_X509(cert, &buf);
229        if (len <= 0)
230            break;
231        if ((size_t) len * 2 + 1 > hexbuf_sz)
232        {
233            hexbuf_sz = len * 2 + 1;
234            newbuf = realloc(hexbuf, hexbuf_sz);
235            if (!newbuf)
236                break;
237            hexbuf = newbuf;
238        }
239        lsquic_hexstr(buf, (size_t) len, hexbuf, hexbuf_sz);
240        LCID("[%" PRIu64 ",\"SECURITY\",\"CHECK_CERT\",\"CERTLOG\","
241                "{\"certificate\":\"%s\"}]", now, hexbuf);
242        OPENSSL_free(buf);
243    }
244
245    if (hexbuf)
246        free(hexbuf);
247}
248
249
250void
251lsquic_qlog_version_negotiation (const lsquic_cid_t* cid,
252                                        const char *action, const char *ver)
253{
254    char *trig;
255
256    if (!action || !ver)
257        return;
258    if (strcmp(action, "proposed") == 0)
259        trig = "LINE";
260    else if (strcmp(action, "supports") == 0 || strcmp(action, "agreed") == 0)
261        trig = "PACKET_RX";
262    else
263        return;
264    LCID("[%" PRIu64 ",\"CONNECTIVITY\",\"VERNEG\",\"%s\","
265            "{\"%s_version\":\"%s\"}]", lsquic_time_now(), trig, action, ver);
266}
267