Coverage Report

Created: 2026-06-30 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/quic/logger.rs
Line
Count
Source
1
/* Copyright (C) 2021 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
use super::parser::QuicType;
19
use super::quic::QuicTransaction;
20
use crate::jsonbuilder::{JsonBuilder, JsonError};
21
use digest::Digest;
22
use digest::Update;
23
use md5::Md5;
24
25
88
fn quic_tls_extension_name(e: u16) -> Option<String> {
26
88
    match e {
27
2
        0 => Some("server_name".to_string()),
28
0
        1 => Some("max_fragment_length".to_string()),
29
0
        2 => Some("client_certificate_url".to_string()),
30
0
        3 => Some("trusted_ca_keys".to_string()),
31
0
        4 => Some("truncated_hmac".to_string()),
32
6
        5 => Some("status_request".to_string()),
33
0
        6 => Some("user_mapping".to_string()),
34
0
        7 => Some("client_authz".to_string()),
35
0
        8 => Some("server_authz".to_string()),
36
0
        9 => Some("cert_type".to_string()),
37
8
        10 => Some("supported_groups".to_string()),
38
6
        11 => Some("ec_point_formats".to_string()),
39
0
        12 => Some("srp".to_string()),
40
8
        13 => Some("signature_algorithms".to_string()),
41
0
        14 => Some("use_srtp".to_string()),
42
0
        15 => Some("heartbeat".to_string()),
43
8
        16 => Some("alpn".to_string()),
44
0
        17 => Some("status_request_v2".to_string()),
45
6
        18 => Some("signed_certificate_timestamp".to_string()),
46
0
        19 => Some("client_certificate_type".to_string()),
47
0
        20 => Some("server_certificate_type".to_string()),
48
0
        21 => Some("padding".to_string()),
49
0
        22 => Some("encrypt_then_mac".to_string()),
50
6
        23 => Some("extended_master_secret".to_string()),
51
0
        24 => Some("token_binding".to_string()),
52
0
        25 => Some("cached_info".to_string()),
53
0
        26 => Some("tls_lts".to_string()),
54
0
        27 => Some("compress_certificate".to_string()),
55
0
        28 => Some("record_size_limit".to_string()),
56
0
        29 => Some("pwd_protect".to_string()),
57
0
        30 => Some("pwd_clear".to_string()),
58
0
        31 => Some("password_salt".to_string()),
59
0
        32 => Some("ticket_pinning".to_string()),
60
0
        33 => Some("tls_cert_with_extern_psk".to_string()),
61
0
        34 => Some("delegated_credentials".to_string()),
62
0
        35 => Some("session_ticket".to_string()),
63
0
        36 => Some("tlmsp".to_string()),
64
0
        37 => Some("tlmsp_proxying".to_string()),
65
0
        38 => Some("tlmsp_delegate".to_string()),
66
0
        39 => Some("supported_ekt_ciphers".to_string()),
67
2
        41 => Some("pre_shared_key".to_string()),
68
0
        42 => Some("early_data".to_string()),
69
10
        43 => Some("supported_versions".to_string()),
70
0
        44 => Some("cookie".to_string()),
71
2
        45 => Some("psk_key_exchange_modes".to_string()),
72
0
        47 => Some("certificate_authorities".to_string()),
73
0
        48 => Some("oid_filters".to_string()),
74
0
        49 => Some("post_handshake_auth".to_string()),
75
0
        50 => Some("signature_algorithms_cert".to_string()),
76
10
        51 => Some("key_share".to_string()),
77
0
        52 => Some("transparency_info".to_string()),
78
0
        53 => Some("connection_id_deprecated".to_string()),
79
0
        54 => Some("connection_id".to_string()),
80
0
        55 => Some("external_id_hash".to_string()),
81
0
        56 => Some("external_session_id".to_string()),
82
8
        57 => Some("quic_transport_parameters".to_string()),
83
0
        58 => Some("ticket_request".to_string()),
84
0
        59 => Some("dnssec_chain".to_string()),
85
0
        13172 => Some("next_protocol_negotiation".to_string()),
86
6
        65281 => Some("renegotiation_info".to_string()),
87
0
        _ => None,
88
    }
89
88
}
90
91
1.52k
fn log_template(tx: &QuicTransaction, log_ja4: bool, js: &mut JsonBuilder) -> Result<(), JsonError> {
92
1.52k
    js.open_object("quic")?;
93
1.52k
    if tx.header.ty != QuicType::Short {
94
1.52k
        js.set_string("version", String::from(tx.header.version).as_str())?;
95
96
1.52k
        if let Some(sni) = &tx.sni {
97
197
            js.set_string("sni", &String::from_utf8_lossy(sni))?;
98
1.32k
        }
99
1.52k
        if let Some(ua) = &tx.ua {
100
195
            js.set_string("ua", &String::from_utf8_lossy(ua))?;
101
1.33k
        }
102
0
    }
103
1.52k
    if !tx.cyu.is_empty() {
104
195
        js.open_array("cyu")?;
105
390
        for cyu in &tx.cyu {
106
195
            js.start_object()?;
107
195
            js.set_string("hash", &cyu.hash)?;
108
195
            js.set_string("string", &cyu.string)?;
109
195
            js.close()?;
110
        }
111
195
        js.close()?;
112
1.33k
    }
113
114
1.52k
    if let Some(ja3) = &tx.ja3 {
115
10
        if tx.client {
116
8
            js.open_object("ja3")?;
117
        } else {
118
2
            js.open_object("ja3s")?;
119
        }
120
10
        let hash = format!("{:x}", Md5::new().chain(ja3).finalize());
121
10
        js.set_string("hash", &hash)?;
122
10
        js.set_string("string", ja3)?;
123
10
        js.close()?;
124
1.51k
    }
125
126
1.52k
    if log_ja4 {
127
0
        if let Some(ref ja4) = &tx.ja4 {
128
0
            js.set_string("ja4", ja4)?;
129
0
        }
130
1.52k
    }
131
132
1.52k
    if !tx.extv.is_empty() {
133
10
        js.open_array("extensions")?;
134
98
        for e in &tx.extv {
135
88
            js.start_object()?;
136
88
            let etype = u16::from(e.etype);
137
88
            if let Some(s) = quic_tls_extension_name(etype) {
138
88
                js.set_string("name", &s)?;
139
0
            }
140
88
            js.set_uint("type", etype.into())?;
141
142
88
            if !e.values.is_empty() {
143
28
                js.open_array("values")?;
144
106
                for i in 0..e.values.len() {
145
106
                    js.append_string(&String::from_utf8_lossy(&e.values[i]))?;
146
                }
147
28
                js.close()?;
148
60
            }
149
88
            js.close()?;
150
        }
151
10
        js.close()?;
152
1.51k
    }
153
154
1.52k
    js.close()?;
155
1.52k
    Ok(())
156
1.52k
}
157
158
#[no_mangle]
159
1.52k
pub unsafe extern "C" fn rs_quic_to_json(
160
1.52k
    tx: *mut std::os::raw::c_void, log_ja4: bool, js: &mut JsonBuilder,
161
1.52k
) -> bool {
162
1.52k
    let tx = cast_pointer!(tx, QuicTransaction);
163
1.52k
    log_template(tx, log_ja4, js).is_ok()
164
1.52k
}