epan/dissectors/pidl/ C99 drsuapi
[wireshark-sm.git] / epan / ftypes / ftype-ipv6.c
blob93f8734b93e5abeaae84c25d5b60faa8c4ce4c83
1 /*
2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
11 #include <ftypes-int.h>
12 #include <epan/addr_resolv.h>
13 #include <epan/to_str.h>
14 #include <wsutil/inet_cidr.h>
15 #include <wsutil/strtoi.h>
16 #include <wsutil/array.h>
18 static bool
19 ipv6_from_literal(fvalue_t *fv, const char *s, bool allow_partial_value _U_, char **err_msg)
21 const char *slash;
22 const char *addr_str;
23 char *addr_str_to_free = NULL;
24 uint32_t nmask_bits;
25 const char *endptr;
27 /* Look for prefix: Is there a single slash in the string? */
28 slash = strchr(s, '/');
29 if (slash) {
30 /* Make a copy of the string up to but not including the
31 * slash; that's the address portion. */
32 addr_str_to_free = wmem_strndup(NULL, s, slash-s);
33 addr_str = addr_str_to_free;
35 else
36 addr_str = s;
38 if (!get_host_ipaddr6(addr_str, &(fv->value.ipv6.addr))) {
39 if (err_msg != NULL)
40 *err_msg = ws_strdup_printf("\"%s\" is not a valid hostname or IPv6 address.", s);
41 if (addr_str_to_free)
42 wmem_free(NULL, addr_str_to_free);
43 return false;
46 if (addr_str_to_free)
47 wmem_free(NULL, addr_str_to_free);
49 /* If prefix */
50 if (slash) {
51 if(!ws_strtou32(slash+1, &endptr, &nmask_bits) || *endptr != '\0') {
52 if (err_msg != NULL) {
53 *err_msg = ws_strdup_printf("%s in not a valid mask", slash+1);
55 return false;
57 if (nmask_bits > 128) {
58 if (err_msg != NULL) {
59 *err_msg = ws_strdup_printf("Prefix in a IPv6 address should be <= 128, not %u",
60 nmask_bits);
62 return false;
64 fv->value.ipv6.prefix = nmask_bits;
65 } else {
66 /* Not CIDR; mask covers entire address. */
67 fv->value.ipv6.prefix = 128;
70 return true;
73 static char *
74 ipv6_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_)
76 char buf[WS_INET6_ADDRSTRLEN];
77 char *repr;
79 ip6_to_str_buf(&fv->value.ipv6.addr, buf, sizeof(buf));
81 if (fv->value.ipv6.prefix != 0 && fv->value.ipv6.prefix != 128)
82 repr = wmem_strdup_printf(scope, "%s/%"PRIu32, buf, fv->value.ipv6.prefix);
83 else
84 repr = wmem_strdup(scope, buf);
86 return repr;
89 static void
90 ipv6_set(fvalue_t *fv, const ipv6_addr_and_prefix *value)
92 fv->value.ipv6 = *value;
95 static const ipv6_addr_and_prefix *
96 ipv6_get(fvalue_t *fv)
98 return &fv->value.ipv6;
101 static const uint8_t bitmasks[9] =
102 { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
104 static enum ft_result
105 cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b, int *cmp)
107 const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
108 const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
109 uint32_t prefix;
110 int pos = 0;
112 prefix = MIN(a->prefix, b->prefix); /* MIN() like IPv4 */
113 prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */
115 while (prefix >= 8) {
116 int byte_a = (int) (a->addr.bytes[pos]);
117 int byte_b = (int) (b->addr.bytes[pos]);
119 if (byte_a != byte_b) {
120 *cmp = byte_a - byte_b;
121 return FT_OK;
124 prefix -= 8;
125 pos++;
128 if (prefix != 0) {
129 int byte_a = (int) (a->addr.bytes[pos] & (bitmasks[prefix]));
130 int byte_b = (int) (b->addr.bytes[pos] & (bitmasks[prefix]));
132 if (byte_a != byte_b) {
133 *cmp = byte_a - byte_b;
134 return FT_OK;
137 *cmp = 0;
138 return FT_OK;
141 static enum ft_result
142 bitwise_and(fvalue_t *dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_)
144 const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
145 const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
146 uint32_t prefix;
147 int pos = 0;
149 prefix = MIN(a->prefix, b->prefix); /* MIN() like in IPv4 */
150 prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */
152 while (prefix >= 8) {
153 dst->value.ipv6.addr.bytes[pos] =
154 a->addr.bytes[pos] & b->addr.bytes[pos];
156 prefix -= 8;
157 pos++;
160 if (prefix != 0) {
161 dst->value.ipv6.addr.bytes[pos] =
162 a->addr.bytes[pos] & b->addr.bytes[pos] & bitmasks[prefix];
164 return FT_OK;
167 static unsigned
168 len(fvalue_t *fv _U_)
170 return FT_IPv6_LEN;
173 static void
174 slice(fvalue_t *fv, GByteArray *bytes, unsigned offset, unsigned length)
176 uint8_t* data;
178 data = fv->value.ipv6.addr.bytes + offset;
180 g_byte_array_append(bytes, data, length);
183 static unsigned
184 ipv6_hash(const fvalue_t *fv)
186 struct _ipv6 {
187 int64_t val[2];
188 } *addr = (struct _ipv6 *)&fv->value.ipv6.addr;
189 int64_t mask = fv->value.ipv6.prefix;
191 return g_int64_hash(&addr->val[0]) ^ g_int64_hash(&addr->val[1]) ^ g_int64_hash(&mask);
194 static bool
195 is_zero(const fvalue_t *fv_a)
197 ws_in6_addr zero = { 0 };
198 return memcmp(&fv_a->value.ipv6.addr, &zero, sizeof(ws_in6_addr)) == 0;
201 void
202 ftype_register_ipv6(void)
204 static const ftype_t ipv6_type = {
205 FT_IPv6, /* ftype */
206 FT_IPv6_LEN, /* wire_size */
207 NULL, /* new_value */
208 NULL, /* copy_value */
209 NULL, /* free_value */
210 ipv6_from_literal, /* val_from_literal */
211 NULL, /* val_from_string */
212 NULL, /* val_from_charconst */
213 NULL, /* val_from_uinteger64 */
214 NULL, /* val_from_sinteger64 */
215 NULL, /* val_from_double */
216 ipv6_to_repr, /* val_to_string_repr */
218 NULL, /* val_to_uinteger64 */
219 NULL, /* val_to_sinteger64 */
220 NULL, /* val_to_double */
222 { .set_value_ipv6 = ipv6_set }, /* union set_value */
223 { .get_value_ipv6 = ipv6_get }, /* union get_value */
225 cmp_order,
226 NULL, /* XXX, cmp_contains, needed? ipv4 doesn't support it */
227 NULL, /* cmp_matches */
229 ipv6_hash,
230 is_zero,
231 NULL,
232 len,
233 (FvalueSlice)slice,
234 bitwise_and,
235 NULL, /* unary_minus */
236 NULL, /* add */
237 NULL, /* subtract */
238 NULL, /* multiply */
239 NULL, /* divide */
240 NULL, /* modulo */
243 ftype_register(FT_IPv6, &ipv6_type);
246 void
247 ftype_register_pseudofields_ipv6(int proto)
249 static int hf_ft_ipv6;
251 static hf_register_info hf_ftypes[] = {
252 { &hf_ft_ipv6,
253 { "FT_IPv6", "_ws.ftypes.ipv6",
254 FT_IPv6, BASE_NONE, NULL, 0x00,
255 NULL, HFILL }
259 proto_register_field_array(proto, hf_ftypes, array_length(hf_ftypes));
263 * Editor modelines - https://www.wireshark.org/tools/modelines.html
265 * Local variables:
266 * c-basic-offset: 8
267 * tab-width: 8
268 * indent-tabs-mode: t
269 * End:
271 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
272 * :indentSize=8:tabSize=8:noTabs=false: