d67883cd53d5318e01eccc4f0b6d747be08fa5f5
[obnox/wireshark/wip.git] / epan / ftypes / ftype-bytes.c
1 /*
2  * $Id$
3  *
4  * Ethereal - Network traffic analyzer
5  * By Gerald Combs <gerald@ethereal.com>
6  * Copyright 2001 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <ftypes-int.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <epan/addr_resolv.h>
31 #include <epan/strutil.h>
32
33 #ifdef HAVE_LIBPCRE
34 #include <pcre.h>
35 #define CMP_MATCHES cmp_matches
36 #else
37 #define CMP_MATCHES NULL
38 #endif
39
40 #define ETHER_LEN       6
41 #define IPv6_LEN        16
42
43 static void
44 bytes_fvalue_new(fvalue_t *fv)
45 {
46         fv->value.bytes = NULL;
47 }
48
49 static void
50 bytes_fvalue_free(fvalue_t *fv)
51 {
52         if (fv->value.bytes) {
53                 g_byte_array_free(fv->value.bytes, TRUE);
54                 fv->value.bytes=NULL;
55         }
56 }
57
58
59 static void
60 bytes_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
61 {
62         g_assert(already_copied);
63
64         /* Free up the old value, if we have one */
65         bytes_fvalue_free(fv);
66
67         fv->value.bytes = value;
68 }
69
70 static int
71 bytes_repr_len(fvalue_t *fv, ftrepr_t rtype _U_)
72 {
73         /* 3 bytes for each byte of the byte "NN:" minus 1 byte
74          * as there's no trailing ":". */
75         return fv->value.bytes->len * 3 - 1;
76 }
77
78 static int
79 oid_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_)
80 {
81         /* more exact computation will come later */
82         return fv->value.bytes->len * 3 + 16;
83 }
84
85 static void
86 oid_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, char *buf)
87 {
88         oid_to_str_buf(fv->value.bytes->data, fv->value.bytes->len, buf, oid_repr_len(fv, rtype));
89 }
90
91 static void
92 bytes_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, char *buf)
93 {
94         guint8 *c;
95         char *write_cursor;
96         unsigned int i;
97
98         c = fv->value.bytes->data;
99         write_cursor = buf;
100
101         for (i = 0; i < fv->value.bytes->len; i++) {
102                 if (i == 0) {
103                         sprintf(write_cursor, "%02x", *c++);
104                         write_cursor += 2;
105                 }
106                 else {
107                         sprintf(write_cursor, ":%02x", *c++);
108                         write_cursor += 3;
109                 }
110         }
111 }
112
113 static void
114 common_fvalue_set(fvalue_t *fv, guint8* data, guint len)
115 {
116         /* Free up the old value, if we have one */
117         bytes_fvalue_free(fv);
118
119         fv->value.bytes = g_byte_array_new();
120         g_byte_array_append(fv->value.bytes, data, len);
121 }
122
123 static void
124 ether_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
125 {
126         g_assert(!already_copied);
127         common_fvalue_set(fv, value, ETHER_LEN);
128 }
129
130 static void
131 ipv6_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
132 {
133         g_assert(!already_copied);
134         common_fvalue_set(fv, value, IPv6_LEN);
135 }
136
137 static void
138 oid_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
139 {
140         g_assert(already_copied);
141
142         /* Free up the old value, if we have one */
143         bytes_fvalue_free(fv);
144
145         fv->value.bytes = value;
146 }
147
148
149 static gpointer
150 value_get(fvalue_t *fv)
151 {
152         return fv->value.bytes->data;
153 }
154
155 static gboolean
156 bytes_from_string(fvalue_t *fv, char *s, LogFunc logfunc _U_)
157 {
158         GByteArray      *bytes;
159
160         bytes = g_byte_array_new();
161
162         g_byte_array_append(bytes, (guint8 *)s, strlen(s));
163
164         /* Free up the old value, if we have one */
165         bytes_fvalue_free(fv);
166         fv->value.bytes = bytes;
167
168         return TRUE;
169 }
170
171 static gboolean
172 bytes_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
173 {
174         GByteArray      *bytes;
175         gboolean        res;
176
177         bytes = g_byte_array_new();
178
179         res = hex_str_to_bytes(s, bytes, TRUE);
180
181         if (!res) {
182                 if (logfunc != NULL)
183                         logfunc("\"%s\" is not a valid byte string.", s);
184                 g_byte_array_free(bytes, TRUE);
185                 return FALSE;
186         }
187
188         /* Free up the old value, if we have one */
189         bytes_fvalue_free(fv);
190
191         fv->value.bytes = bytes;
192
193         return TRUE;
194 }
195
196 static gboolean
197 ether_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value, LogFunc logfunc)
198 {
199         guint8  *mac;
200
201         /*
202          * Don't log a message if this fails; we'll try looking it
203          * up as an Ethernet host name if it does, and if that fails,
204          * we'll log a message.
205          */
206         if (bytes_from_unparsed(fv, s, TRUE, NULL)) {
207                 if (fv->value.bytes->len > ETHER_LEN) {
208                         logfunc("\"%s\" contains too many bytes to be a valid Ethernet address.",
209                             s);
210                         return FALSE;
211                 }
212                 else if (fv->value.bytes->len < ETHER_LEN && !allow_partial_value) {
213                         logfunc("\"%s\" contains too few bytes to be a valid Ethernet address.",
214                             s);
215                         return FALSE;
216                 }
217
218                 return TRUE;
219         }
220
221         mac = get_ether_addr(s);
222         if (!mac) {
223                 logfunc("\"%s\" is not a valid hostname or Ethernet address.",
224                     s);
225                 return FALSE;
226         }
227
228         ether_fvalue_set(fv, mac, FALSE);
229         return TRUE;
230 }
231
232 static gboolean
233 ipv6_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
234 {
235         guint8  buffer[16];
236
237         if (!get_host_ipaddr6(s, (struct e_in6_addr*)buffer)) {
238                 logfunc("\"%s\" is not a valid hostname or IPv6 address.", s);
239                 return FALSE;
240         }
241
242         ipv6_fvalue_set(fv, buffer, FALSE);
243         return TRUE;
244 }
245
246 static int
247 ipv6_repr_len(fvalue_t *fv _U_, ftrepr_t rtype _U_)
248 {
249         /*
250          * 39 characters for "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX".
251          */
252         return 39;
253 }
254
255 static void
256 ipv6_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, char *buf)
257 {
258         ip6_to_str_buf((struct e_in6_addr *)fv->value.bytes->data, buf);
259 }
260
261 static gboolean
262 oid_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
263 {
264         GByteArray      *bytes;
265         gboolean        res;
266
267
268         /*
269          * Don't log a message if this fails; we'll try looking it
270          * up as an OID if it does, and if that fails,
271          * we'll log a message.
272          */
273         if (bytes_from_unparsed(fv, s, TRUE, NULL)) {
274                 return TRUE;
275         }
276
277         bytes = g_byte_array_new();
278         res = oid_str_to_bytes(s, bytes);
279         if (!res) {
280                 if (logfunc != NULL)
281                         logfunc("\"%s\" is not a valid OBJECT IDENTIFIER.", s);
282                 g_byte_array_free(bytes, TRUE);
283                 return FALSE;
284         }
285
286         /* Free up the old value, if we have one */
287         bytes_fvalue_free(fv);
288         fv->value.bytes = bytes;
289
290         return TRUE;
291 }
292
293 static guint
294 len(fvalue_t *fv)
295 {
296         return fv->value.bytes->len;
297 }
298
299 static void
300 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
301 {
302         guint8* data;
303
304         data = fv->value.bytes->data + offset;
305
306         g_byte_array_append(bytes, data, length);
307 }
308
309
310 static gboolean
311 cmp_eq(fvalue_t *fv_a, fvalue_t *fv_b)
312 {
313         GByteArray      *a = fv_a->value.bytes;
314         GByteArray      *b = fv_b->value.bytes;
315
316         if (a->len != b->len) {
317                 return FALSE;
318         }
319
320         return (memcmp(a->data, b->data, a->len) == 0);
321 }
322
323
324 static gboolean
325 cmp_ne(fvalue_t *fv_a, fvalue_t *fv_b)
326 {
327         GByteArray      *a = fv_a->value.bytes;
328         GByteArray      *b = fv_b->value.bytes;
329
330         if (a->len != b->len) {
331                 return FALSE;
332         }
333
334         return (memcmp(a->data, b->data, a->len) != 0);
335 }
336
337
338 static gboolean
339 cmp_gt(fvalue_t *fv_a, fvalue_t *fv_b)
340 {
341         GByteArray      *a = fv_a->value.bytes;
342         GByteArray      *b = fv_b->value.bytes;
343
344         if (a->len > b->len) {
345                 return TRUE;
346         }
347
348         if (a->len < b->len) {
349                 return FALSE;
350         }
351
352         return (memcmp(a->data, b->data, a->len) > 0);
353 }
354
355 static gboolean
356 cmp_ge(fvalue_t *fv_a, fvalue_t *fv_b)
357 {
358         GByteArray      *a = fv_a->value.bytes;
359         GByteArray      *b = fv_b->value.bytes;
360
361         if (a->len > b->len) {
362                 return TRUE;
363         }
364
365         if (a->len < b->len) {
366                 return FALSE;
367         }
368
369         return (memcmp(a->data, b->data, a->len) >= 0);
370 }
371
372 static gboolean
373 cmp_lt(fvalue_t *fv_a, fvalue_t *fv_b)
374 {
375         GByteArray      *a = fv_a->value.bytes;
376         GByteArray      *b = fv_b->value.bytes;
377
378         if (a->len < b->len) {
379                 return TRUE;
380         }
381
382         if (a->len > b->len) {
383                 return FALSE;
384         }
385
386         return (memcmp(a->data, b->data, a->len) < 0);
387 }
388
389 static gboolean
390 cmp_le(fvalue_t *fv_a, fvalue_t *fv_b)
391 {
392         GByteArray      *a = fv_a->value.bytes;
393         GByteArray      *b = fv_b->value.bytes;
394
395         if (a->len < b->len) {
396                 return TRUE;
397         }
398
399         if (a->len > b->len) {
400                 return FALSE;
401         }
402
403         return (memcmp(a->data, b->data, a->len) <= 0);
404 }
405
406 static gboolean cmp_bytes_bitwise_and(fvalue_t *fv_a, fvalue_t *fv_b)
407 {
408         GByteArray      *a = fv_a->value.bytes;
409         GByteArray      *b = fv_b->value.bytes;
410         guint i = 0;
411         unsigned char *p_a, *p_b;
412
413         if (b->len != a->len) {
414                 return FALSE;
415         }
416         p_a = a->data;
417         p_b = b->data;
418         while (i < b->len) {
419                 if (p_a[i] & p_b[i])
420                         i++;
421                 else
422                         return FALSE;
423         }
424         return TRUE;
425 }
426
427 static gboolean
428 cmp_contains(fvalue_t *fv_a, fvalue_t *fv_b)
429 {
430         GByteArray      *a = fv_a->value.bytes;
431         GByteArray      *b = fv_b->value.bytes;
432
433         if (epan_memmem(a->data, a->len, b->data, b->len)) {
434                 return TRUE;
435         }
436         else {
437                 return FALSE;
438         }
439 }
440
441 #ifdef HAVE_LIBPCRE
442 static gboolean
443 cmp_matches(fvalue_t *fv_a, fvalue_t *fv_b)
444 {
445         GString *a = fv_a->value.gstring;
446         pcre_tuple_t *pcre = fv_b->value.re;
447         int options = 0;
448         int rc;
449
450         /* fv_b is always a FT_PCRE, otherwise the dfilter semcheck() would have
451          * warned us. For the same reason (and because we're using g_malloc()),
452          * fv_b->value.re is not NULL.
453          */
454         if (strcmp(fv_b->ftype->name, "FT_PCRE") != 0) {
455                 return FALSE;
456         }
457         if (! pcre) {
458                 return FALSE;
459         }
460         rc = pcre_exec(
461                 pcre->re,       /* Compiled PCRE */
462                 pcre->ex,       /* PCRE extra from pcre_study() */
463                 a->str,         /* The data to check for the pattern... */
464                 a->len,         /* ... and its length */
465                 0,                      /* Start offset within data */
466                 options,        /* PCRE options */
467                 NULL,           /* We are not interested in the matched string */
468                 0                       /* of the pattern; only in success or failure. */
469                 );
470         /* NOTE - DO NOT g_free(data) */
471         if (rc == 0) {
472                 return TRUE;
473         }
474         return FALSE;
475 }
476 #endif
477
478 void
479 ftype_register_bytes(void)
480 {
481
482         static ftype_t bytes_type = {
483                 FT_BYTES,                       /* ftype */
484                 "FT_BYTES",                     /* name */
485                 "sequence of bytes",            /* pretty_name */
486                 0,                              /* wire_size */
487                 bytes_fvalue_new,               /* new_value */
488                 bytes_fvalue_free,              /* free_value */
489                 bytes_from_unparsed,            /* val_from_unparsed */
490                 bytes_from_string,              /* val_from_string */
491                 bytes_to_repr,                  /* val_to_string_repr */
492                 bytes_repr_len,                 /* len_string_repr */
493
494                 bytes_fvalue_set,               /* set_value */
495                 NULL,                           /* set_value_integer */
496                 NULL,                           /* set_value_integer64 */
497                 NULL,                           /* set_value_floating */
498
499                 value_get,                      /* get_value */
500                 NULL,                           /* get_value_integer */
501                 NULL,                           /* get_value_integer64 */
502                 NULL,                           /* get_value_floating */
503
504                 cmp_eq,
505                 cmp_ne,
506                 cmp_gt,
507                 cmp_ge,
508                 cmp_lt,
509                 cmp_le,
510                 cmp_bytes_bitwise_and,
511                 cmp_contains,
512                 CMP_MATCHES,
513
514                 len,
515                 slice,
516         };
517
518         static ftype_t uint_bytes_type = {
519                 FT_UINT_BYTES,          /* ftype */
520                 "FT_UINT_BYTES",                /* name */
521                 "sequence of bytes",            /* pretty_name */
522                 0,                              /* wire_size */
523                 bytes_fvalue_new,               /* new_value */
524                 bytes_fvalue_free,              /* free_value */
525                 bytes_from_unparsed,            /* val_from_unparsed */
526                 NULL,                           /* val_from_string */
527                 bytes_to_repr,                  /* val_to_string_repr */
528                 bytes_repr_len,                 /* len_string_repr */
529
530                 bytes_fvalue_set,               /* set_value */
531                 NULL,                           /* set_value_integer */
532                 NULL,                           /* set_value_integer64 */
533                 NULL,                           /* set_value_floating */
534
535                 value_get,                      /* get_value */
536                 NULL,                           /* get_value_integer */
537                 NULL,                           /* get_value_integer64 */
538                 NULL,                           /* get_value_floating */
539
540                 cmp_eq,
541                 cmp_ne,
542                 cmp_gt,
543                 cmp_ge,
544                 cmp_lt,
545                 cmp_le,
546                 cmp_bytes_bitwise_and,
547                 cmp_contains,
548                 NULL,                           /* cmp_matches */
549
550                 len,
551                 slice,
552         };
553
554         static ftype_t ether_type = {
555                 FT_ETHER,                       /* ftype */
556                 "FT_ETHER",                     /* name */
557                 "Ethernet or other MAC address",/* pretty_name */
558                 ETHER_LEN,                      /* wire_size */
559                 bytes_fvalue_new,               /* new_value */
560                 bytes_fvalue_free,              /* free_value */
561                 ether_from_unparsed,            /* val_from_unparsed */
562                 NULL,                           /* val_from_string */
563                 bytes_to_repr,                  /* val_to_string_repr */
564                 bytes_repr_len,                 /* len_string_repr */
565
566                 ether_fvalue_set,               /* set_value */
567                 NULL,                           /* set_value_integer */
568                 NULL,                           /* set_value_integer64 */
569                 NULL,                           /* set_value_floating */
570
571                 value_get,                      /* get_value */
572                 NULL,                           /* get_value_integer */
573                 NULL,                           /* get_value_integer64 */
574                 NULL,                           /* get_value_floating */
575
576                 cmp_eq,
577                 cmp_ne,
578                 cmp_gt,
579                 cmp_ge,
580                 cmp_lt,
581                 cmp_le,
582                 cmp_bytes_bitwise_and,
583                 cmp_contains,
584                 CMP_MATCHES,
585
586                 len,
587                 slice,
588         };
589
590         static ftype_t ipv6_type = {
591                 FT_IPv6,                        /* ftype */
592                 "FT_IPv6",                      /* name */
593                 "IPv6 address",                 /* pretty_name */
594                 IPv6_LEN,                       /* wire_size */
595                 bytes_fvalue_new,               /* new_value */
596                 bytes_fvalue_free,              /* free_value */
597                 ipv6_from_unparsed,             /* val_from_unparsed */
598                 NULL,                           /* val_from_string */
599                 ipv6_to_repr,                   /* val_to_string_repr */
600                 ipv6_repr_len,                  /* len_string_repr */
601
602                 ipv6_fvalue_set,                /* set_value */
603                 NULL,                           /* set_value_integer */
604                 NULL,                           /* set_value_integer64 */
605                 NULL,                           /* set_value_floating */
606
607                 value_get,                      /* get_value */
608                 NULL,                           /* get_value_integer */
609                 NULL,                           /* get_value_integer64 */
610                 NULL,                           /* get_value_floating */
611
612                 cmp_eq,
613                 cmp_ne,
614                 cmp_gt,
615                 cmp_ge,
616                 cmp_lt,
617                 cmp_le,
618                 cmp_bytes_bitwise_and,
619                 cmp_contains,
620                 NULL,                           /* cmp_matches */
621
622                 len,
623                 slice,
624         };
625
626         static ftype_t oid_type = {
627                 FT_OID,                 /* ftype */
628                 "OID",                  /* name */
629                 "OBJECT IDENTIFIER",                    /* pretty_name */
630                 0,                      /* wire_size */
631                 bytes_fvalue_new,               /* new_value */
632                 bytes_fvalue_free,              /* free_value */
633                 oid_from_unparsed,              /* val_from_unparsed */
634                 NULL,                           /* val_from_string */
635                 oid_to_repr,                    /* val_to_string_repr */
636                 oid_repr_len,                   /* len_string_repr */
637
638                 oid_fvalue_set,         /* set_value */
639                 NULL,                           /* set_value_integer */
640                 NULL,                           /* set_value_integer64 */
641                 NULL,                           /* set_value_floating */
642
643                 value_get,                      /* get_value */
644                 NULL,                           /* get_value_integer */
645                 NULL,                           /* get_value_integer64 */
646                 NULL,                           /* get_value_floating */
647
648                 cmp_eq,
649                 cmp_ne,
650                 cmp_gt,
651                 cmp_ge,
652                 cmp_lt,
653                 cmp_le,
654                 cmp_bytes_bitwise_and,
655                 cmp_contains,
656                 NULL,                           /* cmp_matches */
657
658                 len,
659                 slice,
660         };
661
662         ftype_register(FT_BYTES, &bytes_type);
663         ftype_register(FT_UINT_BYTES, &uint_bytes_type);
664         ftype_register(FT_ETHER, &ether_type);
665         ftype_register(FT_IPv6, &ipv6_type);
666         ftype_register(FT_OID, &oid_type);
667 }