lsquic_qlog.c revision b55a5117
1/* Copyright (c) 2017 - 2020 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#define QLOG_FRAME_DICT_PREFIX_COMMA ",{\"frame_type\":\""
87#define QLOG_FRAME_DICT_PREFIX "{\"frame_type\":\""
88#define QLOG_FRAME_DICT_SUFFIX "\"}"
89#define QLOG_FRAME_LIST_PREFIX ",\"frames\":["
90#define QLOG_FRAME_LIST_SUFFIX "]"
91#define QLOG_FRAME_LIST_MAX \
92    sizeof(QLOG_FRAME_LIST_PREFIX) + \
93    sizeof(QLOG_FRAME_LIST_SUFFIX) + \
94    lsquic_frame_types_str_sz + \
95    (N_QUIC_FRAMES * \
96    (sizeof(QLOG_FRAME_DICT_PREFIX_COMMA) + \
97     sizeof(QLOG_FRAME_DICT_SUFFIX)))
98
99void
100lsquic_qlog_packet_rx (const lsquic_cid_t* cid,
101                        const struct lsquic_packet_in *packet_in,
102                        const unsigned char *packet_in_data,
103                        size_t packet_in_size)
104{
105    int i, first, ret;
106    unsigned cur;
107    size_t raw_bytes_written;
108    char data[QLOG_PACKET_RAW_SZ];
109    char frame_list[QLOG_FRAME_LIST_MAX + 1];
110
111    if (!packet_in || !packet_in_data)
112        return;
113
114    if (packet_in->pi_frame_types)
115    {
116        memcpy(frame_list, QLOG_FRAME_LIST_PREFIX,
117                                            sizeof(QLOG_FRAME_LIST_PREFIX));
118        cur = sizeof(QLOG_FRAME_LIST_PREFIX) - 1;
119        for (i = 0, first = 0; i < N_QUIC_FRAMES; i++)
120            if (packet_in->pi_frame_types & (1 << i))
121            {
122                ret = snprintf(frame_list + cur,
123                                QLOG_FRAME_LIST_MAX - cur,
124                                /* prefix + FRAME_NAME + suffix */
125                                "%s%s%s",
126                                /* skip comma in prefix if first frame */
127                                (first++ ?
128                                    QLOG_FRAME_DICT_PREFIX_COMMA :
129                                    QLOG_FRAME_DICT_PREFIX),
130                                QUIC_FRAME_NAME(i),
131                                QLOG_FRAME_DICT_SUFFIX);
132                if (ret < 0 || (unsigned)ret > QLOG_FRAME_LIST_MAX - cur)
133                    break;
134                cur += ret;
135            }
136        if (cur + sizeof(QLOG_FRAME_LIST_SUFFIX) <= QLOG_FRAME_LIST_MAX)
137            memcpy(frame_list + cur, QLOG_FRAME_LIST_SUFFIX,
138                                        sizeof(QLOG_FRAME_LIST_SUFFIX));
139    }
140    else
141        frame_list[0] = '\0';
142
143    raw_bytes_written = lsquic_hex_encode(packet_in_data, packet_in_size,
144                                                    data, QLOG_PACKET_RAW_SZ);
145
146    LCID("[%" PRIu64 ",\"TRANSPORT\",\"PACKET_RX\",\"LINE\","
147            "{"
148                "\"raw\":\"%s%s\","
149                "\"header\":{"
150                    "\"type\":\"%s\","
151                    "\"payload_length\":\"%d\","
152                    "\"packet_number\":\"%" PRIu64 "\""
153                "}%s"
154            "}]",
155            packet_in->pi_received,
156            data, (raw_bytes_written < packet_in_size) ? "..." : "",
157            lsquic_hety2str[packet_in->pi_header_type],
158            packet_in->pi_data_sz,
159            packet_in->pi_packno,
160            frame_list);
161}
162
163
164void
165lsquic_qlog_hsk_completed (const lsquic_cid_t* cid)
166{
167    LCID("[%" PRIu64 ",\"CONNECTIVITY\",\"HANDSHAKE\",\"PACKET_RX\","
168            "{\"status\":\"complete\"}]", lsquic_time_now());
169}
170
171
172void
173lsquic_qlog_zero_rtt (const lsquic_cid_t* cid)
174{
175    LCID("[%" PRIu64 ",\"RECOVERY\",\"RTT_UPDATE\",\"PACKET_RX\","
176            "{\"zero_rtt\":\"successful\"}]", lsquic_time_now());
177}
178
179
180void
181lsquic_qlog_check_certs (const lsquic_cid_t* cid, const lsquic_str_t **certs,
182                                                                size_t count)
183{
184    size_t i;
185    size_t buf_sz = 0;
186    char *buf = NULL;
187    char *new_buf;
188
189    for (i = 0; i < count; i++)
190    {
191        if (buf_sz < (lsquic_str_len(certs[i]) * 2) + 1)
192        {
193            buf_sz = (lsquic_str_len(certs[i]) * 2) + 1;
194            new_buf = realloc(buf, buf_sz);
195            if (!new_buf)
196                break;
197            buf = new_buf;
198        }
199        lsquic_hex_encode(lsquic_str_cstr(certs[i]), lsquic_str_len(certs[i]),
200                                                                buf, buf_sz);
201        LCID("[%" PRIu64 ",\"SECURITY\",\"CHECK_CERT\",\"CERTLOG\","
202                "{\"certificate\":\"%s\"}]", lsquic_time_now(), buf);
203    }
204    if (buf)
205        free(buf);
206}
207
208
209void
210lsquic_qlog_cert_chain (const lsquic_cid_t* cid, struct stack_st_X509 *chain)
211{
212    X509 *cert;
213    unsigned i;
214    unsigned char *buf;
215    char *hexbuf, *newbuf;
216    size_t hexbuf_sz;
217    int len;
218    lsquic_time_t now;
219
220    now = lsquic_time_now();
221    hexbuf = NULL;
222    hexbuf_sz = 0;
223    for (i = 0; i < sk_X509_num(chain); ++i)
224    {
225        cert = sk_X509_value(chain, i);
226        buf = NULL;
227        len = i2d_X509(cert, &buf);
228        if (len <= 0)
229            break;
230        if ((size_t) len * 2 + 1 > hexbuf_sz)
231        {
232            hexbuf_sz = len * 2 + 1;
233            newbuf = realloc(hexbuf, hexbuf_sz);
234            if (!newbuf)
235                break;
236            hexbuf = newbuf;
237        }
238        lsquic_hexstr(buf, (size_t) len, hexbuf, hexbuf_sz);
239        LCID("[%" PRIu64 ",\"SECURITY\",\"CHECK_CERT\",\"CERTLOG\","
240                "{\"certificate\":\"%s\"}]", now, hexbuf);
241        OPENSSL_free(buf);
242    }
243
244    if (hexbuf)
245        free(hexbuf);
246}
247
248
249void
250lsquic_qlog_version_negotiation (const lsquic_cid_t* cid,
251                                        const char *action, const char *ver)
252{
253    char *trig;
254
255    if (!action || !ver)
256        return;
257    if (strcmp(action, "proposed") == 0)
258        trig = "LINE";
259    else if (strcmp(action, "supports") == 0 || strcmp(action, "agreed") == 0)
260        trig = "PACKET_RX";
261    else
262        return;
263    LCID("[%" PRIu64 ",\"CONNECTIVITY\",\"VERNEG\",\"%s\","
264            "{\"%s_version\":\"%s\"}]", lsquic_time_now(), trig, action, ver);
265}
266