Coverage Report

Created: 2026-06-07 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-ip.c
Line
Count
Source
1
/* Copyright (C) 2007-2013 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
/**
19
 * \file
20
 *
21
 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22
 * \author Duarte Silva <duarte.silva@serializing.me>
23
 *
24
 * IP addresses related utility functions
25
 */
26
27
#include "suricata-common.h"
28
#include "util-ip.h"
29
#include "util-byte.h"
30
#include "util-debug.h"
31
32
/** \brief determine if a string is a valid ipv4 address
33
 *  \retval bool is addr valid?
34
 */
35
bool IPv4AddressStringIsValid(const char *str)
36
0
{
37
0
    int alen = 0;
38
0
    char addr[4][4];
39
0
    int dots = 0;
40
41
0
    memset(&addr, 0, sizeof(addr));
42
43
0
    uint32_t len = strlen(str);
44
0
    uint32_t i = 0;
45
0
    for (i = 0; i < len; i++) {
46
0
        if (!(str[i] == '.' || isdigit(str[i]))) {
47
0
            return false;
48
0
        }
49
0
        if (str[i] == '.') {
50
0
            if (dots == 3) {
51
0
                SCLogDebug("too many dots");
52
0
                return false;
53
0
            }
54
0
            addr[dots][alen] = '\0';
55
0
            dots++;
56
0
            alen = 0;
57
0
        } else {
58
0
            if (alen >= 3) {
59
0
                SCLogDebug("too long");
60
0
                return false;
61
0
            }
62
0
            addr[dots][alen++] = str[i];
63
0
        }
64
0
    }
65
0
    if (dots != 3)
66
0
        return false;
67
68
0
    addr[dots][alen] = '\0';
69
0
    for (int x = 0; x < 4; x++) {
70
0
        uint8_t a;
71
0
        if (StringParseUint8(&a, 10, 0, (const char *)addr[x]) < 0) {
72
0
            SCLogDebug("invalid value for address byte: %s", addr[x]);
73
0
            return false;
74
0
        }
75
0
    }
76
0
    return true;
77
0
}
78
79
/** \brief determine if a string is a valid ipv6 address
80
 *  \retval bool is addr valid?
81
 */
82
bool IPv6AddressStringIsValid(const char *str)
83
0
{
84
0
    int block_size = 0;
85
0
    int sep = 0;
86
0
    bool colon_seen = false;
87
88
0
    uint32_t len = strlen(str);
89
0
    uint32_t i = 0;
90
0
    for (i = 0; i < len && str[i] != 0; i++) {
91
0
        if (!(str[i] == '.' || str[i] == ':' ||
92
0
            isxdigit(str[i])))
93
0
            return false;
94
95
0
        if (str[i] == ':') {
96
0
            block_size = 0;
97
0
            colon_seen = true;
98
0
            sep++;
99
0
        } else if (str[i] == '.') {
100
0
            block_size = false;
101
0
            sep++;
102
0
        } else {
103
0
            if (block_size == 4)
104
0
                return false;
105
0
            block_size++;
106
0
        }
107
0
    }
108
109
0
    if (!colon_seen)
110
0
        return false;
111
0
    if (sep > 7) {
112
0
        SCLogDebug("too many seps %d", sep);
113
0
        return false;
114
0
    }
115
0
    return true;
116
0
}
117
118
/**
119
 * \brief Validates an IPV4 address and returns the network endian arranged
120
 *        version of the IPV4 address
121
 *
122
 * \param addr Pointer to a character string containing an IPV4 address.  A
123
 *             valid IPV4 address is a character string containing a dotted
124
 *             format of "ddd.ddd.ddd.ddd"
125
 *
126
 * \retval Pointer to an in_addr instance containing the network endian format
127
 *         of the IPV4 address
128
 * \retval NULL if the IPV4 address is invalid
129
 */
130
struct in_addr *ValidateIPV4Address(const char *addr_str)
131
0
{
132
0
    struct in_addr *addr = NULL;
133
134
0
    if (!IPv4AddressStringIsValid(addr_str))
135
0
        return NULL;
136
137
0
    if ( (addr = SCMalloc(sizeof(struct in_addr))) == NULL) {
138
0
        FatalError("Fatal error encountered in ValidateIPV4Address. Exiting...");
139
0
    }
140
141
0
    if (inet_pton(AF_INET, addr_str, addr) <= 0) {
142
0
        SCFree(addr);
143
0
        return NULL;
144
0
    }
145
146
0
    return addr;
147
0
}
148
149
/**
150
 * \brief Validates an IPV6 address and returns the network endian arranged
151
 *        version of the IPV6 address
152
 *
153
 * \param addr Pointer to a character string containing an IPV6 address
154
 *
155
 * \retval Pointer to a in6_addr instance containing the network endian format
156
 *         of the IPV6 address
157
 * \retval NULL if the IPV6 address is invalid
158
 */
159
struct in6_addr *ValidateIPV6Address(const char *addr_str)
160
0
{
161
0
    struct in6_addr *addr = NULL;
162
163
0
    if (!IPv6AddressStringIsValid(addr_str))
164
0
        return NULL;
165
166
0
    if ( (addr = SCMalloc(sizeof(struct in6_addr))) == NULL) {
167
0
        FatalError("Fatal error encountered in ValidateIPV6Address. Exiting...");
168
0
    }
169
170
0
    if (inet_pton(AF_INET6, addr_str, addr) <= 0) {
171
0
        SCFree(addr);
172
0
        return NULL;
173
0
    }
174
175
0
    return addr;
176
0
}
177
178
/**
179
 * \brief Culls the non-netmask portion of the IP address. For example an IP
180
 *        address 192.168.240.1 would be chopped to 192.168.224.0 against a
181
 *        netmask value of 19.
182
 *
183
 * \param stream  Pointer the IP address that has to be masked
184
 * \param netmask The netmask value (cidr) to which the IP address has to be culled
185
 * \param key_bitlen  The bitlen of the stream
186
 */
187
void MaskIPNetblock(uint8_t *stream, int netmask, int key_bitlen)
188
21.8k
{
189
21.8k
    uint32_t mask = 0;
190
21.8k
    int i = 0;
191
21.8k
    int bytes = key_bitlen / 8;
192
193
226k
    for (i = 0; i < bytes; i++) {
194
204k
        mask = UINT_MAX;
195
204k
        if ( ((i + 1) * 8) > netmask) {
196
150k
            if ( ((i + 1) * 8 - netmask) < 8)
197
3.83k
                mask = UINT_MAX << ((i + 1) * 8 - netmask);
198
146k
            else
199
146k
                mask = 0;
200
150k
        }
201
204k
        stream[i] &= mask;
202
204k
    }
203
204
21.8k
    return;
205
21.8k
}