d38836923e690b5bfbc8039643ce7ac18317dcc0
[metze/wireshark/wip.git] / epan / ftypes / ftype-ipv6.c
1 /*
2  * Wireshark - Network traffic analyzer
3  * By Gerald Combs <gerald@wireshark.org>
4  * Copyright 2001 Gerald Combs
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include <ftypes-int.h>
26 #include <epan/ipv6.h>
27 #include <epan/addr_resolv.h>
28 #include <epan/to_str.h>
29
30 static void
31 ipv6_fvalue_set(fvalue_t *fv, const guint8 *value)
32 {
33         memcpy(fv->value.ipv6.addr.bytes, value, FT_IPv6_LEN);
34         fv->value.ipv6.prefix = 128;
35 }
36
37 static gboolean
38 ipv6_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
39 {
40         const char *slash;
41         const char *addr_str;
42         char *addr_str_to_free = NULL;
43         unsigned int nmask_bits;
44         fvalue_t *nmask_fvalue;
45
46         /* Look for prefix: Is there a single slash in the string? */
47         slash = strchr(s, '/');
48         if (slash) {
49                 /* Make a copy of the string up to but not including the
50                  * slash; that's the address portion. */
51                 addr_str_to_free = wmem_strndup(NULL, s, slash-s);
52                 addr_str = addr_str_to_free;
53         }
54         else
55                 addr_str = s;
56
57         if (!get_host_ipaddr6(addr_str, &(fv->value.ipv6.addr))) {
58                 if (err_msg != NULL)
59                         *err_msg = g_strdup_printf("\"%s\" is not a valid hostname or IPv6 address.", s);
60                 if (addr_str_to_free)
61                         wmem_free(NULL, addr_str_to_free);
62                 return FALSE;
63         }
64
65         if (addr_str_to_free)
66                 wmem_free(NULL, addr_str_to_free);
67
68         /* If prefix */
69         if (slash) {
70                 /* XXX - this is inefficient */
71                 nmask_fvalue = fvalue_from_unparsed(FT_UINT32, slash+1, FALSE, err_msg);
72                 if (!nmask_fvalue) {
73                         return FALSE;
74                 }
75                 nmask_bits = fvalue_get_uinteger(nmask_fvalue);
76                 FVALUE_FREE(nmask_fvalue);
77
78                 if (nmask_bits > 128) {
79                         if (err_msg != NULL) {
80                                 *err_msg = g_strdup_printf("Prefix in a IPv6 address should be <= 128, not %u",
81                                                 nmask_bits);
82                         }
83                         return FALSE;
84                 }
85                 fv->value.ipv6.prefix = nmask_bits;
86         } else {
87                 /* Not CIDR; mask covers entire address. */
88                 fv->value.ipv6.prefix = 128;
89         }
90
91         return TRUE;
92 }
93
94 static int
95 ipv6_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_, int field_display _U_)
96 {
97         return MAX_IP6_STR_LEN;
98 }
99
100 static void
101 ipv6_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_, char *buf, unsigned int size)
102 {
103         ip6_to_str_buf(&(fv->value.ipv6.addr), buf, size);
104 }
105
106 static gpointer
107 value_get(fvalue_t *fv)
108 {
109         return fv->value.ipv6.addr.bytes;
110 }
111
112 static const guint8 bitmasks[9] =
113         { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
114
115 static gint
116 cmp_compare(const fvalue_t *fv_a, const fvalue_t *fv_b)
117 {
118         const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
119         const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
120         guint32 prefix;
121         int pos = 0;
122
123         prefix = MIN(a->prefix, b->prefix);     /* MIN() like IPv4 */
124         prefix = MIN(prefix, 128);              /* sanitize, max prefix is 128 */
125
126         while (prefix >= 8) {
127                 gint byte_a = (gint) (a->addr.bytes[pos]);
128                 gint byte_b = (gint) (b->addr.bytes[pos]);
129
130                 if (byte_a != byte_b)
131                         return byte_a - byte_b;
132
133                 prefix -= 8;
134                 pos++;
135         }
136
137         if (prefix != 0) {
138                 gint byte_a = (gint) (a->addr.bytes[pos] & (bitmasks[prefix]));
139                 gint byte_b = (gint) (b->addr.bytes[pos] & (bitmasks[prefix]));
140
141                 if (byte_a != byte_b)
142                         return byte_a - byte_b;
143         }
144         return 0;
145 }
146
147 static gboolean
148 cmp_eq(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
154 cmp_ne(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
160 cmp_gt(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
166 cmp_ge(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
172 cmp_lt(const fvalue_t *fv_a, const fvalue_t *fv_b)
173 {
174         return (cmp_compare(fv_a, fv_b) < 0);
175 }
176
177 static gboolean
178 cmp_le(const fvalue_t *fv_a, const fvalue_t *fv_b)
179 {
180         return (cmp_compare(fv_a, fv_b) <= 0);
181 }
182
183 static gboolean
184 cmp_bitwise_and(const fvalue_t *fv_a, const fvalue_t *fv_b)
185 {
186         const ipv6_addr_and_prefix *a = &(fv_a->value.ipv6);
187         const ipv6_addr_and_prefix *b = &(fv_b->value.ipv6);
188         guint32 prefix;
189         int pos = 0;
190
191         prefix = MIN(a->prefix, b->prefix);     /* MIN() like in IPv4 */
192         prefix = MIN(prefix, 128);                      /* sanitize, max prefix is 128 */
193
194         while (prefix >= 8) {
195                 if (a->addr.bytes[pos] & b->addr.bytes[pos])
196                         return TRUE;
197
198                 prefix -= 8;
199                 pos++;
200         }
201
202         if (prefix != 0) {
203                 guint8 byte_a = (a->addr.bytes[pos] & (bitmasks[prefix]));
204                 guint8 byte_b = (b->addr.bytes[pos] & (bitmasks[prefix]));
205
206                 if (byte_a & byte_b)
207                         return TRUE;
208         }
209         return FALSE;
210 }
211
212 static void
213 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
214 {
215         /* XXX needed? ipv4 doesn't support slice() */
216         guint8* data;
217
218         data = fv->value.ipv6.addr.bytes + offset;
219
220         g_byte_array_append(bytes, data, length);
221 }
222
223 void
224 ftype_register_ipv6(void)
225 {
226         static ftype_t ipv6_type = {
227                 FT_IPv6,                        /* ftype */
228                 "FT_IPv6",                      /* name */
229                 "IPv6 address",                 /* pretty_name */
230                 FT_IPv6_LEN,                    /* wire_size */
231                 NULL,                           /* new_value */
232                 NULL,                           /* free_value */
233                 ipv6_from_unparsed,             /* val_from_unparsed */
234                 NULL,                           /* val_from_string */
235                 ipv6_to_repr,                   /* val_to_string_repr */
236                 ipv6_repr_len,                  /* len_string_repr */
237
238                 { .set_value_bytes = ipv6_fvalue_set }, /* union set_value */
239
240                 NULL,                           /* set_value_sinteger */
241                 NULL,                           /* set_value_uinteger64 */
242                 NULL,                           /* set_value_sinteger64 */
243                 NULL,                           /* set_value_floating */
244
245                 value_get,                      /* get_value */
246                 NULL,                           /* get_value_uinteger */
247                 NULL,                           /* get_value_sinteger */
248                 NULL,                           /* get_value_uinteger64 */
249                 NULL,                           /* get_value_sinteger64 */
250                 NULL,                           /* get_value_floating */
251
252                 cmp_eq,
253                 cmp_ne,
254                 cmp_gt,
255                 cmp_ge,
256                 cmp_lt,
257                 cmp_le,
258                 cmp_bitwise_and,
259                 NULL,                           /* XXX, cmp_contains, needed? ipv4 doesn't support it */
260                 NULL,                           /* cmp_matches */
261
262                 NULL,
263                 slice,
264         };
265
266         ftype_register(FT_IPv6, &ipv6_type);
267 }
268
269 /*
270  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
271  *
272  * Local variables:
273  * c-basic-offset: 8
274  * tab-width: 8
275  * indent-tabs-mode: t
276  * End:
277  *
278  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
279  * :indentSize=8:tabSize=8:noTabs=false:
280  */