1 /*
2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "config.h"
10
11 #include <string.h>
12
13 #include <ftypes-int.h>
14 #include <epan/ipv6.h>
15 #include <epan/addr_resolv.h>
16 #include <epan/to_str.h>
17
18 static void
ipv6_fvalue_set(fvalue_t * fv,const guint8 * value)19 ipv6_fvalue_set(fvalue_t *fv, const guint8 *value)
20 {
21 memcpy(fv->value.ipv6.addr.bytes, value, FT_IPv6_LEN);
22 fv->value.ipv6.prefix = 128;
23 }
24
25 static gboolean
ipv6_from_unparsed(fvalue_t * fv,const char * s,gboolean allow_partial_value _U_,gchar ** err_msg)26 ipv6_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
27 {
28 const char *slash;
29 const char *addr_str;
30 char *addr_str_to_free = NULL;
31 unsigned int nmask_bits;
32 fvalue_t *nmask_fvalue;
33
34 /* Look for prefix: Is there a single slash in the string? */
35 slash = strchr(s, '/');
36 if (slash) {
37 /* Make a copy of the string up to but not including the
38 * slash; that's the address portion. */
39 addr_str_to_free = wmem_strndup(NULL, s, slash-s);
40 addr_str = addr_str_to_free;
41 }
42 else
43 addr_str = s;
44
45 if (!get_host_ipaddr6(addr_str, &(fv->value.ipv6.addr))) {
46 if (err_msg != NULL)
47 *err_msg = g_strdup_printf("\"%s\" is not a valid hostname or IPv6 address.", s);
48 if (addr_str_to_free)
49 wmem_free(NULL, addr_str_to_free);
50 return FALSE;
51 }
52
53 if (addr_str_to_free)
54 wmem_free(NULL, addr_str_to_free);
55
56 /* If prefix */
57 if (slash) {
58 /* XXX - this is inefficient */
59 nmask_fvalue = fvalue_from_unparsed(FT_UINT32, slash+1, FALSE, err_msg);
60 if (!nmask_fvalue) {
61 return FALSE;
62 }
63 nmask_bits = fvalue_get_uinteger(nmask_fvalue);
64 FVALUE_FREE(nmask_fvalue);
65
66 if (nmask_bits > 128) {
67 if (err_msg != NULL) {
68 *err_msg = g_strdup_printf("Prefix in a IPv6 address should be <= 128, not %u",
69 nmask_bits);
70 }
71 return FALSE;
72 }
73 fv->value.ipv6.prefix = nmask_bits;
74 } else {
75 /* Not CIDR; mask covers entire address. */
76 fv->value.ipv6.prefix = 128;
77 }
78
79 return TRUE;
80 }
81
82 static int
ipv6_repr_len(fvalue_t * fv _U_,ftrepr_t rtype _U_,int field_display _U_)83 ipv6_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_)
84 {
85 return WS_INET6_ADDRSTRLEN;
86 }
87
88 static void
ipv6_to_repr(fvalue_t * fv,ftrepr_t rtype _U_,int field_display _U_,char * buf,unsigned int size)89 ipv6_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf, unsigned int size)
90 {
91 ip6_to_str_buf(&(fv->value.ipv6.addr), buf, size);
92 }
93
94 static gpointer
value_get(fvalue_t * fv)95 value_get(fvalue_t *fv)
96 {
97 return fv->value.ipv6.addr.bytes;
98 }
99
100 static const guint8 bitmasks[9] =
101 { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
102
103 static gint
cmp_compare(const fvalue_t * fv_a,const fvalue_t * fv_b)104 cmp_compare(const fvalue_t *fv_a, const fvalue_t *fv_b)
105 {
106 const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
107 const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
108 guint32 prefix;
109 int pos = 0;
110
111 prefix = MIN(a->prefix, b->prefix); /* MIN() like IPv4 */
112 prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */
113
114 while (prefix >= 8) {
115 gint byte_a = (gint) (a->addr.bytes[pos]);
116 gint byte_b = (gint) (b->addr.bytes[pos]);
117
118 if (byte_a != byte_b)
119 return byte_a - byte_b;
120
121 prefix -= 8;
122 pos++;
123 }
124
125 if (prefix != 0) {
126 gint byte_a = (gint) (a->addr.bytes[pos] & (bitmasks[prefix]));
127 gint byte_b = (gint) (b->addr.bytes[pos] & (bitmasks[prefix]));
128
129 if (byte_a != byte_b)
130 return byte_a - byte_b;
131 }
132 return 0;
133 }
134
135 static gboolean
cmp_eq(const fvalue_t * fv_a,const fvalue_t * fv_b)136 cmp_eq(const fvalue_t *fv_a, const fvalue_t *fv_b)
137 {
138 return (cmp_compare(fv_a, fv_b) == 0);
139 }
140
141 static gboolean
cmp_ne(const fvalue_t * fv_a,const fvalue_t * fv_b)142 cmp_ne(const fvalue_t *fv_a, const fvalue_t *fv_b)
143 {
144 return (cmp_compare(fv_a, fv_b) != 0);
145 }
146
147 static gboolean
cmp_gt(const fvalue_t * fv_a,const fvalue_t * fv_b)148 cmp_gt(const fvalue_t *fv_a, const fvalue_t *fv_b)
149 {
150 return (cmp_compare(fv_a, fv_b) > 0);
151 }
152
153 static gboolean
cmp_ge(const fvalue_t * fv_a,const fvalue_t * fv_b)154 cmp_ge(const fvalue_t *fv_a, const fvalue_t *fv_b)
155 {
156 return (cmp_compare(fv_a, fv_b) >= 0);
157 }
158
159 static gboolean
cmp_lt(const fvalue_t * fv_a,const fvalue_t * fv_b)160 cmp_lt(const fvalue_t *fv_a, const fvalue_t *fv_b)
161 {
162 return (cmp_compare(fv_a, fv_b) < 0);
163 }
164
165 static gboolean
cmp_le(const fvalue_t * fv_a,const fvalue_t * fv_b)166 cmp_le(const fvalue_t *fv_a, const fvalue_t *fv_b)
167 {
168 return (cmp_compare(fv_a, fv_b) <= 0);
169 }
170
171 static gboolean
cmp_bitwise_and(const fvalue_t * fv_a,const fvalue_t * fv_b)172 cmp_bitwise_and(const fvalue_t *fv_a, const fvalue_t *fv_b)
173 {
174 const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
175 const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
176 guint32 prefix;
177 int pos = 0;
178
179 prefix = MIN(a->prefix, b->prefix); /* MIN() like in IPv4 */
180 prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */
181
182 while (prefix >= 8) {
183 if (a->addr.bytes[pos] & b->addr.bytes[pos])
184 return TRUE;
185
186 prefix -= 8;
187 pos++;
188 }
189
190 if (prefix != 0) {
191 guint8 byte_a = (a->addr.bytes[pos] & (bitmasks[prefix]));
192 guint8 byte_b = (b->addr.bytes[pos] & (bitmasks[prefix]));
193
194 if (byte_a & byte_b)
195 return TRUE;
196 }
197 return FALSE;
198 }
199
200 static void
slice(fvalue_t * fv,GByteArray * bytes,guint offset,guint length)201 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
202 {
203 guint8* data;
204
205 data = fv->value.ipv6.addr.bytes + offset;
206
207 g_byte_array_append(bytes, data, length);
208 }
209
210 void
ftype_register_ipv6(void)211 ftype_register_ipv6(void)
212 {
213 static ftype_t ipv6_type = {
214 FT_IPv6, /* ftype */
215 "FT_IPv6", /* name */
216 "IPv6 address", /* pretty_name */
217 FT_IPv6_LEN, /* wire_size */
218 NULL, /* new_value */
219 NULL, /* free_value */
220 ipv6_from_unparsed, /* val_from_unparsed */
221 NULL, /* val_from_string */
222 ipv6_to_repr, /* val_to_string_repr */
223 ipv6_repr_len, /* len_string_repr */
224
225 { .set_value_bytes = ipv6_fvalue_set }, /* union set_value */
226 { .get_value_ptr = value_get }, /* union get_value */
227
228 cmp_eq,
229 cmp_ne,
230 cmp_gt,
231 cmp_ge,
232 cmp_lt,
233 cmp_le,
234 cmp_bitwise_and,
235 NULL, /* XXX, cmp_contains, needed? ipv4 doesn't support it */
236 NULL, /* cmp_matches */
237
238 NULL,
239 slice,
240 };
241
242 ftype_register(FT_IPv6, &ipv6_type);
243 }
244
245 /*
246 * Editor modelines - https://www.wireshark.org/tools/modelines.html
247 *
248 * Local variables:
249 * c-basic-offset: 8
250 * tab-width: 8
251 * indent-tabs-mode: t
252 * End:
253 *
254 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
255 * :indentSize=8:tabSize=8:noTabs=false:
256 */
257