• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/rust/src/utils/ipaddr.rs
1
/* Copyright (C) 2026 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
// Author: Jeff Lucovsky <jlucovsky@oisf.net>
19

20
use std::ffi::{c_char, c_uchar};
21
use std::net::Ipv6Addr;
22

23
/// Writes the compressed IPv6 string into `out_buf`, which has length `out_len`.
24
/// Returns the number of bytes written (excluding the null terminator),
25
/// or 0 on error (invalid addr pointer, buffer too small, etc.)
26
#[no_mangle]
UNCOV
27
pub unsafe extern "C" fn SCIPv6Compress(
×
UNCOV
28
    addr: *const c_uchar, // pointer to 16-byte IPv6
×
UNCOV
29
    out_buf: *mut c_char, // out buffer allocated by caller
×
UNCOV
30
    out_len: usize,       // size of out buffer
×
UNCOV
31
) -> usize {
×
UNCOV
32
    if addr.is_null() || out_buf.is_null() || out_len == 0 {
×
UNCOV
33
        return 0;
×
UNCOV
34
    }
×
UNCOV
35

×
UNCOV
36
    // get 16-byte IPv6 address
×
UNCOV
37
    let fixed = std::ptr::read_unaligned(addr as *const [u8; 16]);
×
UNCOV
38
    let ipv6 = Ipv6Addr::from(fixed);
×
UNCOV
39

×
UNCOV
40
    let ipv6_str = ipv6.to_string();
×
UNCOV
41
    // Sufficient room?
×
UNCOV
42
    if ipv6_str.len() + 1 > out_len {
×
UNCOV
43
        return 0;
×
UNCOV
44
    }
×
UNCOV
45
    // Copy string + NULL termination
×
UNCOV
46
    let len = ipv6_str.len();
×
UNCOV
47
    crate::ffi::strings::copy_to_c_char(ipv6_str, out_buf, out_len);
×
UNCOV
48
    len
×
UNCOV
49
}
×
50

51
#[cfg(test)]
52
mod tests {
53

54
    use super::*;
55
    use std::os::raw::{c_char, c_uchar};
56

57
    struct CompressedResult {
58
        string: String,
59
    }
60

61
    fn call_compresser(bytes: &[u8; 16]) -> Option<CompressedResult> {
62
        let mut out = vec![0u8; 64];
63
        let len = unsafe {
64
            SCIPv6Compress(
65
                bytes.as_ptr() as *const c_uchar,
66
                out.as_mut_ptr() as *mut c_char,
67
                out.len(),
68
            )
69
        };
70

71
        if len == 0 {
72
            return None;
73
        }
74

75
        let s = String::from_utf8(out[..len].to_vec()).unwrap();
76
        Some(CompressedResult { string: s })
77
    }
78

79
    #[test]
80
    fn test_ipv6_compress_success_zero_addr() {
81
        let addr = [0u8; 16];
82
        let out = call_compresser(&addr).unwrap();
83
        assert_eq!(out.string, "::");
84
        assert_eq!(out.string.len(), 2);
85
    }
86

87
    #[test]
88
    fn test_ipv6_compress_success_loopback() {
89
        let mut addr = [0u8; 16];
90
        addr[15] = 1; // ::1
91
        let out = call_compresser(&addr).unwrap();
92
        assert_eq!(out.string, "::1");
93
        assert_eq!(out.string.len(), 3);
94
    }
95

96
    #[test]
97
    fn test_ipv6_compress_success_normal_addr() {
98
        let addr = [
99
            0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100
            0x00, 0x01,
101
        ];
102
        let out = call_compresser(&addr).unwrap();
103
        assert_eq!(out.string, "2001:db8::1");
104
        assert_eq!(out.string.len(), 11);
105
    }
106

107
    #[test]
108
    fn test_ipv6_compress_success_ipv4_mapped() {
109
        let addr: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 0, 1];
110
        let out = call_compresser(&addr).unwrap();
111
        assert_eq!(out.string, "::ffff:192.168.0.1");
112
        assert_eq!(out.string.len(), 18);
113
    }
114

115
    #[test]
116
    fn test_ipv6_compress_success_no_zero_compression() {
117
        // 2001:db8:1:2:3:4:5:6 (fully expanded, no zero-run)
118
        let addr: [u8; 16] = [
119
            0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05,
120
            0x00, 0x06,
121
        ];
122
        let out = call_compresser(&addr).unwrap();
123
        assert_eq!(out.string, "2001:db8:1:2:3:4:5:6");
124
        assert_eq!(out.string.len(), 20);
125
    }
126

127
    #[test]
128
    fn test_ipv6_compress_fail_null_addr() {
129
        let mut out = vec![0u8; 64];
130
        let len =
131
            unsafe { SCIPv6Compress(std::ptr::null(), out.as_mut_ptr() as *mut c_char, out.len()) };
132
        assert_eq!(len, 0);
133
    }
134

135
    #[test]
136
    fn test_ipv6_compress_fail_null_out_buf() {
137
        let addr = [0u8; 16];
138
        let len =
139
            unsafe { SCIPv6Compress(addr.as_ptr() as *const c_uchar, std::ptr::null_mut(), 64) };
140
        assert_eq!(len, 0);
141
    }
142

143
    #[test]
144
    fn test_ipv6_compress_fail_out_buf_too_small() {
145
        let addr = [0u8; 16];
146
        // "::" is 2 bytes + NUL = 3, so give only length 2
147
        let mut out = vec![0u8; 2];
148
        let len = unsafe {
149
            SCIPv6Compress(
150
                addr.as_ptr() as *const c_uchar,
151
                out.as_mut_ptr() as *mut c_char,
152
                out.len(),
153
            )
154
        };
155
        assert_eq!(len, 0);
156
    }
157

158
    #[test]
159
    fn test_ipv6_compress_fail_exactly_one_byte_short() {
160
        let addr = [0u8; 16];
161
        let compressed = "::";
162
        let needed = compressed.len() + 1; // for NUL
163
        let mut out = vec![0u8; needed - 1]; // one byte too small
164
        let len = unsafe {
165
            SCIPv6Compress(
166
                addr.as_ptr() as *const c_uchar,
167
                out.as_mut_ptr() as *mut c_char,
168
                out.len(),
169
            )
170
        };
171
        assert_eq!(len, 0);
172
    }
173

174
    #[test]
175
    fn test_ipv6_compress_writes_nul_terminator() {
176
        let addr = [0u8; 16];
177
        let mut out = vec![0u8; 64];
178
        let len = unsafe {
179
            SCIPv6Compress(
180
                addr.as_ptr() as *const c_uchar,
181
                out.as_mut_ptr() as *mut c_char,
182
                out.len(),
183
            )
184
        };
185
        assert!(len > 0);
186
        assert_eq!(out[len], 0);
187
    }
188
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc