summaryrefslogtreecommitdiffstats
path: root/src/util-ip.c
blob: 8d482d90ed5ffb63e9bc5e9f383728f1bd43e3d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/* Copyright (C) 2007-2013 Open Information Security Foundation
 *
 * You can copy, redistribute or modify this Program under the terms of
 * the GNU General Public License version 2 as published by the Free
 * Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * version 2 along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

/**
 * \file
 *
 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
 * \author Duarte Silva <duarte.silva@serializing.me>
 *
 * IP addresses related utility functions
 */

#include "suricata-common.h"
#include "util-ip.h"
#include "util-byte.h"
#include "util-debug.h"

/** \brief determine if a string is a valid ipv4 address
 *  \retval bool is addr valid?
 */
bool IPv4AddressStringIsValid(const char *str)
{
    int alen = 0;
    char addr[4][4];
    int dots = 0;

    memset(&addr, 0, sizeof(addr));

    uint32_t len = strlen(str);
    uint32_t i = 0;
    for (i = 0; i < len; i++) {
        if (!(str[i] == '.' || isdigit(str[i]))) {
            return false;
        }
        if (str[i] == '.') {
            if (dots == 3) {
                SCLogDebug("too many dots");
                return false;
            }
            addr[dots][alen] = '\0';
            dots++;
            alen = 0;
        } else {
            if (alen >= 3) {
                SCLogDebug("too long");
                return false;
            }
            addr[dots][alen++] = str[i];
        }
    }
    if (dots != 3)
        return false;

    addr[dots][alen] = '\0';
    for (int x = 0; x < 4; x++) {
        uint8_t a;
        if (StringParseUint8(&a, 10, 0, (const char *)addr[x]) < 0) {
            SCLogDebug("invalid value for address byte: %s", addr[x]);
            return false;
        }
    }
    return true;
}

/** \brief determine if a string is a valid ipv6 address
 *  \retval bool is addr valid?
 */
bool IPv6AddressStringIsValid(const char *str)
{
    int block_size = 0;
    int sep = 0;
    bool colon_seen = false;

    uint32_t len = strlen(str);
    uint32_t i = 0;
    for (i = 0; i < len && str[i] != 0; i++) {
        if (!(str[i] == '.' || str[i] == ':' ||
            isxdigit(str[i])))
            return false;

        if (str[i] == ':') {
            block_size = 0;
            colon_seen = true;
            sep++;
        } else if (str[i] == '.') {
            block_size = false;
            sep++;
        } else {
            if (block_size == 4)
                return false;
            block_size++;
        }
    }

    if (!colon_seen)
        return false;
    if (sep > 7) {
        SCLogDebug("too many seps %d", sep);
        return false;
    }
    return true;
}

/**
 * \brief Validates an IPV4 address and returns the network endian arranged
 *        version of the IPV4 address
 *
 * \param addr Pointer to a character string containing an IPV4 address.  A
 *             valid IPV4 address is a character string containing a dotted
 *             format of "ddd.ddd.ddd.ddd"
 *
 * \retval Pointer to an in_addr instance containing the network endian format
 *         of the IPV4 address
 * \retval NULL if the IPV4 address is invalid
 */
struct in_addr *ValidateIPV4Address(const char *addr_str)
{
    struct in_addr *addr = NULL;

    if (!IPv4AddressStringIsValid(addr_str))
        return NULL;

    if ( (addr = SCMalloc(sizeof(struct in_addr))) == NULL) {
        FatalError("Fatal error encountered in ValidateIPV4Address. Exiting...");
    }

    if (inet_pton(AF_INET, addr_str, addr) <= 0) {
        SCFree(addr);
        return NULL;
    }

    return addr;
}

/**
 * \brief Validates an IPV6 address and returns the network endian arranged
 *        version of the IPV6 address
 *
 * \param addr Pointer to a character string containing an IPV6 address
 *
 * \retval Pointer to a in6_addr instance containing the network endian format
 *         of the IPV6 address
 * \retval NULL if the IPV6 address is invalid
 */
struct in6_addr *ValidateIPV6Address(const char *addr_str)
{
    struct in6_addr *addr = NULL;

    if (!IPv6AddressStringIsValid(addr_str))
        return NULL;

    if ( (addr = SCMalloc(sizeof(struct in6_addr))) == NULL) {
        FatalError("Fatal error encountered in ValidateIPV6Address. Exiting...");
    }

    if (inet_pton(AF_INET6, addr_str, addr) <= 0) {
        SCFree(addr);
        return NULL;
    }

    return addr;
}

/**
 * \brief Culls the non-netmask portion of the IP address. For example an IP
 *        address 192.168.240.1 would be chopped to 192.168.224.0 against a
 *        netmask value of 19.
 *
 * \param stream  Pointer the IP address that has to be masked
 * \param netmask The netmask value (cidr) to which the IP address has to be culled
 * \param key_bitlen  The bitlen of the stream
 */
void MaskIPNetblock(uint8_t *stream, int netmask, int key_bitlen)
{
    uint32_t mask = 0;
    int i = 0;
    int bytes = key_bitlen / 8;

    for (i = 0; i < bytes; i++) {
        mask = UINT_MAX;
        if ( ((i + 1) * 8) > netmask) {
            if ( ((i + 1) * 8 - netmask) < 8)
                mask = UINT_MAX << ((i + 1) * 8 - netmask);
            else
                mask = 0;
        }
        stream[i] &= mask;
    }

    return;
}