From ec9ca01616d179043c0e84d5e5799cfec8ad63ba Mon Sep 17 00:00:00 2001 From: Lars Roland Date: Wed, 9 Feb 2005 23:38:00 +0000 Subject: Move the following files from /trunk to /trunk/epan: asn1.[ch] follow.[ch] ptvcursor.[ch] reassemble.[ch] xmlstub.[ch] fix #include statements accordingly. svn path=/trunk/; revision=13366 --- epan/Makefile.common | 21 +- epan/asn1.c | 1085 +++++++++++++++++++++ epan/asn1.h | 150 +++ epan/dissectors/ncp2222.py | 2 +- epan/dissectors/packet-acse.c | 2 +- epan/dissectors/packet-ansi_map.c | 2 +- epan/dissectors/packet-atalk.c | 2 +- epan/dissectors/packet-clnp.c | 2 +- epan/dissectors/packet-cops.c | 2 +- epan/dissectors/packet-dcerpc.c | 2 +- epan/dissectors/packet-diameter.c | 2 +- epan/dissectors/packet-dnp.c | 2 +- epan/dissectors/packet-eap.c | 2 +- epan/dissectors/packet-fc.c | 2 +- epan/dissectors/packet-ftam.c | 2 +- epan/dissectors/packet-gsm_a.c | 2 +- epan/dissectors/packet-gsm_sms_ud.c | 2 +- epan/dissectors/packet-gsm_ss.c | 2 +- epan/dissectors/packet-gssapi.c | 2 +- epan/dissectors/packet-ieee80211.c | 2 +- epan/dissectors/packet-inap.c | 2 +- epan/dissectors/packet-ip.c | 2 +- epan/dissectors/packet-ipv6.c | 2 +- epan/dissectors/packet-kerberos.c | 2 +- epan/dissectors/packet-ldap.c | 2 +- epan/dissectors/packet-lwapp.c | 2 +- epan/dissectors/packet-mq.c | 2 +- epan/dissectors/packet-mysql.c | 2 +- epan/dissectors/packet-ncp.c | 2 +- epan/dissectors/packet-ndmp.c | 2 +- epan/dissectors/packet-ndps.c | 2 +- epan/dissectors/packet-netbios.c | 2 +- epan/dissectors/packet-ntlmssp.c | 2 +- epan/dissectors/packet-pgsql.c | 2 +- epan/dissectors/packet-pres.c | 2 +- epan/dissectors/packet-q931.c | 2 +- epan/dissectors/packet-rpc.c | 2 +- epan/dissectors/packet-smb-pipe.c | 2 +- epan/dissectors/packet-smb.c | 2 +- epan/dissectors/packet-sna.c | 2 +- epan/dissectors/packet-sndcp.c | 2 +- epan/dissectors/packet-snmp.c | 2 +- epan/dissectors/packet-spnego.c | 2 +- epan/dissectors/packet-srvloc.c | 2 +- epan/dissectors/packet-ssh.c | 2 +- epan/dissectors/packet-tcap.c | 2 +- epan/dissectors/packet-tcp.c | 4 +- epan/dissectors/packet-tds.c | 2 +- epan/dissectors/packet-wtp.c | 2 +- epan/dissectors/packet-x25.c | 2 +- epan/follow.c | 336 +++++++ epan/follow.h | 57 ++ epan/packet.c | 2 +- epan/plugins.c | 4 +- epan/ptvcursor.c | 116 +++ epan/ptvcursor.h | 80 ++ epan/reassemble.c | 1833 +++++++++++++++++++++++++++++++++++ epan/reassemble.h | 244 +++++ epan/xmlstub.c | 170 ++++ epan/xmlstub.h | 1123 +++++++++++++++++++++ 60 files changed, 5258 insertions(+), 59 deletions(-) create mode 100644 epan/asn1.c create mode 100644 epan/asn1.h create mode 100644 epan/follow.c create mode 100644 epan/follow.h create mode 100644 epan/ptvcursor.c create mode 100644 epan/ptvcursor.h create mode 100644 epan/reassemble.c create mode 100644 epan/reassemble.h create mode 100644 epan/xmlstub.c create mode 100644 epan/xmlstub.h (limited to 'epan') diff --git a/epan/Makefile.common b/epan/Makefile.common index f6d7e22526..4002bd54b2 100644 --- a/epan/Makefile.common +++ b/epan/Makefile.common @@ -28,6 +28,7 @@ LIBETHEREAL_SRC = \ addr_resolv.c \ adler32.c \ afn.c \ + asn1.c \ atalk-utils.c \ base64.c \ bitswap.c \ @@ -45,6 +46,7 @@ LIBETHEREAL_SRC = \ epan.c \ except.c \ filesystem.c \ + follow.c \ frame_data.c \ h225-persistentdata.c \ in_cksum.c \ @@ -55,7 +57,9 @@ LIBETHEREAL_SRC = \ plugins.c \ prefs.c \ proto.c \ + ptvcursor.c \ range.c \ + reassemble.c \ req_resp_hdrs.c \ sha1.c \ sigcomp_state_hdlr.c \ @@ -69,7 +73,8 @@ LIBETHEREAL_SRC = \ to_str.c \ tvbuff.c \ value_string.c \ - xdlc.c + xdlc.c \ + xmlstub.c LIBETHEREAL_INCLUDES = \ addr_and_mask.h \ @@ -78,6 +83,7 @@ LIBETHEREAL_INCLUDES = \ adler32.h \ afn.h \ arptypes.h \ + asn1.h \ atalk-utils.h \ base64.h \ bitswap.h \ @@ -98,6 +104,7 @@ LIBETHEREAL_INCLUDES = \ except.h \ exceptions.h \ filesystem.h \ + follow.h \ frame_data.h \ gdebug.h \ h225-persistentdata.h \ @@ -114,7 +121,9 @@ LIBETHEREAL_INCLUDES = \ prefs.h \ prefs-int.h \ proto.h \ + ptvcursor.h \ range.h \ + reassemble.h \ report_err.h \ req_resp_hdrs.h \ sha1.h \ @@ -130,13 +139,9 @@ LIBETHEREAL_INCLUDES = \ to_str.h \ tvbuff.h \ value_string.h \ - xdlc.h + xdlc.h \ + xmlstub.h # dissector helpers (needed from the dissectors, but not a dissector itself) -DISSECTOR_SUPPORT_SRC = \ - ../asn1.c \ - ../follow.c \ - ../ptvcursor.c \ - ../reassemble.c \ - ../xmlstub.c +DISSECTOR_SUPPORT_SRC = diff --git a/epan/asn1.c b/epan/asn1.c new file mode 100644 index 0000000000..f9ff91f85c --- /dev/null +++ b/epan/asn1.c @@ -0,0 +1,1085 @@ +/* asn1.c + * Routines for ASN.1 BER dissection + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * + * Based on "g_asn1.c" from: + * + * GXSNMP -- An snmp mangament application + * Copyright (C) 1998 Gregory McLean & Jochen Friedrich + * Beholder RMON ethernet network monitor, Copyright (C) 1993 DNPAP group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * MODULE INFORMATION + * ------------------ + * FILE NAME: g_asn1.c + * SYSTEM NAME: ASN1 Basic Encoding + * ORIGINAL AUTHOR(S): Dirk Wisse + * VERSION NUMBER: 1 + * CREATION DATE: 1990/11/22 + * + * DESCRIPTION: ASN1 Basic Encoding Rules. + * + * To decode this we must do: + * + * asn1_open (asn1, tvb, offset); + * asn1_header_decode (asn1, &end_of_seq, cls, con, tag, def, len); + * asn1_header_decode (asn1, &end_of_octs, cls, con, tag, def, len); + * asn1_octets_decode (asn1, end_of_octs, str, len); + * asn1_header_decode (asn1, &end_of_int, cls, con, tag); + * asn1_int_decode (asn1, end_of_int, &integer); + * asn1_eoc_decode (asn1, end_of_seq); + * asn1_close (asn1, &offset); + * + * For indefinite encoding end_of_seq and &end_of_seq in the + * example above should be replaced by NULL. + * For indefinite decoding nothing has to be changed. + * This can be very useful if you want to decode both + * definite and indefinite encodings. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include + +#ifdef NEED_SNPRINTF_H +# include "snprintf.h" +#endif + +#include +#include + +/* + * NAME: asn1_open [API] + * SYNOPSIS: void asn1_open + * ( + * ASN1_SCK *asn1, + * tvbuff_t *tvb, + * int offset + * ) + * DESCRIPTION: Opens an ASN1 socket. + * Parameters: + * asn1: pointer to ASN1 socket. + * tvb: Tvbuff for encoding. + * offset: Current offset in tvbuff. + * Encoding starts at the end of the buffer, and + * proceeds to the beginning. + * RETURNS: void + */ + +void +asn1_open(ASN1_SCK *asn1, tvbuff_t *tvb, int offset) +{ + asn1->tvb = tvb; + asn1->offset = offset; +} + +/* + * NAME: asn1_close [API] + * SYNOPSIS: void asn1_close + * ( + * ASN1_SCK *asn1, + * int *offset + * ) + * DESCRIPTION: Closes an ASN1 socket. + * Parameters: + * asn1: pointer to ASN1 socket. + * offset: pointer to variable into which current offset is + * to be put. + * RETURNS: void + */ + +void +asn1_close(ASN1_SCK *asn1, int *offset) +{ + *offset = asn1->offset; +} + +/* + * NAME: asn1_octet_decode + * SYNOPSIS: int asn1_octet_decode + * ( + * ASN1_SCK *asn1, + * guchar *ch + * ) + * DESCRIPTION: Decodes an octet. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_octet_decode(ASN1_SCK *asn1, guchar *ch) +{ + *ch = tvb_get_guint8(asn1->tvb, asn1->offset); + asn1->offset++; + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_tag_get + * SYNOPSIS: int asn1_tag_get + * ( + * ASN1_SCK *asn1, + * guint *tag + * ) + * DESCRIPTION: Decodes a tag number, combining it with existing tag bits. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +static int +asn1_tag_get(ASN1_SCK *asn1, guint *tag) +{ + int ret; + guchar ch; + + do { + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *tag <<= 7; + *tag |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_tag_decode + * SYNOPSIS: int asn1_tag_decode + * ( + * ASN1_SCK *asn1, + * guint *tag + * ) + * DESCRIPTION: Decodes a tag number. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_tag_decode(ASN1_SCK *asn1, guint *tag) +{ + *tag = 0; + return asn1_tag_get(asn1, tag); +} + +/* + * NAME: asn1_id_decode + * SYNOPSIS: int asn1_id_decode + * ( + * ASN1_SCK *asn1, + * guint *cls, + * guint *con, + * guint *tag + * ) + * DESCRIPTION: Decodes an identifier. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_id_decode(ASN1_SCK *asn1, guint *cls, guint *con, guint *tag) +{ + int ret; + guchar ch; + + *tag = 0; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *cls = (ch & 0xC0) >> 6; + *con = (ch & 0x20) >> 5; + *tag = (ch & 0x1F); + if (*tag == 0x1F) { + ret = asn1_tag_decode (asn1, tag); + if (ret != ASN1_ERR_NOERROR) + return ret; + } + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_id_decode1 + * SYNOPSIS: int asn1_id_decode1 + * ( + * ASN1_SCK *asn1, + * guint *tag + * ) + * DESCRIPTION: Decodes an identifier. + * Like asn1_id_decode() except that the Class and Constructor + * bits are returned in the tag. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_id_decode1(ASN1_SCK *asn1, guint *tag) +{ + int ret; + guchar ch; + + *tag = 0; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + + *tag = ch; + if ((*tag & 0x1F) == 0x1F) { /* high-tag-number format */ + *tag = ch >> 5; /* leave just the Class and Constructor bits */ + ret = asn1_tag_get (asn1, tag); + if (ret != ASN1_ERR_NOERROR) + return ret; + } + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_length_decode + * SYNOPSIS: int asn1_length_decode + * ( + * ASN1_SCK *asn1, + * gboolean *def, + * guint *len + * ) + * DESCRIPTION: Decodes an ASN1 length. + * Parameters: + * asn1: pointer to ASN1 socket. + * def: Boolean - TRUE if length definite, FALSE if not + * len: length, if length is definite + * DESCRIPTION: Decodes a definite or indefinite length. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_length_decode(ASN1_SCK *asn1, gboolean *def, guint *len) +{ + int ret; + guchar ch, cnt; + + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + if (ch == 0x80) + *def = FALSE; /* indefinite length */ + else { + *def = TRUE; /* definite length */ + if (ch < 0x80) + *len = ch; + else { + cnt = (guchar) (ch & 0x7F); + *len = 0; + while (cnt > 0) { + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *len <<= 8; + *len |= ch; + cnt--; + } + } + } + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_header_decode [API] + * SYNOPSIS: int asn1_header_decode + * ( + * ASN1_SCK *asn1, + * guint *cls, + * guint *con, + * guint *tag + * gboolean *defp, + * guint *lenp + * ) + * DESCRIPTION: Decodes an ASN1 header. + * Parameters: + * asn1: pointer to ASN1 socket. + * cls: Class (see asn1.h) + * con: Primitive, Constructed (ASN1_PRI, ASN1_CON) + * tag: Tag (see asn1.h) + * defp: Boolean - TRUE if length definite, FALSE if not + * lenp: length, if length is definite + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_header_decode(ASN1_SCK *asn1, guint *cls, guint *con, guint *tag, + gboolean *defp, guint *lenp) +{ + int ret; + guint def, len; + + ret = asn1_id_decode (asn1, cls, con, tag); + if (ret != ASN1_ERR_NOERROR) + return ret; + ret = asn1_length_decode (asn1, &def, &len); + if (ret != ASN1_ERR_NOERROR) + return ret; + *defp = def; + *lenp = len; + return ASN1_ERR_NOERROR; +} + + +/* + * NAME: asn1_eoc [API] + * SYNOPSIS: gboolean asn1_eoc + * ( + * ASN1_SCK *asn1, + * int eoc + * ) + * DESCRIPTION: Checks if decoding is at End Of Contents. + * Parameters: + * asn1: pointer to ASN1 socket. + * eoc: offset of end of encoding, or -1 if indefinite. + * RETURNS: gboolean success + */ +gboolean +asn1_eoc ( ASN1_SCK *asn1, int eoc) +{ + if (eoc == -1) + return (tvb_get_guint8(asn1->tvb, asn1->offset) == 0x00 + && tvb_get_guint8(asn1->tvb, asn1->offset + 1) == 0x00); + else + return (asn1->offset >= eoc); +} + +/* + * NAME: asn1_eoc_decode [API] + * SYNOPSIS: int asn1_eoc_decode + * ( + * ASN1_SCK *asn1, + * int eoc + * ) + * DESCRIPTION: Decodes End Of Contents. + * Parameters: + * asn1: pointer to ASN1 socket. + * eoc: offset of end of encoding, or -1 if indefinite. + * If eoc is -1 it decodes an ASN1 End Of + * Contents (0x00 0x00), so it has to be an + * indefinite length encoding. If eoc is a non-negative + * integer, it probably was filled by asn1_header_decode, + * and should refer to the octet after the last of the encoding. + * It is checked if this offset refers to the octet to be + * decoded. This only takes place in decoding a + * definite length encoding. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_eoc_decode (ASN1_SCK *asn1, int eoc) +{ + int ret; + guchar ch; + + if (eoc == -1) { + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + if (ch != 0x00) + return ASN1_ERR_EOC_MISMATCH; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + if (ch != 0x00) + return ASN1_ERR_EOC_MISMATCH; + return ASN1_ERR_NOERROR; + } else { + if (asn1->offset != eoc) + return ASN1_ERR_LENGTH_MISMATCH; + return ASN1_ERR_NOERROR; + } +} + +/* + * NAME: asn1_null_decode [API] + * SYNOPSIS: int asn1_null_decode + * ( + * ASN1_SCK *asn1, + * int enc_len + * ) + * DESCRIPTION: Decodes Null. + * Parameters: + * asn1: pointer to ASN1 socket. + * enc_len: length of encoding of value. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_null_decode ( ASN1_SCK *asn1, int enc_len) +{ + int start_off = asn1->offset; + + asn1->offset += enc_len; + /* + * Check for integer overflows. + * XXX - ASN1_ERR_LENGTH_MISMATCH seemed like the most appropriate + * error from the ones available. Should we make a new one? + */ + if (asn1->offset < 0 || asn1->offset < start_off) + return ASN1_ERR_LENGTH_MISMATCH; + + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_bool_decode [API] + * SYNOPSIS: int asn1_bool_decode + * ( + * ASN1_SCK *asn1, + * int enc_len, + * gboolean *boolean + * ) + * DESCRIPTION: Decodes Boolean. + * Parameters: + * asn1: pointer to ASN1 socket. + * enc_len: length of encoding of value. + * bool: False, True (0, !0). + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_bool_decode ( ASN1_SCK *asn1, int enc_len, gboolean *boolean) +{ + int ret; + guchar ch; + + if (enc_len != 1) + return ASN1_ERR_LENGTH_MISMATCH; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *boolean = ch ? TRUE : FALSE; + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_int32_value_decode [API] + * SYNOPSIS: int asn1_int32_value_decode + * ( + * ASN1_SCK *asn1, + * int enc_len, + * gint32 *integer + * ) + * DESCRIPTION: Decodes value portion of Integer (which must be no more + * than 32 bits). + * Parameters: + * asn1: pointer to ASN1 socket. + * enc_len: length of encoding of value. + * integer: Integer. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_int32_value_decode ( ASN1_SCK *asn1, int enc_len, gint32 *integer) +{ + int ret; + int eoc; + guchar ch; + guint len; + + eoc = asn1->offset + enc_len; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *integer = (gint) ch; + len = 1; + while (asn1->offset < eoc) { + if (++len > sizeof (gint32)) + return ASN1_ERR_WRONG_LENGTH_FOR_TYPE; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *integer <<= 8; + *integer |= ch; + } + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_int32_decode [API] + * SYNOPSIS: int asn1_int32_decode + * ( + * ASN1_SCK *asn1, + * gint32 *integer, + * guint *nbytes, + * ) + * DESCRIPTION: Decodes Integer (which must be no more than 32 bits). + * Parameters: + * asn1: pointer to ASN1 socket. + * integer: Integer. + * nbytes: number of bytes used to encode it. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_int32_decode ( ASN1_SCK *asn1, gint32 *integer, guint *nbytes) +{ + int ret; + int start; + guint cls; + guint con; + guint tag; + gboolean def; + guint enc_len; + + start = asn1->offset; + ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len); + if (ret != ASN1_ERR_NOERROR) + goto done; + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) { + ret = ASN1_ERR_WRONG_TYPE; + goto done; + } + if (!def) { + ret = ASN1_ERR_LENGTH_NOT_DEFINITE; + goto done; + } + ret = asn1_int32_value_decode (asn1, enc_len, integer); + +done: + *nbytes = asn1->offset - start; + return ret; +} + +/* + * NAME: asn1_uint32_value_decode [API] + * SYNOPSIS: int asn1_uint32_value_decode + * ( + * ASN1_SCK *asn1, + * int enc_len, + * guint32 *integer + * ) + * DESCRIPTION: Decodes value part of Unsigned Integer (which must be no + * more than 32 bits). + * Parameters: + * asn1: pointer to ASN1 socket. + * enc_len: length of encoding of value. + * integer: Integer. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_uint32_value_decode ( ASN1_SCK *asn1, int enc_len, guint32 *integer) +{ + int ret; + int eoc; + guchar ch; + guint len; + + eoc = asn1->offset + enc_len; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *integer = ch; + if (ch == 0) + len = 0; + else + len = 1; + while (asn1->offset < eoc) { + if (++len > sizeof (guint32)) + return ASN1_ERR_WRONG_LENGTH_FOR_TYPE; + ret = asn1_octet_decode (asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *integer <<= 8; + *integer |= ch; + } + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_uint32_decode [API] + * SYNOPSIS: int asn1_uint32_decode + * ( + * ASN1_SCK *asn1, + * guint32 *integer, + * guint *nbytes, + * ) + * DESCRIPTION: Decodes Unsigned Integer (which must be no more than 32 bits). + * Parameters: + * asn1: pointer to ASN1 socket. + * integer: Integer. + * nbytes: number of bytes used to encode it. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_uint32_decode ( ASN1_SCK *asn1, guint32 *integer, guint *nbytes) +{ + int ret; + int start; + guint cls; + guint con; + guint tag; + gboolean def; + guint enc_len; + + start = asn1->offset; + ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len); + if (ret != ASN1_ERR_NOERROR) + goto done; + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) { + ret = ASN1_ERR_WRONG_TYPE; + goto done; + } + if (!def) { + ret = ASN1_ERR_LENGTH_NOT_DEFINITE; + goto done; + } + ret = asn1_uint32_value_decode (asn1, enc_len, integer); + +done: + *nbytes = asn1->offset - start; + return ret; +} + +/* + * NAME: asn1_bits_decode [API] + * SYNOPSIS: int asn1_bits_decode + * ( + * ASN1_SCK *asn1, + * int eoc, + * guchar *bits, + * guint size, + * guint len, + * guchar unused + * ) + * DESCRIPTION: Decodes Bit String. + * Parameters: + * asn1: pointer to ASN1 socket. + * enc_len: length of value. + * bits: pointer to variable we set to point to strring + * len: Size of Bit String in characters. + * unused: Number of unused bits in last character. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_bits_decode ( ASN1_SCK *asn1, int enc_len, guchar **bits, + guint *len, guchar *unused) +{ + int ret; + int eoc; + guchar *ptr; + + eoc = asn1->offset + enc_len; + *bits = NULL; + ret = asn1_octet_decode (asn1, unused); + if (ret != ASN1_ERR_NOERROR) + return ret; + *len = 0; + + /* + * First, make sure the entire string is in the tvbuff, and throw + * an exception if it isn't. If the length is bogus, this should + * keep us from trying to allocate an immensely large buffer. + * (It won't help if the length is *valid* but immensely large, + * but that's another matter; in any case, that would happen only + * if we had an immensely large tvbuff....) + */ + if (enc_len != 0) { + tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len); + *bits = g_malloc (enc_len); + } else { + /* + * If the length is 0, we allocate a 1-byte buffer, as + * "g_malloc()" returns NULL if passed 0 as an argument, + * and our caller expects us to return a pointer to a + * buffer. + */ + *bits = g_malloc (1); + } + + ptr = *bits; + while (asn1->offset < eoc) { + ret = asn1_octet_decode (asn1, (guchar *)ptr++); + if (ret != ASN1_ERR_NOERROR) { + g_free(*bits); + *bits = NULL; + return ret; + } + } + *len = ptr - *bits; + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_string_value_decode [API] + * SYNOPSIS: int asn1_string_value_decode + * ( + * ASN1_SCK *asn1, + * int enc_len, + * guchar **octets + * ) + * DESCRIPTION: Decodes value portion of string (Octet String, various + * character string types) + * Parameters: + * asn1: pointer to ASN1 socket. + * enc_len: length of encoding of value. + * octets: pointer to variable we set to point to string, + * which is '\0' terminated for ease of use as C-string + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_string_value_decode ( ASN1_SCK *asn1, int enc_len, guchar **octets) +{ + int ret; + int eoc; + guchar *ptr; + + /* + * First, make sure the entire string is in the tvbuff, and throw + * an exception if it isn't. If the length is bogus, this should + * keep us from trying to allocate an immensely large buffer. + * (It won't help if the length is *valid* but immensely large, + * but that's another matter; in any case, that would happen only + * if we had an immensely large tvbuff....) + */ + if (enc_len != 0) + tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len); + *octets = g_malloc (enc_len+1); + + eoc = asn1->offset + enc_len; + ptr = *octets; + while (asn1->offset < eoc) { + ret = asn1_octet_decode (asn1, (guchar *)ptr++); + if (ret != ASN1_ERR_NOERROR) { + g_free(*octets); + *octets = NULL; + return ret; + } + } + *(guchar *)ptr = '\0'; + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_string_decode [API] + * SYNOPSIS: int asn1_string_decode + * ( + * ASN1_SCK *asn1, + * guchar **octets, + * guint *str_len, + * guint *nbytes, + * guint expected_tag + * ) + * DESCRIPTION: Decodes string (Octet String, various character string + * types) + * Parameters: + * asn1: pointer to ASN1 socket. + * octets: pointer to variable we set to point to string. + * str_len: length of octet_string. + * nbytes: number of bytes used to encode. + * expected_tag: tag expected for this type of string. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_string_decode ( ASN1_SCK *asn1, guchar **octets, guint *str_len, + guint *nbytes, guint expected_tag) +{ + int ret; + int start; + int enc_len; + guint cls; + guint con; + guint tag; + gboolean def; + + start = asn1->offset; + ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len); + if (ret != ASN1_ERR_NOERROR) + goto done; + if (cls != ASN1_UNI || con != ASN1_PRI || tag != expected_tag) { + /* XXX - handle the constructed encoding? */ + ret = ASN1_ERR_WRONG_TYPE; + goto done; + } + if (!def) { + ret = ASN1_ERR_LENGTH_NOT_DEFINITE; + goto done; + } + + ret = asn1_string_value_decode (asn1, enc_len, octets); + *str_len = enc_len; + +done: + *nbytes = asn1->offset - start; + return ret; +} + +/* + * NAME: asn1_octet_string_decode [API] + * SYNOPSIS: int asn1_octet_string_decode + * ( + * ASN1_SCK *asn1, + * guchar **octets, + * guint *str_len, + * guint *nbytes, + * ) + * DESCRIPTION: Decodes Octet String. + * Parameters: + * asn1: pointer to ASN1 socket. + * octets: pointer to variable we set to point to string. + * str_len: length of octet_string. + * nbytes: number of bytes used to encode. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_octet_string_decode ( ASN1_SCK *asn1, guchar **octets, guint *str_len, + guint *nbytes) +{ + return asn1_string_decode(asn1, octets, str_len, nbytes, ASN1_OTS); +} + +/* + * NAME: asn1_subid_decode + * SYNOPSIS: int asn1_subid_decode + * ( + * ASN1_SCK *asn1, + * subid_t *subid + * ) + * DESCRIPTION: Decodes Sub Identifier. + * Parameters: + * asn1: pointer to ASN1 socket. + * subid: Sub Identifier. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_subid_decode ( ASN1_SCK *asn1, subid_t *subid) +{ + int ret; + guchar ch; + + *subid = 0; + do { + ret = asn1_octet_decode(asn1, &ch); + if (ret != ASN1_ERR_NOERROR) + return ret; + *subid <<= 7; + *subid |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_oid_value_decode [API] + * SYNOPSIS: int asn1_oid_value_decode + * ( + * ASN1_SCK *asn1, + * int enc_len, + * subid_t **oid, + * guint *len + * ) + * DESCRIPTION: Decodes value portion of Object Identifier. + * Parameters: + * asn1: pointer to ASN1 socket. + * enc_len: length of encoding of value. + * oid: pointer to variable we set to Object Identifier. + * len: Length of Object Identifier in gulongs. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_oid_value_decode ( ASN1_SCK *asn1, int enc_len, subid_t **oid, guint *len) +{ + int ret; + int eoc; + subid_t subid; + guint size; + subid_t *optr; + + /* + * First, make sure the entire string is in the tvbuff, and throw + * an exception if it isn't. If the length is bogus, this should + * keep us from trying to allocate an immensely large buffer. + * (It won't help if the length is *valid* but immensely large, + * but that's another matter; in any case, that would happen only + * if we had an immensely large tvbuff....) + */ + if (enc_len != 0) + tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len); + + eoc = asn1->offset + enc_len; + + size = enc_len + 1; + *oid = g_malloc(size * sizeof(gulong)); + optr = *oid; + + ret = asn1_subid_decode (asn1, &subid); + if (ret != ASN1_ERR_NOERROR) { + g_free(*oid); + *oid = NULL; + return ret; + } + if (subid < 40) { + optr[0] = 0; + optr[1] = subid; + } else if (subid < 80) { + optr[0] = 1; + optr[1] = subid - 40; + } else { + optr[0] = 2; + optr[1] = subid - 80; + } + *len = 2; + optr += 2; + while (asn1->offset < eoc) { + if (++(*len) > size) { + g_free(*oid); + *oid = NULL; + return ASN1_ERR_WRONG_LENGTH_FOR_TYPE; + } + ret = asn1_subid_decode (asn1, optr++); + if (ret != ASN1_ERR_NOERROR) { + g_free(*oid); + *oid = NULL; + return ret; + } + } + return ASN1_ERR_NOERROR; +} + +/* + * NAME: asn1_oid_decode [API] + * SYNOPSIS: int asn1_oid_decode + * ( + * ASN1_SCK *asn1, + * subid_t **oid, + * guint *len, + * guint *nbytes + * ) + * DESCRIPTION: Decodes Object Identifier. + * Parameters: + * asn1: pointer to ASN1 socket. + * oid: pointer to variable we set to Object Identifier. + * len: Length of Object Identifier in gulongs. + * nbytes: number of bytes used to encode. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_oid_decode ( ASN1_SCK *asn1, subid_t **oid, guint *len, guint *nbytes) +{ + int ret; + int start; + guint cls; + guint con; + guint tag; + gboolean def; + guint enc_len; + + start = asn1->offset; + ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len); + if (ret != ASN1_ERR_NOERROR) + goto done; + if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) { + ret = ASN1_ERR_WRONG_TYPE; + goto done; + } + if (!def) { + ret = ASN1_ERR_LENGTH_NOT_DEFINITE; + goto done; + } + + ret = asn1_oid_value_decode (asn1, enc_len, oid, len); + +done: + *nbytes = asn1->offset - start; + return ret; +} + +/* + * NAME: asn1_sequence_decode [API] + * SYNOPSIS: int asn1_sequence_decode + * ( + * ASN1_SCK *asn1, + * guint *seq_len, + * guint *nbytes + * ) + * DESCRIPTION: Decodes header for SEQUENCE. + * Parameters: + * asn1: pointer to ASN1 socket. + * seq_len: length of sequence. + * nbytes: number of bytes used to encode header. + * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) + */ +int +asn1_sequence_decode ( ASN1_SCK *asn1, guint *seq_len, guint *nbytes) +{ + int ret; + int start; + guint cls; + guint con; + guint tag; + gboolean def; + + start = asn1->offset; + ret = asn1_header_decode(asn1, &cls, &con, &tag, + &def, seq_len); + if (ret != ASN1_ERR_NOERROR) + goto done; + if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) { + ret = ASN1_ERR_WRONG_TYPE; + goto done; + } + if (!def) { + /* XXX - might some sequences have an indefinite length? */ + ret = ASN1_ERR_LENGTH_NOT_DEFINITE; + goto done; + } + ret = ASN1_ERR_NOERROR; + +done: + *nbytes = asn1->offset - start; + return ret; +} + +/* + * NAME: asn1_err_to_str [API] + * SYNOPSIS: char *asn1_err_to_str + * ( + * int err + * ) + * DESCRIPTION: Returns the string corresponding to an ASN.1 library error. + * Parameters: + * err: the error code + * RETURNS: string for the error + */ +char * +asn1_err_to_str(int err) +{ + char *errstr; + char errstrbuf[14+1+1+11+1+1]; /* "Unknown error (%d)\0" */ + + switch (err) { + + case ASN1_ERR_EOC_MISMATCH: + errstr = "EOC mismatch"; + break; + + case ASN1_ERR_WRONG_TYPE: + errstr = "Wrong type for that item"; + break; + + case ASN1_ERR_LENGTH_NOT_DEFINITE: + errstr = "Length was indefinite"; + break; + + case ASN1_ERR_LENGTH_MISMATCH: + errstr = "Length mismatch"; + break; + + case ASN1_ERR_WRONG_LENGTH_FOR_TYPE: + errstr = "Wrong length for that item's type"; + break; + + default: + snprintf(errstrbuf, sizeof errstrbuf, "Unknown error (%d)", err); + errstr = errstrbuf; + break; + } + return errstr; +} diff --git a/epan/asn1.h b/epan/asn1.h new file mode 100644 index 0000000000..5d751ff7fd --- /dev/null +++ b/epan/asn1.h @@ -0,0 +1,150 @@ +/* asn1.h + * Definitions for ASN.1 BER dissection + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * + * Based on "g_asn1.h" from: + * + * GXSNMP -- An snmp mangament application + * Copyright (C) 1998 Gregory McLean & Jochen Friedrich + * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __ASN1_H__ +#define __ASN1_H__ + +#define ASN1_UNI 0 /* Universal */ +#define ASN1_APL 1 /* Application */ +#define ASN1_CTX 2 /* Context */ +#define ASN1_PRV 3 /* Private */ + + /* Tag */ +#define ASN1_EOC 0 /* End Of Contents */ +#define ASN1_BOL 1 /* Boolean */ +#define ASN1_INT 2 /* Integer */ +#define ASN1_BTS 3 /* Bit String */ +#define ASN1_OTS 4 /* Octet String */ +#define ASN1_NUL 5 /* Null */ +#define ASN1_OJI 6 /* Object Identifier */ +#define ASN1_OJD 7 /* Object Description */ +#define ASN1_EXT 8 /* External */ +#define ASN1_REAL 9 /* Real */ +#define ASN1_ENUM 10 /* Enumerated */ +#define ASN1_SEQ 16 /* Sequence */ +#define ASN1_SET 17 /* Set */ +#define ASN1_NUMSTR 18 /* Numerical String */ +#define ASN1_PRNSTR 19 /* Printable String */ +#define ASN1_TEXSTR 20 /* Teletext String */ +#define ASN1_VIDSTR 21 /* Video String */ +#define ASN1_IA5STR 22 /* IA5 String */ +#define ASN1_UNITIM 23 /* Universal Time */ +#define ASN1_GENTIM 24 /* General Time */ +#define ASN1_GRASTR 25 /* Graphical String */ +#define ASN1_VISSTR 26 /* Visible String */ +#define ASN1_GENSTR 27 /* General String */ + + /* Primitive / Constructed */ +#define ASN1_PRI 0 /* Primitive */ +#define ASN1_CON 1 /* Constructed */ + +/* + * Oh, this is hellish. + * + * The CMU SNMP library defines an OID as a sequence of "u_int"s, + * unless EIGHTBIT_SUBIDS is defined, in which case it defines + * an OID as a sequence of "u_char"s. None of its header files + * define EIGHTBIT_SUBIDS, and if a program defines it, that's + * not going to change the library to treat OIDs as sequences + * of "u_chars", so I'll assume that it'll be "u_int"s. + * + * The UCD SNMP library does the same, except it defines an OID + * as a sequence of "u_long"s, by default. + * + * "libsmi" defines it as a sequence of "unsigned int"s. + * + * I don't want to oblige all users of ASN.1 to include the SNMP + * library header files, so I'll assume none of the SNMP libraries + * will rudely surprise me by changing the definition; if they + * do, there will be compiler warnings, so we'll at least be able + * to catch it. + * + * This requires that, if you're going to use "asn1_subid_decode()", + * "asn1_oid_value_decode()", or "asn1_oid_decode()", you include + * "config.h", to get the right #defines defined, so that we properly + * typedef "subid_t". + */ +#if defined(HAVE_SOME_SNMP) +typedef gulong subid_t; /* Net-SNMP or UCD SNMP */ +#else +typedef guint subid_t; /* CMU SNMP, libsmi, or nothing */ +#endif + +#define ASN1_ERR_NOERROR 0 /* no error */ +#define ASN1_ERR_EOC_MISMATCH 1 +#define ASN1_ERR_WRONG_TYPE 2 /* type not right */ +#define ASN1_ERR_LENGTH_NOT_DEFINITE 3 /* length should be definite */ +#define ASN1_ERR_LENGTH_MISMATCH 4 +#define ASN1_ERR_WRONG_LENGTH_FOR_TYPE 5 /* length wrong for type */ + +typedef struct _ASN1_SCK ASN1_SCK; + +struct _ASN1_SCK +{ /* ASN1 socket */ + tvbuff_t *tvb; /* Tvbuff whence the data comes */ + int offset; /* Current offset in tvbuff */ +}; + +extern void asn1_open (ASN1_SCK *asn1, tvbuff_t *tvb, int offset); +extern void asn1_close (ASN1_SCK *asn1, int *offset); +extern int asn1_octet_decode (ASN1_SCK *asn1, guchar *ch); +extern int asn1_tag_decode (ASN1_SCK *asn1, guint *tag); +extern int asn1_id_decode (ASN1_SCK *asn1, guint *cls, guint *con, guint *tag); +extern int asn1_id_decode1 (ASN1_SCK *asn1, guint *tag); +extern int asn1_length_decode (ASN1_SCK *asn1, gboolean *def, guint *len); +extern int asn1_header_decode(ASN1_SCK *asn1, guint *cls, guint *con, + guint *tag, gboolean *defp, guint *lenp); +extern int asn1_eoc (ASN1_SCK *asn1, int eoc); +extern int asn1_eoc_decode (ASN1_SCK *asn1, int eoc); +extern int asn1_null_decode (ASN1_SCK *asn1, int enc_len); +extern int asn1_bool_decode (ASN1_SCK *asn1, int enc_len, gboolean *boolean); +extern int asn1_int32_value_decode (ASN1_SCK *asn1, int enc_len, + gint32 *integer); +extern int asn1_int32_decode (ASN1_SCK *asn1, gint32 *integer, guint *nbytes); +extern int asn1_uint32_value_decode (ASN1_SCK *asn1, int enc_len, + guint32 *integer); +extern int asn1_uint32_decode (ASN1_SCK *asn1, guint32 *integer, guint *nbytes); +extern int asn1_bits_decode (ASN1_SCK *asn1, int enc_len, guchar **bits, + guint *len, guchar *unused); +extern int asn1_string_value_decode (ASN1_SCK *asn1, int enc_len, + guchar **octets); +extern int asn1_string_decode (ASN1_SCK *asn1, guchar **octets, guint *str_len, + guint *nbytes, guint expected_tag); +extern int asn1_octet_string_decode (ASN1_SCK *asn1, guchar **octets, + guint *str_len, guint *nbytes); +extern int asn1_subid_decode (ASN1_SCK *asn1, subid_t *subid); +extern int asn1_oid_value_decode (ASN1_SCK *asn1, int enc_len, subid_t **oid, + guint *len); +extern int asn1_oid_decode (ASN1_SCK *asn1, subid_t **oid, guint *len, + guint *nbytes); +extern int asn1_sequence_decode (ASN1_SCK *asn1, guint *seq_len, guint *nbytes); + +extern char *asn1_err_to_str (int err); + +#endif diff --git a/epan/dissectors/ncp2222.py b/epan/dissectors/ncp2222.py index b341510745..5e156ccf62 100755 --- a/epan/dissectors/ncp2222.py +++ b/epan/dissectors/ncp2222.py @@ -5559,7 +5559,7 @@ def produce_code(): #include #include #include -#include "ptvcursor.h" +#include #include "packet-ncp-int.h" #include "packet-ncp-nmas.h" #include diff --git a/epan/dissectors/packet-acse.c b/epan/dissectors/packet-acse.c index 1ba1eb52ea..778c6f2695 100644 --- a/epan/dissectors/packet-acse.c +++ b/epan/dissectors/packet-acse.c @@ -41,7 +41,7 @@ #include -#include "asn1.h" +#include #include "format-oid.h" #include "packet-ses.h" diff --git a/epan/dissectors/packet-ansi_map.c b/epan/dissectors/packet-ansi_map.c index ad5928a32e..3b9dd942f1 100644 --- a/epan/dissectors/packet-ansi_map.c +++ b/epan/dissectors/packet-ansi_map.c @@ -110,7 +110,7 @@ #include #include "epan/packet.h" -#include "asn1.h" +#include #include #include "packet-ansi_a.h" diff --git a/epan/dissectors/packet-atalk.c b/epan/dissectors/packet-atalk.c index 3204e7e79a..7f48b4e346 100644 --- a/epan/dissectors/packet-atalk.c +++ b/epan/dissectors/packet-atalk.c @@ -41,7 +41,7 @@ #include #include -#include "reassemble.h" +#include #include "packet-afp.h" diff --git a/epan/dissectors/packet-clnp.c b/epan/dissectors/packet-clnp.c index e1dbb4a3e7..95da85266f 100644 --- a/epan/dissectors/packet-clnp.c +++ b/epan/dissectors/packet-clnp.c @@ -33,7 +33,7 @@ #include #include #include -#include "reassemble.h" +#include #include "packet-osi.h" #include "packet-osi-options.h" #include "packet-isis.h" diff --git a/epan/dissectors/packet-cops.c b/epan/dissectors/packet-cops.c index f69dc05a59..5b42d14293 100644 --- a/epan/dissectors/packet-cops.c +++ b/epan/dissectors/packet-cops.c @@ -84,7 +84,7 @@ #endif /* HAVE_NET_SNMP */ #endif /* HAVE_SOME_SNMP */ -#include "asn1.h" +#include #include "format-oid.h" #include diff --git a/epan/dissectors/packet-dcerpc.c b/epan/dissectors/packet-dcerpc.c index 0dde4abb9f..4c762c6826 100644 --- a/epan/dissectors/packet-dcerpc.c +++ b/epan/dissectors/packet-dcerpc.c @@ -40,7 +40,7 @@ #include #include #include -#include "reassemble.h" +#include #include #include #include diff --git a/epan/dissectors/packet-diameter.c b/epan/dissectors/packet-diameter.c index 1c7d096c60..1a33176b5a 100644 --- a/epan/dissectors/packet-diameter.c +++ b/epan/dissectors/packet-diameter.c @@ -48,7 +48,7 @@ #include #include #include -#include "xmlstub.h" +#include #include #include #include diff --git a/epan/dissectors/packet-dnp.c b/epan/dissectors/packet-dnp.c index 1c69ff1f35..7d3dda725d 100644 --- a/epan/dissectors/packet-dnp.c +++ b/epan/dissectors/packet-dnp.c @@ -40,7 +40,7 @@ #include #include -#include "reassemble.h" +#include /* * See diff --git a/epan/dissectors/packet-eap.c b/epan/dissectors/packet-eap.c index 72389f65b9..570a212400 100644 --- a/epan/dissectors/packet-eap.c +++ b/epan/dissectors/packet-eap.c @@ -31,7 +31,7 @@ #include #include #include "ppptypes.h" -#include "reassemble.h" +#include static int proto_eap = -1; static int hf_eap_code = -1; diff --git a/epan/dissectors/packet-fc.c b/epan/dissectors/packet-fc.c index 73acfb07e2..85810905d4 100644 --- a/epan/dissectors/packet-fc.c +++ b/epan/dissectors/packet-fc.c @@ -50,7 +50,7 @@ #include #include -#include "reassemble.h" +#include #include #include "etypes.h" #include "packet-fc.h" diff --git a/epan/dissectors/packet-ftam.c b/epan/dissectors/packet-ftam.c index ebec9ad767..90eaa400eb 100644 --- a/epan/dissectors/packet-ftam.c +++ b/epan/dissectors/packet-ftam.c @@ -42,7 +42,7 @@ #include -#include "asn1.h" +#include #include "format-oid.h" #include "packet-ses.h" diff --git a/epan/dissectors/packet-gsm_a.c b/epan/dissectors/packet-gsm_a.c index a5c7428026..8b93c4e6ae 100644 --- a/epan/dissectors/packet-gsm_a.c +++ b/epan/dissectors/packet-gsm_a.c @@ -84,7 +84,7 @@ #include #include #include -#include "asn1.h" +#include #include "packet-tcap.h" #include "packet-bssap.h" diff --git a/epan/dissectors/packet-gsm_sms_ud.c b/epan/dissectors/packet-gsm_sms_ud.c index 542207d213..005cae0a11 100644 --- a/epan/dissectors/packet-gsm_sms_ud.c +++ b/epan/dissectors/packet-gsm_sms_ud.c @@ -70,7 +70,7 @@ #include #include -#include "reassemble.h" +#include static void dissect_gsm_sms_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); diff --git a/epan/dissectors/packet-gsm_ss.c b/epan/dissectors/packet-gsm_ss.c index 2be9f7aef5..f91bf761d1 100644 --- a/epan/dissectors/packet-gsm_ss.c +++ b/epan/dissectors/packet-gsm_ss.c @@ -56,7 +56,7 @@ #include "epan/packet.h" #include -#include "asn1.h" +#include #include "packet-tcap.h" #include "packet-gsm_sms.h" diff --git a/epan/dissectors/packet-gssapi.c b/epan/dissectors/packet-gssapi.c index 5356ba024c..ac3ad4bb95 100644 --- a/epan/dissectors/packet-gssapi.c +++ b/epan/dissectors/packet-gssapi.c @@ -38,7 +38,7 @@ #include #include -#include "asn1.h" +#include #include "format-oid.h" #include #include diff --git a/epan/dissectors/packet-ieee80211.c b/epan/dissectors/packet-ieee80211.c index 5805a4f720..330d1338b1 100644 --- a/epan/dissectors/packet-ieee80211.c +++ b/epan/dissectors/packet-ieee80211.c @@ -62,7 +62,7 @@ #include #include #include -#include "reassemble.h" +#include #include "packet-ipx.h" #include "packet-llc.h" #include "packet-ieee80211.h" diff --git a/epan/dissectors/packet-inap.c b/epan/dissectors/packet-inap.c index b062dd0800..8c5bfb3814 100644 --- a/epan/dissectors/packet-inap.c +++ b/epan/dissectors/packet-inap.c @@ -11,7 +11,7 @@ * Copyright 2004, Tim Endean * Built from the gsm-map dissector Copyright 2004, Anders Broman * - * $Id:$ + * $Id$ * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs diff --git a/epan/dissectors/packet-ip.c b/epan/dissectors/packet-ip.c index 646a822a9d..7e5f6e8a43 100644 --- a/epan/dissectors/packet-ip.c +++ b/epan/dissectors/packet-ip.c @@ -39,7 +39,7 @@ #include #include "ip_opts.h" #include -#include "reassemble.h" +#include #include "etypes.h" #include "greproto.h" #include "ppptypes.h" diff --git a/epan/dissectors/packet-ipv6.c b/epan/dissectors/packet-ipv6.c index dce5de93fb..9b4bf99e0c 100644 --- a/epan/dissectors/packet-ipv6.c +++ b/epan/dissectors/packet-ipv6.c @@ -37,7 +37,7 @@ #include "ip_opts.h" #include #include -#include "reassemble.h" +#include #include #include "etypes.h" #include "ppptypes.h" diff --git a/epan/dissectors/packet-kerberos.c b/epan/dissectors/packet-kerberos.c index afa3dfe7d4..bab8577bd7 100644 --- a/epan/dissectors/packet-kerberos.c +++ b/epan/dissectors/packet-kerberos.c @@ -94,7 +94,7 @@ #include #include -#include "asn1.h" /* for "subid_t" */ +#include /* for "subid_t" */ #include #define UDP_PORT_KERBEROS 88 diff --git a/epan/dissectors/packet-ldap.c b/epan/dissectors/packet-ldap.c index 19eb208d18..5ffd40d666 100644 --- a/epan/dissectors/packet-ldap.c +++ b/epan/dissectors/packet-ldap.c @@ -79,7 +79,7 @@ #include -#include "asn1.h" +#include #include #include #include "packet-frame.h" diff --git a/epan/dissectors/packet-lwapp.c b/epan/dissectors/packet-lwapp.c index cdba063454..b3aa845a76 100644 --- a/epan/dissectors/packet-lwapp.c +++ b/epan/dissectors/packet-lwapp.c @@ -37,7 +37,7 @@ #include #include #include -#include "xmlstub.h" +#include #include #include #include diff --git a/epan/dissectors/packet-mq.c b/epan/dissectors/packet-mq.c index fdea9d0121..a1f7aabe64 100644 --- a/epan/dissectors/packet-mq.c +++ b/epan/dissectors/packet-mq.c @@ -71,7 +71,7 @@ #include #include #include -#include "reassemble.h" +#include #include #include "packet-tcp.h" #include "packet-mq.h" diff --git a/epan/dissectors/packet-mysql.c b/epan/dissectors/packet-mysql.c index 73f45389bf..46fb2f74ef 100644 --- a/epan/dissectors/packet-mysql.c +++ b/epan/dissectors/packet-mysql.c @@ -40,7 +40,7 @@ #include #include "packet-tcp.h" -#include "reassemble.h" +#include #include /* Capabilities */ diff --git a/epan/dissectors/packet-ncp.c b/epan/dissectors/packet-ncp.c index e3d453b9fd..7d4035a65d 100644 --- a/epan/dissectors/packet-ncp.c +++ b/epan/dissectors/packet-ncp.c @@ -49,7 +49,7 @@ #include "packet-ipx.h" #include "packet-tcp.h" #include "packet-ncp-int.h" -#include "reassemble.h" +#include #include int proto_ncp = -1; diff --git a/epan/dissectors/packet-ndmp.c b/epan/dissectors/packet-ndmp.c index 535b9d11ec..002178d56b 100644 --- a/epan/dissectors/packet-ndmp.c +++ b/epan/dissectors/packet-ndmp.c @@ -42,7 +42,7 @@ #include "packet-scsi.h" #include "packet-frame.h" #include -#include "reassemble.h" +#include #include "rpc_defrag.h" #define TCP_PORT_NDMP 10000 diff --git a/epan/dissectors/packet-ndps.c b/epan/dissectors/packet-ndps.c index a35961ebbf..6ea84aba9b 100644 --- a/epan/dissectors/packet-ndps.c +++ b/epan/dissectors/packet-ndps.c @@ -36,7 +36,7 @@ #include "packet-tcp.h" #include #include "packet-ndps.h" -#include "reassemble.h" +#include #define NDPS_PACKET_INIT_COUNT 200 diff --git a/epan/dissectors/packet-netbios.c b/epan/dissectors/packet-netbios.c index 364ca9faa5..1d3b29289f 100644 --- a/epan/dissectors/packet-netbios.c +++ b/epan/dissectors/packet-netbios.c @@ -36,7 +36,7 @@ #include #include "llcsaps.h" -#include "reassemble.h" +#include #include #include "packet-netbios.h" diff --git a/epan/dissectors/packet-ntlmssp.c b/epan/dissectors/packet-ntlmssp.c index 1b5790c412..707e90c4ff 100644 --- a/epan/dissectors/packet-ntlmssp.c +++ b/epan/dissectors/packet-ntlmssp.c @@ -36,7 +36,7 @@ #include "packet-windows-common.h" #include "packet-smb-common.h" -#include "asn1.h" /* XXX - needed for subid_t */ +#include /* XXX - needed for subid_t */ #include "packet-gssapi.h" #include "packet-frame.h" #include diff --git a/epan/dissectors/packet-pgsql.c b/epan/dissectors/packet-pgsql.c index ee3727e291..34371d0a10 100644 --- a/epan/dissectors/packet-pgsql.c +++ b/epan/dissectors/packet-pgsql.c @@ -34,7 +34,7 @@ #include #include "packet-tcp.h" -#include "reassemble.h" +#include static int proto_pgsql = -1; diff --git a/epan/dissectors/packet-pres.c b/epan/dissectors/packet-pres.c index b692101ae7..b988fb9b97 100644 --- a/epan/dissectors/packet-pres.c +++ b/epan/dissectors/packet-pres.c @@ -41,7 +41,7 @@ #include -#include "asn1.h" +#include #include "format-oid.h" #include "packet-ses.h" diff --git a/epan/dissectors/packet-q931.c b/epan/dissectors/packet-q931.c index 4e2f40000b..96189169cf 100644 --- a/epan/dissectors/packet-q931.c +++ b/epan/dissectors/packet-q931.c @@ -39,7 +39,7 @@ #include "packet-q931.h" #include "packet-e164.h" #include -#include "reassemble.h" +#include #include "lapd_sapi.h" #include "packet-tpkt.h" diff --git a/epan/dissectors/packet-rpc.c b/epan/dissectors/packet-rpc.c index c6c56d0d50..933561b36d 100644 --- a/epan/dissectors/packet-rpc.c +++ b/epan/dissectors/packet-rpc.c @@ -39,7 +39,7 @@ #include "packet-frame.h" #include "packet-tcp.h" #include -#include "reassemble.h" +#include #include "rpc_defrag.h" #include "packet-nfs.h" #include diff --git a/epan/dissectors/packet-smb-pipe.c b/epan/dissectors/packet-smb-pipe.c index e2bb58e518..8d7ca90ee3 100644 --- a/epan/dissectors/packet-smb-pipe.c +++ b/epan/dissectors/packet-smb-pipe.c @@ -48,7 +48,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets #include "packet-smb-common.h" #include "packet-windows-common.h" #include "packet-dcerpc.h" -#include "reassemble.h" +#include static int proto_smb_pipe = -1; static int hf_pipe_function = -1; diff --git a/epan/dissectors/packet-smb.c b/epan/dissectors/packet-smb.c index a9e60e1d49..d2ea3ab4b2 100644 --- a/epan/dissectors/packet-smb.c +++ b/epan/dissectors/packet-smb.c @@ -41,7 +41,7 @@ #include "smb.h" #include #include -#include "reassemble.h" +#include #include #include "packet-ipx.h" diff --git a/epan/dissectors/packet-sna.c b/epan/dissectors/packet-sna.c index 9fc9603edb..70e8ef4337 100644 --- a/epan/dissectors/packet-sna.c +++ b/epan/dissectors/packet-sna.c @@ -35,7 +35,7 @@ #include #include #include -#include "reassemble.h" +#include /* * http://www.wanresources.com/snacell.html diff --git a/epan/dissectors/packet-sndcp.c b/epan/dissectors/packet-sndcp.c index b6123b3310..f46da753d7 100644 --- a/epan/dissectors/packet-sndcp.c +++ b/epan/dissectors/packet-sndcp.c @@ -38,7 +38,7 @@ #endif #include -#include "reassemble.h" +#include /* Bitmasks for the bits in the address field */ diff --git a/epan/dissectors/packet-snmp.c b/epan/dissectors/packet-snmp.c index e63a930abd..18c2fcc753 100644 --- a/epan/dissectors/packet-snmp.c +++ b/epan/dissectors/packet-snmp.c @@ -105,7 +105,7 @@ #endif /* HAVE_SOME_SNMP */ -#include "asn1.h" +#include #include "packet-snmp.h" #include "format-oid.h" diff --git a/epan/dissectors/packet-spnego.c b/epan/dissectors/packet-spnego.c index 28255daa0c..6ad56b9656 100644 --- a/epan/dissectors/packet-spnego.c +++ b/epan/dissectors/packet-spnego.c @@ -37,7 +37,7 @@ #include #include -#include "asn1.h" +#include #include "format-oid.h" #include "packet-gssapi.h" #include "packet-kerberos.h" diff --git a/epan/dissectors/packet-srvloc.c b/epan/dissectors/packet-srvloc.c index 7a5a0c1b62..5105f36da1 100644 --- a/epan/dissectors/packet-srvloc.c +++ b/epan/dissectors/packet-srvloc.c @@ -49,7 +49,7 @@ #include #include #include "packet-tcp.h" -#include "reassemble.h" +#include static gboolean srvloc_desegment = TRUE; static int proto_srvloc = -1; diff --git a/epan/dissectors/packet-ssh.c b/epan/dissectors/packet-ssh.c index 9de167baa0..d6cc21821b 100644 --- a/epan/dissectors/packet-ssh.c +++ b/epan/dissectors/packet-ssh.c @@ -39,7 +39,7 @@ #include #include "packet-tcp.h" -#include "reassemble.h" +#include #include /* get from openssh ssh2.h */ diff --git a/epan/dissectors/packet-tcap.c b/epan/dissectors/packet-tcap.c index ce8865d7b6..1c8bf2f178 100644 --- a/epan/dissectors/packet-tcap.c +++ b/epan/dissectors/packet-tcap.c @@ -61,7 +61,7 @@ #include #include -#include "asn1.h" +#include #include "packet-tcap.h" #include "packet-ber.h" diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c index b7065674ed..c64d74d691 100644 --- a/epan/dissectors/packet-tcp.c +++ b/epan/dissectors/packet-tcp.c @@ -35,14 +35,14 @@ #include #include #include "ip_opts.h" -#include "follow.h" +#include #include #include "packet-tcp.h" #include "packet-ip.h" #include "packet-frame.h" #include #include -#include "reassemble.h" +#include #include static int tcp_tap = -1; diff --git a/epan/dissectors/packet-tds.c b/epan/dissectors/packet-tds.c index 7cb1124d26..511eeba062 100644 --- a/epan/dissectors/packet-tds.c +++ b/epan/dissectors/packet-tds.c @@ -157,7 +157,7 @@ #include #include "packet-frame.h" -#include "reassemble.h" +#include #include #define TDS_QUERY_PKT 1 diff --git a/epan/dissectors/packet-wtp.c b/epan/dissectors/packet-wtp.c index f9082b2780..36649ead4c 100644 --- a/epan/dissectors/packet-wtp.c +++ b/epan/dissectors/packet-wtp.c @@ -41,7 +41,7 @@ #include #include #include -#include "reassemble.h" +#include #include "packet-wap.h" #include "packet-wtp.h" #include "packet-wsp.h" diff --git a/epan/dissectors/packet-x25.c b/epan/dissectors/packet-x25.c index b7f2d4d69f..aba61af789 100644 --- a/epan/dissectors/packet-x25.c +++ b/epan/dissectors/packet-x25.c @@ -34,7 +34,7 @@ #include "llcsaps.h" #include #include -#include "reassemble.h" +#include #include #include "nlpid.h" #include "x264_prt_id.h" diff --git a/epan/follow.c b/epan/follow.c new file mode 100644 index 0000000000..19e14303b2 --- /dev/null +++ b/epan/follow.c @@ -0,0 +1,336 @@ +/* follow.c + * + * $Id$ + * + * Copyright 1998 Mike Hall + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include "follow.h" + +#define MAX_IPADDR_LEN 16 + +typedef struct _tcp_frag { + gulong seq; + gulong len; + gulong data_len; + gchar *data; + struct _tcp_frag *next; +} tcp_frag; + +FILE* data_out_file = NULL; + +gboolean incomplete_tcp_stream = FALSE; + +static guint8 ip_address[2][MAX_IPADDR_LEN]; +static guint tcp_port[2]; +static guint bytes_written[2]; +static gboolean is_ipv6 = FALSE; + +static int check_fragments( int, tcp_stream_chunk * ); +static void write_packet_data( int, tcp_stream_chunk *, const char * ); + +void +follow_tcp_stats(follow_tcp_stats_t* stats) +{ + int i; + + for (i = 0; i < 2 ; i++) { + memcpy(stats->ip_address[i], ip_address[i], MAX_IPADDR_LEN); + stats->tcp_port[i] = tcp_port[i]; + stats->bytes_written[i] = bytes_written[i]; + stats->is_ipv6 = is_ipv6; + } +} + +/* this will build libpcap filter text that will only + pass the packets related to the stream. There is a + chance that two streams could intersect, but not a + very good one */ +char* +build_follow_filter( packet_info *pi ) { + char* buf = g_malloc(1024); + int len; + if( pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4 + && pi->ipproto == 6 ) { + /* TCP over IPv4 */ + sprintf( buf, + "(ip.addr eq %s and ip.addr eq %s) and (tcp.port eq %d and tcp.port eq %d)", + ip_to_str( pi->net_src.data), + ip_to_str( pi->net_dst.data), + pi->srcport, pi->destport ); + len = 4; + is_ipv6 = FALSE; + } + else if( pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6 + && pi->ipproto == 6 ) { + /* TCP over IPv6 */ + sprintf( buf, + "(ipv6.addr eq %s and ipv6.addr eq %s) and (tcp.port eq %d and tcp.port eq %d)", + ip6_to_str((const struct e_in6_addr *)pi->net_src.data), + ip6_to_str((const struct e_in6_addr *)pi->net_dst.data), + pi->srcport, pi->destport ); + len = 16; + is_ipv6 = TRUE; + } + else { + g_free( buf ); + return NULL; + } + memcpy(ip_address[0], pi->net_src.data, len); + memcpy(ip_address[1], pi->net_dst.data, len); + tcp_port[0] = pi->srcport; + tcp_port[1] = pi->destport; + return buf; +} + +/* here we are going to try and reconstruct the data portion of a TCP + session. We will try and handle duplicates, TCP fragments, and out + of order packets in a smart way. */ + +static tcp_frag *frags[2] = { 0, 0 }; +static gulong seq[2]; +static guint8 src_addr[2][MAX_IPADDR_LEN]; +static guint src_port[2] = { 0, 0 }; + +void +reassemble_tcp( gulong sequence, gulong length, const char* data, + gulong data_length, int synflag, address *net_src, + address *net_dst, guint srcport, guint dstport) { + guint8 srcx[MAX_IPADDR_LEN], dstx[MAX_IPADDR_LEN]; + int src_index, j, first = 0, len; + gulong newseq; + tcp_frag *tmp_frag; + tcp_stream_chunk sc; + + src_index = -1; + + /* First, check if this packet should be processed. */ + + if ((net_src->type != AT_IPv4 && net_src->type != AT_IPv6) || + (net_dst->type != AT_IPv4 && net_dst->type != AT_IPv6)) + return; + + if (net_src->type == AT_IPv4) + len = 4; + else + len = 16; + + /* Now check if the packet is for this connection. */ + memcpy(srcx, net_src->data, len); + memcpy(dstx, net_dst->data, len); + if ( + ! ( + memcmp(srcx, ip_address[0], len) == 0 && + memcmp(dstx, ip_address[1], len) == 0 && + srcport == tcp_port[0] && + dstport == tcp_port[1] + ) && + ! ( + memcmp(srcx, ip_address[1], len) == 0 && + memcmp(dstx, ip_address[0], len) == 0 && + srcport == tcp_port[1] && + dstport == tcp_port[0] + ) + ) + return; + + /* Initialize our stream chunk. This data gets written to disk. */ + memcpy(sc.src_addr, srcx, len); + sc.src_port = srcport; + sc.dlen = data_length; + + /* Check to see if we have seen this source IP and port before. + (Yes, we have to check both source IP and port; the connection + might be between two different ports on the same machine.) */ + for( j=0; j<2; j++ ) { + if (memcmp(src_addr[j], srcx, len) == 0 && src_port[j] == srcport ) { + src_index = j; + } + } + /* we didn't find it if src_index == -1 */ + if( src_index < 0 ) { + /* assign it to a src_index and get going */ + for( j=0; j<2; j++ ) { + if( src_port[j] == 0 ) { + memcpy(src_addr[j], srcx, len); + src_port[j] = srcport; + src_index = j; + first = 1; + break; + } + } + } + if( src_index < 0 ) { + fprintf( stderr, "ERROR in reassemble_tcp: Too many addresses!\n"); + return; + } + + if( data_length < length ) { + incomplete_tcp_stream = TRUE; + } + + /* now that we have filed away the srcs, lets get the sequence number stuff + figured out */ + if( first ) { + /* this is the first time we have seen this src's sequence number */ + seq[src_index] = sequence + length; + if( synflag ) { + seq[src_index]++; + } + /* write out the packet data */ + write_packet_data( src_index, &sc, data ); + return; + } + /* if we are here, we have already seen this src, let's + try and figure out if this packet is in the right place */ + if( sequence < seq[src_index] ) { + /* this sequence number seems dated, but + check the end to make sure it has no more + info than we have already seen */ + newseq = sequence + length; + if( newseq > seq[src_index] ) { + gulong new_len; + + /* this one has more than we have seen. let's get the + payload that we have not seen. */ + + new_len = seq[src_index] - sequence; + + if ( data_length <= new_len ) { + data = NULL; + data_length = 0; + incomplete_tcp_stream = TRUE; + } else { + data += new_len; + data_length -= new_len; + } + sc.dlen = data_length; + sequence = seq[src_index]; + length = newseq - seq[src_index]; + + /* this will now appear to be right on time :) */ + } + } + if ( sequence == seq[src_index] ) { + /* right on time */ + seq[src_index] += length; + if( synflag ) seq[src_index]++; + if( data ) { + write_packet_data( src_index, &sc, data ); + } + /* done with the packet, see if it caused a fragment to fit */ + while( check_fragments( src_index, &sc ) ) + ; + } + else { + /* out of order packet */ + if(data_length > 0 && sequence > seq[src_index] ) { + tmp_frag = (tcp_frag *)malloc( sizeof( tcp_frag ) ); + tmp_frag->data = (guchar *)malloc( data_length ); + tmp_frag->seq = sequence; + tmp_frag->len = length; + tmp_frag->data_len = data_length; + memcpy( tmp_frag->data, data, data_length ); + if( frags[src_index] ) { + tmp_frag->next = frags[src_index]; + } else { + tmp_frag->next = NULL; + } + frags[src_index] = tmp_frag; + } + } +} /* end reassemble_tcp */ + +/* here we search through all the frag we have collected to see if + one fits */ +static int +check_fragments( int index, tcp_stream_chunk *sc ) { + tcp_frag *prev = NULL; + tcp_frag *current; + current = frags[index]; + while( current ) { + if( current->seq == seq[index] ) { + /* this fragment fits the stream */ + if( current->data ) { + sc->dlen = current->data_len; + write_packet_data( index, sc, current->data ); + } + seq[index] += current->len; + if( prev ) { + prev->next = current->next; + } else { + frags[index] = current->next; + } + free( current->data ); + free( current ); + return 1; + } + prev = current; + current = current->next; + } + return 0; +} + +/* this should always be called before we start to reassemble a stream */ +void +reset_tcp_reassembly() { + tcp_frag *current, *next; + int i; + incomplete_tcp_stream = FALSE; + for( i=0; i<2; i++ ) { + seq[i] = 0; + memset(src_addr[i], '\0', MAX_IPADDR_LEN); + src_port[i] = 0; + memset(ip_address[i], '\0', MAX_IPADDR_LEN); + tcp_port[i] = 0; + bytes_written[i] = 0; + current = frags[i]; + while( current ) { + next = current->next; + free( current->data ); + free( current ); + current = next; + } + frags[i] = NULL; + } +} + +static void +write_packet_data( int index, tcp_stream_chunk *sc, const char *data ) +{ + fwrite( sc, 1, sizeof(tcp_stream_chunk), data_out_file ); + fwrite( data, 1, sc->dlen, data_out_file ); + bytes_written[index] += sc->dlen; +} diff --git a/epan/follow.h b/epan/follow.h new file mode 100644 index 0000000000..013519d43e --- /dev/null +++ b/epan/follow.h @@ -0,0 +1,57 @@ +/* follow.h + * + * $Id$ + * + * Copyright 1998 Mike Hall + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __FOLLOW_H__ +#define __FOLLOW_H__ + +#include + +#define MAX_IPADDR_LEN 16 + +/* With MSVC and a libethereal.dll, we need a special declaration. */ +ETH_VAR_IMPORT gboolean incomplete_tcp_stream; + +typedef struct _tcp_stream_chunk { + guint8 src_addr[MAX_IPADDR_LEN]; + guint16 src_port; + guint32 dlen; +} tcp_stream_chunk; + +char* build_follow_filter( packet_info * ); +void reassemble_tcp( gulong, gulong, const char*, gulong, int, + address *, address *, guint, guint ); +void reset_tcp_reassembly( void ); + +typedef struct { + guint8 ip_address[2][MAX_IPADDR_LEN]; + guint32 tcp_port[2]; + unsigned int bytes_written[2]; + gboolean is_ipv6; +} follow_tcp_stats_t; + +void follow_tcp_stats(follow_tcp_stats_t* stats); + +#endif diff --git a/epan/packet.c b/epan/packet.c index 671eacbef7..b7528983c1 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -53,7 +53,7 @@ #include "plugins.h" #include "epan_dissect.h" -#include "../reassemble.h" +#include static gint proto_malformed = -1; static dissector_handle_t frame_handle = NULL; diff --git a/epan/plugins.c b/epan/plugins.c index 72a41e8853..b880fe7963 100644 --- a/epan/plugins.c +++ b/epan/plugins.c @@ -60,14 +60,14 @@ #ifdef PLUGINS_NEED_ADDRESS_TABLE #include "conversation.h" -#include "reassemble.h" +#include #include #include #include #include #include #include -#include "asn1.h" +#include #include #include #include diff --git a/epan/ptvcursor.c b/epan/ptvcursor.c new file mode 100644 index 0000000000..cde56022f0 --- /dev/null +++ b/epan/ptvcursor.c @@ -0,0 +1,116 @@ +/* ptvcursor.c + * + * Proto Tree TVBuff cursor + * Gilbert Ramirez + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ptvcursor.h" + + +struct ptvcursor { + proto_tree *tree; + tvbuff_t *tvb; + gint offset; +}; + + +/* Allocates an initializes a ptvcursor_t with 3 variables: + * proto_tree, tvbuff, and offset. */ +ptvcursor_t* +ptvcursor_new(proto_tree *tree, tvbuff_t *tvb, gint offset) +{ + ptvcursor_t *ptvc; + + ptvc = g_new(ptvcursor_t, 1); + ptvc->tree = tree; + ptvc->tvb = tvb; + ptvc->offset = offset; + return ptvc; +} + + +/* Gets data from tvbuff, adds it to proto_tree, increments offset, + * and returns proto_item* */ +proto_item* +ptvcursor_add(ptvcursor_t *ptvc, int hf, gint length, gboolean endianness) +{ + proto_item *item; + + item = ptvcursor_add_no_advance(ptvc, hf, length, endianness); + ptvc->offset += proto_item_get_len(item); + return item; +} + +/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment + * offset, and returns proto_item* */ +proto_item* +ptvcursor_add_no_advance(ptvcursor_t* ptvc, int hf, gint length, + gboolean endianness) +{ + proto_item *item; + + item = proto_tree_add_item(ptvc->tree, hf, ptvc->tvb, ptvc->offset, + length, endianness); + + return item; +} + +/* Advance the ptvcursor's offset within its tvbuff without + * adding anything to the proto_tree. */ +void +ptvcursor_advance(ptvcursor_t* ptvc, gint length) +{ + ptvc->offset += length; +} + +/* Frees memory for ptvcursor_t, but nothing deeper than that. */ +void +ptvcursor_free(ptvcursor_t *ptvc) +{ + g_free(ptvc); +} +/* Returns tvbuff. */ +tvbuff_t* +ptvcursor_tvbuff(ptvcursor_t* ptvc) +{ + return ptvc->tvb; +} + +/* Returns current offset. */ +gint +ptvcursor_current_offset(ptvcursor_t* ptvc) +{ + return ptvc->offset; +} + +proto_tree* +ptvcursor_tree(ptvcursor_t* ptvc) +{ + return ptvc->tree; +} + +void +ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree) +{ + ptvc->tree = tree; +} diff --git a/epan/ptvcursor.h b/epan/ptvcursor.h new file mode 100644 index 0000000000..6467bcdea9 --- /dev/null +++ b/epan/ptvcursor.h @@ -0,0 +1,80 @@ +/* ptvcursor.h + * + * Proto Tree TVBuff cursor + * Gilbert Ramirez + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 2000 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PTVCURSOR_H__ +#define __PTVCURSOR_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +typedef struct ptvcursor ptvcursor_t; + +/* Allocates an initializes a ptvcursor_t with 3 variables: + * proto_tree, tvbuff, and offset. */ +ptvcursor_t* +ptvcursor_new(proto_tree*, tvbuff_t*, gint); + +/* Gets data from tvbuff, adds it to proto_tree, increments offset, + * and returns proto_item* */ +proto_item* +ptvcursor_add(ptvcursor_t*, int hf, gint length, gboolean endianness); + + +/* Gets data from tvbuff, adds it to proto_tree, *DOES NOT* increment + * offset, and returns proto_item* */ +proto_item* +ptvcursor_add_no_advance(ptvcursor_t*, int hf, gint length, gboolean endianness); + +/* Advance the ptvcursor's offset within its tvbuff without + * adding anything to the proto_tree. */ +void +ptvcursor_advance(ptvcursor_t* ptvc, gint length); + +/* Frees memory for ptvcursor_t, but nothing deeper than that. */ +void +ptvcursor_free(ptvcursor_t*); + +/* Returns tvbuff. */ +tvbuff_t* +ptvcursor_tvbuff(ptvcursor_t*); + +/* Returns current offset. */ +gint +ptvcursor_current_offset(ptvcursor_t*); + +/* Returns the proto_tree* */ +proto_tree* +ptvcursor_tree(ptvcursor_t* ptvc); + +/* Sets a new proto_tree* for the ptvcursor_t */ +void +ptvcursor_set_tree(ptvcursor_t* ptvc, proto_tree *tree); + +#endif /* __PTVCURSOR_H__ */ diff --git a/epan/reassemble.c b/epan/reassemble.c new file mode 100644 index 0000000000..9622d390e2 --- /dev/null +++ b/epan/reassemble.c @@ -0,0 +1,1833 @@ +/* reassemble.c + * Routines for {fragment,segment} reassembly + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include + +#include + +typedef struct _fragment_key { + address src; + address dst; + guint32 id; +} fragment_key; + +typedef struct _dcerpc_fragment_key { + address src; + address dst; + guint32 id; + e_uuid_t act_id; +} dcerpc_fragment_key; + +static GMemChunk *fragment_key_chunk = NULL; +static GMemChunk *dcerpc_fragment_key_chunk = NULL; +static GMemChunk *fragment_data_chunk = NULL; +static int fragment_init_count = 200; + +#define LINK_FRAG(fd_head,fd) \ + { fragment_data *fd_i; \ + /* add fragment to list, keep list sorted */ \ + for(fd_i=(fd_head);fd_i->next;fd_i=fd_i->next){ \ + if( ((fd)->offset) < (fd_i->next->offset) ) \ + break; \ + } \ + (fd)->next=fd_i->next; \ + fd_i->next=(fd); \ + } + +static gint +fragment_equal(gconstpointer k1, gconstpointer k2) +{ + const fragment_key* key1 = (const fragment_key*) k1; + const fragment_key* key2 = (const fragment_key*) k2; + + /*key.id is the first item to compare since item is most + likely to differ between sessions, thus shortcircuiting + the comparasion of addresses. + */ + return ( ( (key1->id == key2->id) && + (ADDRESSES_EQUAL(&key1->src, &key2->src)) && + (ADDRESSES_EQUAL(&key1->dst, &key2->dst)) + ) ? + TRUE : FALSE); +} + +static guint +fragment_hash(gconstpointer k) +{ + const fragment_key* key = (const fragment_key*) k; + guint hash_val; +/* + int i; +*/ + + hash_val = 0; + +/* More than likely: in most captures src and dst addresses are the + same, and would hash the same. + We only use id as the hash as an optimization. + + for (i = 0; i < key->src.len; i++) + hash_val += key->src.data[i]; + for (i = 0; i < key->dst.len; i++) + hash_val += key->dst.data[i]; +*/ + + hash_val += key->id; + + return hash_val; +} + +static gint +dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2) +{ + const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1; + const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2; + + /*key.id is the first item to compare since item is most + likely to differ between sessions, thus shortcircuiting + the comparasion of addresses. + */ + return (((key1->id == key2->id) + && (ADDRESSES_EQUAL(&key1->src, &key2->src)) + && (ADDRESSES_EQUAL(&key1->dst, &key2->dst)) + && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)) + ? TRUE : FALSE); +} + +static guint +dcerpc_fragment_hash(gconstpointer k) +{ + const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k; + guint hash_val; + + hash_val = 0; + + hash_val += key->id; + hash_val += key->act_id.Data1; + hash_val += key->act_id.Data2 << 16; + hash_val += key->act_id.Data3; + + return hash_val; +} + +typedef struct _reassembled_key { + guint32 id; + guint32 frame; +} reassembled_key; + +static GMemChunk *reassembled_key_chunk = NULL; + +static gint +reassembled_equal(gconstpointer k1, gconstpointer k2) +{ + const reassembled_key* key1 = (const reassembled_key*) k1; + const reassembled_key* key2 = (const reassembled_key*) k2; + + /* + * We assume that the frame numbers are unlikely to be equal, + * so we check them first. + */ + return key1->frame == key2->frame && key1->id == key2->id; +} + +static guint +reassembled_hash(gconstpointer k) +{ + const reassembled_key* key = (const reassembled_key*) k; + + return key->frame; +} + +/* + * For a fragment hash table entry, free the address data to which the key + * refers and the fragment data to which the value refers. + * (The actual key and value structures get freed by "reassemble_init()".) + */ +static gboolean +free_all_fragments(gpointer key_arg, gpointer value, gpointer user_data _U_) +{ + fragment_key *key = key_arg; + fragment_data *fd_head; + + /* + * Grr. I guess the theory here is that freeing + * something sure as heck modifies it, so you + * want to ban attempts to free it, but, alas, + * if we make the "data" field of an "address" + * structure not a "const", the compiler whines if + * we try to make it point into the data for a packet, + * as that's a "const" array (and should be, as dissectors + * shouldn't trash it). + * + * So we cast the complaint into oblivion, and rely on + * the fact that these addresses are known to have had + * their data mallocated, i.e. they don't point into, + * say, the middle of the data for a packet. + */ + g_free((gpointer)key->src.data); + g_free((gpointer)key->dst.data); + + for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) { + if(fd_head->data && !(fd_head->flags&FD_NOT_MALLOCED)) + g_free(fd_head->data); + } + + return TRUE; +} + +/* + * For a reassembled-packet hash table entry, free the fragment data + * to which the value refers. + * (The actual value structures get freed by "reassemble_init()".) + */ +static gboolean +free_all_reassembled_fragments(gpointer key_arg _U_, gpointer value, + gpointer user_data _U_) +{ + fragment_data *fd_head; + + for (fd_head = value; fd_head != NULL; fd_head = fd_head->next) { + if(fd_head->data && !(fd_head->flags&FD_NOT_MALLOCED)) { + g_free(fd_head->data); + + /* + * A reassembled packet is inserted into the + * hash table once for every frame that made + * up the reassembled packet; clear the data + * pointer so that we only free the data the + * first time we see it. + */ + fd_head->data = NULL; + } + } + + return TRUE; +} + +/* + * Initialize a fragment table. + */ +void +fragment_table_init(GHashTable **fragment_table) +{ + if (*fragment_table != NULL) { + /* + * The fragment hash table exists. + * + * Remove all entries and free fragment data for + * each entry. (The key and value data is freed + * by "reassemble_init()".) + */ + g_hash_table_foreach_remove(*fragment_table, + free_all_fragments, NULL); + } else { + /* The fragment table does not exist. Create it */ + *fragment_table = g_hash_table_new(fragment_hash, + fragment_equal); + } +} + +void +dcerpc_fragment_table_init(GHashTable **fragment_table) +{ + if (*fragment_table != NULL) { + /* + * The fragment hash table exists. + * + * Remove all entries and free fragment data for + * each entry. (The key and value data is freed + * by "reassemble_init()".) + */ + g_hash_table_foreach_remove(*fragment_table, + free_all_fragments, NULL); + } else { + /* The fragment table does not exist. Create it */ + *fragment_table = g_hash_table_new(dcerpc_fragment_hash, + dcerpc_fragment_equal); + } +} + +/* + * Initialize a reassembled-packet table. + */ +void +reassembled_table_init(GHashTable **reassembled_table) +{ + if (*reassembled_table != NULL) { + /* + * The reassembled-packet hash table exists. + * + * Remove all entries and free reassembled packet + * data for each entry. (The key data is freed + * by "reassemble_init()".) + */ + g_hash_table_foreach_remove(*reassembled_table, + free_all_reassembled_fragments, NULL); + } else { + /* The fragment table does not exist. Create it */ + *reassembled_table = g_hash_table_new(reassembled_hash, + reassembled_equal); + } +} + +/* + * Free up all space allocated for fragment keys and data and + * reassembled keys. + */ +void +reassemble_init(void) +{ + if (fragment_key_chunk != NULL) + g_mem_chunk_destroy(fragment_key_chunk); + if (dcerpc_fragment_key_chunk != NULL) + g_mem_chunk_destroy(dcerpc_fragment_key_chunk); + if (fragment_data_chunk != NULL) + g_mem_chunk_destroy(fragment_data_chunk); + if (reassembled_key_chunk != NULL) + g_mem_chunk_destroy(reassembled_key_chunk); + fragment_key_chunk = g_mem_chunk_new("fragment_key_chunk", + sizeof(fragment_key), + fragment_init_count * sizeof(fragment_key), + G_ALLOC_AND_FREE); + dcerpc_fragment_key_chunk = g_mem_chunk_new("dcerpc_fragment_key_chunk", + sizeof(dcerpc_fragment_key), + fragment_init_count * sizeof(dcerpc_fragment_key), + G_ALLOC_AND_FREE); + fragment_data_chunk = g_mem_chunk_new("fragment_data_chunk", + sizeof(fragment_data), + fragment_init_count * sizeof(fragment_data), + G_ALLOC_ONLY); + reassembled_key_chunk = g_mem_chunk_new("reassembled_key_chunk", + sizeof(reassembled_key), + fragment_init_count * sizeof(reassembled_key), + G_ALLOC_AND_FREE); +} + +/* This function cleans up the stored state and removes the reassembly data and + * (with one exception) all allocated memory for matching reassembly. + * + * The exception is : + * If the PDU was already completely reassembled, then the buffer containing the + * reassembled data WILL NOT be free()d, and the pointer to that buffer will be + * returned. + * Othervise the function will return NULL. + * + * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to + * g_free() that buffer. + */ +unsigned char * +fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table) +{ + fragment_data *fd_head, *fd; + fragment_key key; + unsigned char *data=NULL; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + if(fd_head==NULL){ + /* We do not recognize this as a PDU we have seen before. return*/ + return NULL; + } + + data=fd_head->data; + /* loop over all partial fragments and free any buffers */ + for(fd=fd_head->next;fd;){ + fragment_data *tmp_fd; + tmp_fd=fd->next; + + if( !(fd->flags&FD_NOT_MALLOCED) ) + g_free(fd->data); + g_mem_chunk_free(fragment_data_chunk, fd); + fd=tmp_fd; + } + g_mem_chunk_free(fragment_data_chunk, fd_head); + g_hash_table_remove(fragment_table, &key); + + return data; +} + +/* This function is used to check if there is partial or completed reassembly state + * matching this packet. I.e. Are there reassembly going on or not for this packet? + */ +fragment_data * +fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table) +{ + fragment_data *fd_head; + fragment_key key; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + return fd_head; +} + +/* This function can be used to explicitely set the total length (if known) + * for reassembly of a PDU. + * This is useful for reassembly of PDUs where one may have the total length specified + * in the first fragment instead of as for, say, IPv4 where a flag indicates which + * is the last fragment. + * + * Such protocols might fragment_add with a more_frags==TRUE for every fragment + * and just tell the reassembly engine the expected total length of the reassembled data + * using fragment_set_tot_len immediately after doing fragment_add for the first packet. + * + * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment. + * i.e. since the block numbers start at 0, if we specify tot_len==2, that + * actually means we want to defragment 3 blocks, block 0, 1 and 2. + */ +void +fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 tot_len) +{ + fragment_data *fd_head; + fragment_key key; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + if(fd_head){ + fd_head->datalen = tot_len; + } + + return; +} + +guint32 +fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table) +{ + fragment_data *fd_head; + fragment_key key; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + if(fd_head){ + return fd_head->datalen; + } + + return 0; +} + + +/* This function will set the partial reassembly flag for a fh. + When this function is called, the fh MUST already exist, i.e. + the fh MUST be created by the initial call to fragment_add() before + this function is called. + Also note that this function MUST be called to indicate a fh will be + extended (increase the already stored data) +*/ + +void +fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table) +{ + fragment_data *fd_head; + fragment_key key; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + if(fd_head){ + fd_head->flags |= FD_PARTIAL_REASSEMBLY; + } +} + +/* + * This function gets rid of an entry from a fragment table, given + * a pointer to the key for that entry; it also frees up the key + * and the addresses in it. + */ +static void +fragment_unhash(GHashTable *fragment_table, fragment_key *key) +{ + /* + * Free up the copies of the addresses from the old key. + */ + g_free((gpointer)key->src.data); + g_free((gpointer)key->dst.data); + + /* + * Remove the entry from the fragment table. + */ + g_hash_table_remove(fragment_table, key); + + /* + * Free the key itself. + */ + g_mem_chunk_free(fragment_key_chunk, key); +} + +/* + * This function adds fragment_data structure to a reassembled-packet + * hash table, using the frame numbers of each of the frames from + * which it was reassembled as keys, and sets the "reassembled_in" + * frame number. + */ +static void +fragment_reassembled(fragment_data *fd_head, packet_info *pinfo, + GHashTable *reassembled_table, guint32 id) +{ + reassembled_key *new_key; + fragment_data *fd; + + if (fd_head->next == NULL) { + /* + * This was not fragmented, so there's no fragment + * table; just hash it using the current frame number. + */ + new_key = g_mem_chunk_alloc(reassembled_key_chunk); + new_key->frame = pinfo->fd->num; + new_key->id = id; + g_hash_table_insert(reassembled_table, new_key, fd_head); + } else { + /* + * Hash it with the frame numbers for all the frames. + */ + for (fd = fd_head->next; fd != NULL; fd = fd->next){ + new_key = g_mem_chunk_alloc(reassembled_key_chunk); + new_key->frame = fd->frame; + new_key->id = id; + g_hash_table_insert(reassembled_table, new_key, + fd_head); + } + } + fd_head->flags |= FD_DEFRAGMENTED; + fd_head->reassembled_in = pinfo->fd->num; +} + +/* + * This function adds a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new entry + * is created in the hash table, otherwise this fragment is just added + * to the linked list of fragments for this packet. + * The list of fragments for a specific datagram is kept sorted for + * easier handling. + * + * Returns a pointer to the head of the fragment data list if we have all the + * fragments, NULL otherwise. + * + * This function assumes frag_offset being a byte offset into the defragment + * packet. + * + * 01-2002 + * Once the fh is defragmented (= FD_DEFRAGMENTED set), it can be + * extended using the FD_PARTIAL_REASSEMBLY flag. This flag should be set + * using fragment_set_partial_reassembly() before calling fragment_add + * with the new fragment. FD_TOOLONGFRAGMENT and FD_MULTIPLETAILS flags + * are lowered when a new extension process is started. + */ +static gboolean +fragment_add_work(fragment_data *fd_head, tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags) +{ + fragment_data *fd; + fragment_data *fd_i; + guint32 max, dfpos; + unsigned char *old_data; + + /* create new fd describing this fragment */ + fd = g_mem_chunk_alloc(fragment_data_chunk); + fd->next = NULL; + fd->flags = 0; + fd->frame = pinfo->fd->num; + fd->offset = frag_offset; + fd->len = frag_data_len; + fd->data = NULL; + + /* + * If it was already defragmented and this new fragment goes beyond + * data limits, set flag in already empty fds & point old fds to malloc'ed data. + */ + if(fd_head->flags & FD_DEFRAGMENTED && (frag_offset+frag_data_len) >= fd_head->datalen && + fd_head->flags & FD_PARTIAL_REASSEMBLY){ + for(fd_i=fd_head->next; fd_i; fd_i=fd_i->next){ + if( !fd_i->data ) { + fd_i->data = fd_head->data + fd_i->offset; + fd_i->flags |= FD_NOT_MALLOCED; + } + fd_i->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS); + } + fd_head->flags ^= FD_DEFRAGMENTED|FD_PARTIAL_REASSEMBLY; + fd_head->flags &= (~FD_TOOLONGFRAGMENT) & (~FD_MULTIPLETAILS); + fd_head->datalen=0; + } + + if (!more_frags) { + /* + * This is the tail fragment in the sequence. + */ + if (fd_head->datalen) { + /* ok we have already seen other tails for this packet + * it might be a duplicate. + */ + if (fd_head->datalen != (fd->offset + fd->len) ){ + /* Oops, this tail indicates a different packet + * len than the previous ones. Somethings wrong + */ + fd->flags |= FD_MULTIPLETAILS; + fd_head->flags |= FD_MULTIPLETAILS; + } + } else { + /* this was the first tail fragment, now we know the + * length of the packet + */ + fd_head->datalen = fd->offset + fd->len; + } + } + + + + + /* If the packet is already defragmented, this MUST be an overlap. + * The entire defragmented packet is in fd_head->data + * Even if we have previously defragmented this packet, we still check + * check it. Someone might play overlap and TTL games. + */ + if (fd_head->flags & FD_DEFRAGMENTED) { + fd->flags |= FD_OVERLAP; + fd_head->flags |= FD_OVERLAP; + /* make sure its not too long */ + if (fd->offset + fd->len > fd_head->datalen) { + fd->flags |= FD_TOOLONGFRAGMENT; + fd_head->flags |= FD_TOOLONGFRAGMENT; + LINK_FRAG(fd_head,fd); + return TRUE; + } + /* make sure it doesnt conflict with previous data */ + if ( memcmp(fd_head->data+fd->offset, + tvb_get_ptr(tvb,offset,fd->len),fd->len) ){ + fd->flags |= FD_OVERLAPCONFLICT; + fd_head->flags |= FD_OVERLAPCONFLICT; + LINK_FRAG(fd_head,fd); + return TRUE; + } + /* it was just an overlap, link it and return */ + LINK_FRAG(fd_head,fd); + return TRUE; + } + + + + /* If we have reached this point, the packet is not defragmented yet. + * Save all payload in a buffer until we can defragment. + * XXX - what if we didn't capture the entire fragment due + * to a too-short snapshot length? + */ + fd->data = g_malloc(fd->len); + tvb_memcpy(tvb, fd->data, offset, fd->len); + LINK_FRAG(fd_head,fd); + + + if( !(fd_head->datalen) ){ + /* if we dont know the datalen, there are still missing + * packets. Cheaper than the check below. + */ + return FALSE; + } + + + /* check if we have received the entire fragment + * this is easy since the list is sorted and the head is faked. + */ + max = 0; + for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { + if ( ((fd_i->offset)<=max) && + ((fd_i->offset+fd_i->len)>max) ){ + max = fd_i->offset+fd_i->len; + } + } + + if (max < (fd_head->datalen)) { + /* we have not received all packets yet */ + return FALSE; + } + + + if (max > (fd_head->datalen)) { + /*XXX not sure if current fd was the TOOLONG*/ + /*XXX is it fair to flag current fd*/ + /* oops, too long fragment detected */ + fd->flags |= FD_TOOLONGFRAGMENT; + fd_head->flags |= FD_TOOLONGFRAGMENT; + } + + + /* we have received an entire packet, defragment it and + * free all fragments + */ + /* store old data just in case */ + old_data=fd_head->data; + fd_head->data = g_malloc(max); + + /* add all data fragments */ + for (dfpos=0,fd_i=fd_head;fd_i;fd_i=fd_i->next) { + if (fd_i->len) { + if (fd_i->offset < dfpos) { + fd_i->flags |= FD_OVERLAP; + fd_head->flags |= FD_OVERLAP; + if ( memcmp(fd_head->data+fd_i->offset, + fd_i->data, + MIN(fd_i->len,(dfpos-fd_i->offset)) + ) ){ + fd_i->flags |= FD_OVERLAPCONFLICT; + fd_head->flags |= FD_OVERLAPCONFLICT; + } + } + /* dfpos is always >= than fd_i->offset */ + /* No gaps can exist here, max_loop(above) does this */ + if( fd_i->offset+fd_i->len > dfpos ) + memcpy(fd_head->data+dfpos, fd_i->data+(dfpos-fd_i->offset), + fd_i->len-(dfpos-fd_i->offset)); + if( fd_i->flags & FD_NOT_MALLOCED ) + fd_i->flags ^= FD_NOT_MALLOCED; + else + g_free(fd_i->data); + fd_i->data=NULL; + + dfpos=MAX(dfpos,(fd_i->offset+fd_i->len)); + } + } + + if( old_data ) + g_free(old_data); + /* mark this packet as defragmented. + allows us to skip any trailing fragments */ + fd_head->flags |= FD_DEFRAGMENTED; + fd_head->reassembled_in=pinfo->fd->num; + + return TRUE; +} + +fragment_data * +fragment_add_common(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + GHashTable *fragment_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags, + gboolean check_already_added) +{ + fragment_key key, *new_key; + fragment_data *fd_head; + fragment_data *fd_item; + gboolean already_added=pinfo->fd->flags.visited; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + /* + * "already_added" is true if "pinfo->fd->flags.visited" is true; + * if "pinfo->fd->flags.visited", this isn't the first pass, so + * we've already done all the reassembly and added all the + * fragments. + * + * If it's not true, but "check_already_added" is true, just check + * if we have seen this fragment before, i.e., if we have already + * added it to reassembly. + * That can be true even if "pinfo->fd->flags.visited" is false + * since we sometimes might call a subdissector multiple times. + * As an additional check, just make sure we have not already added + * this frame to the reassembly list, if there is a reassembly list; + * note that the first item in the reassembly list is not a + * fragment, it's a data structure for the reassembled packet. + * We don't check it because its "frame" member isn't initialized + * to anything, and because it doesn't count in any case. + */ + if (!already_added && check_already_added && fd_head != NULL) { + for(fd_item=fd_head->next;fd_item;fd_item=fd_item->next){ + if(pinfo->fd->num==fd_item->frame){ + already_added=TRUE; + } + } + } + /* have we already added this frame ?*/ + if (already_added) { + if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) { + return fd_head; + } else { + return NULL; + } + } + + if (fd_head==NULL){ + /* not found, this must be the first snooped fragment for this + * packet. Create list-head. + */ + fd_head=g_mem_chunk_alloc(fragment_data_chunk); + + /* head/first structure in list only holds no other data than + * 'datalen' then we don't have to change the head of the list + * even if we want to keep it sorted + */ + fd_head->next=NULL; + fd_head->datalen=0; + fd_head->offset=0; + fd_head->len=0; + fd_head->flags=0; + fd_head->data=NULL; + fd_head->reassembled_in=0; + + /* + * We're going to use the key to insert the fragment, + * so allocate a structure for it, and copy the + * addresses, allocating new buffers for the address + * data. + */ + new_key = g_mem_chunk_alloc(fragment_key_chunk); + COPY_ADDRESS(&new_key->src, &key.src); + COPY_ADDRESS(&new_key->dst, &key.dst); + new_key->id = key.id; + g_hash_table_insert(fragment_table, new_key, fd_head); + } + + if (fragment_add_work(fd_head, tvb, offset, pinfo, frag_offset, + frag_data_len, more_frags)) { + /* + * Reassembly is complete. + */ + return fd_head; + } else { + /* + * Reassembly isn't complete. + */ + return NULL; + } +} + +fragment_data * +fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + GHashTable *fragment_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags) +{ + return fragment_add_common(tvb, offset, pinfo, id, fragment_table, + frag_offset, frag_data_len, more_frags, TRUE); +} + +/* + * For use when you can have multiple fragments in the same frame added + * to the same reassembled PDU, e.g. with ONC RPC-over-TCP. + */ +fragment_data * +fragment_add_multiple_ok(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + guint32 frag_offset, guint32 frag_data_len, + gboolean more_frags) +{ + return fragment_add_common(tvb, offset, pinfo, id, fragment_table, + frag_offset, frag_data_len, more_frags, FALSE); +} + +fragment_data * +fragment_add_check(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags) +{ + reassembled_key reass_key; + fragment_key key, *new_key, *old_key; + gpointer orig_key, value; + fragment_data *fd_head; + + /* + * If this isn't the first pass, look for this frame in the table + * of reassembled packets. + */ + if (pinfo->fd->flags.visited) { + reass_key.frame = pinfo->fd->num; + reass_key.id = id; + return g_hash_table_lookup(reassembled_table, &reass_key); + } + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + if (!g_hash_table_lookup_extended(fragment_table, &key, + &orig_key, &value)) { + /* not found, this must be the first snooped fragment for this + * packet. Create list-head. + */ + fd_head=g_mem_chunk_alloc(fragment_data_chunk); + + /* head/first structure in list only holds no other data than + * 'datalen' then we don't have to change the head of the list + * even if we want to keep it sorted + */ + fd_head->next=NULL; + fd_head->datalen=0; + fd_head->offset=0; + fd_head->len=0; + fd_head->flags=0; + fd_head->data=NULL; + fd_head->reassembled_in=0; + + /* + * We're going to use the key to insert the fragment, + * so allocate a structure for it, and copy the + * addresses, allocating new buffers for the address + * data. + */ + new_key = g_mem_chunk_alloc(fragment_key_chunk); + COPY_ADDRESS(&new_key->src, &key.src); + COPY_ADDRESS(&new_key->dst, &key.dst); + new_key->id = key.id; + g_hash_table_insert(fragment_table, new_key, fd_head); + + orig_key = new_key; /* for unhashing it later */ + } else { + /* + * We found it. + */ + fd_head = value; + } + + /* + * If this is a short frame, then we can't, and don't, do + * reassembly on it. We just give up. + */ + if (tvb_reported_length(tvb) > tvb_length(tvb)) + return NULL; + + if (fragment_add_work(fd_head, tvb, offset, pinfo, frag_offset, + frag_data_len, more_frags)) { + /* + * Reassembly is complete. + * Remove this from the table of in-progress + * reassemblies, add it to the table of + * reassembled packets, and return it. + */ + + /* + * Remove this from the table of in-progress reassemblies, + * and free up any memory used for it in that table. + */ + old_key = orig_key; + fragment_unhash(fragment_table, old_key); + + /* + * Add this item to the table of reassembled packets. + */ + fragment_reassembled(fd_head, pinfo, reassembled_table, id); + return fd_head; + } else { + /* + * Reassembly isn't complete. + */ + return NULL; + } +} + +/* + * This function adds a new fragment to the entry for a reassembly + * operation. + * + * The list of fragments for a specific datagram is kept sorted for + * easier handling. + * + * Returns TRUE if we have all the fragments, FALSE otherwise. + * + * This function assumes frag_number being a block sequence number. + * The bsn for the first block is 0. + */ +static gboolean +fragment_add_seq_work(fragment_data *fd_head, tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags) +{ + fragment_data *fd; + fragment_data *fd_i; + fragment_data *last_fd; + guint32 max, dfpos, size; + + /* create new fd describing this fragment */ + fd = g_mem_chunk_alloc(fragment_data_chunk); + fd->next = NULL; + fd->flags = 0; + fd->frame = pinfo->fd->num; + fd->offset = frag_number; + fd->len = frag_data_len; + fd->data = NULL; + + if (!more_frags) { + /* + * This is the tail fragment in the sequence. + */ + if (fd_head->datalen) { + /* ok we have already seen other tails for this packet + * it might be a duplicate. + */ + if (fd_head->datalen != fd->offset ){ + /* Oops, this tail indicates a different packet + * len than the previous ones. Somethings wrong + */ + fd->flags |= FD_MULTIPLETAILS; + fd_head->flags |= FD_MULTIPLETAILS; + } + } else { + /* this was the first tail fragment, now we know the + * sequence number of that fragment (which is NOT + * the length of the packet!) + */ + fd_head->datalen = fd->offset; + } + } + + /* If the packet is already defragmented, this MUST be an overlap. + * The entire defragmented packet is in fd_head->data + * Even if we have previously defragmented this packet, we still check + * check it. Someone might play overlap and TTL games. + */ + if (fd_head->flags & FD_DEFRAGMENTED) { + fd->flags |= FD_OVERLAP; + fd_head->flags |= FD_OVERLAP; + + /* make sure it's not past the end */ + if (fd->offset > fd_head->datalen) { + /* new fragment comes after the end */ + fd->flags |= FD_TOOLONGFRAGMENT; + fd_head->flags |= FD_TOOLONGFRAGMENT; + LINK_FRAG(fd_head,fd); + return TRUE; + } + /* make sure it doesnt conflict with previous data */ + dfpos=0; + last_fd=NULL; + for (fd_i=fd_head->next;fd_i->offset!=fd->offset;fd_i=fd_i->next) { + if (!last_fd || last_fd->offset!=fd_i->offset){ + dfpos += fd_i->len; + } + last_fd=fd_i; + } + if(fd_i){ + /* new fragment overlaps existing fragment */ + if(fd_i->len!=fd->len){ + /* + * They have different lengths; this + * is definitely a conflict. + */ + fd->flags |= FD_OVERLAPCONFLICT; + fd_head->flags |= FD_OVERLAPCONFLICT; + LINK_FRAG(fd_head,fd); + return TRUE; + } + g_assert(fd_head->len >= dfpos + fd->len); + if ( memcmp(fd_head->data+dfpos, + tvb_get_ptr(tvb,offset,fd->len),fd->len) ){ + /* + * They have the same length, but the + * data isn't the same. + */ + fd->flags |= FD_OVERLAPCONFLICT; + fd_head->flags |= FD_OVERLAPCONFLICT; + LINK_FRAG(fd_head,fd); + return TRUE; + } + /* it was just an overlap, link it and return */ + LINK_FRAG(fd_head,fd); + return TRUE; + } else { + /* + * New fragment doesn't overlap an existing + * fragment - there was presumably a gap in + * the sequence number space. + * + * XXX - what should we do here? Is it always + * the case that there are no gaps, or are there + * protcols using sequence numbers where there + * can be gaps? + * + * If the former, the check below for having + * received all the fragments should check for + * holes in the sequence number space and for the + * first sequence number being 0. If we do that, + * the only way we can get here is if this fragment + * is past the end of the sequence number space - + * but the check for "fd->offset > fd_head->datalen" + * would have caught that above, so it can't happen. + * + * If the latter, we don't have a good way of + * knowing whether reassembly is complete if we + * get packet out of order such that the "last" + * fragment doesn't show up last - but, unless + * in-order reliable delivery of fragments is + * guaranteed, an implementation of the protocol + * has no way of knowing whether reassembly is + * complete, either. + * + * For now, we just link the fragment in and + * return. + */ + LINK_FRAG(fd_head,fd); + return TRUE; + } + } + + /* If we have reached this point, the packet is not defragmented yet. + * Save all payload in a buffer until we can defragment. + * XXX - what if we didn't capture the entire fragment due + * to a too-short snapshot length? + */ + fd->data = g_malloc(fd->len); + tvb_memcpy(tvb, fd->data, offset, fd->len); + LINK_FRAG(fd_head,fd); + + + if( !(fd_head->datalen) ){ + /* if we dont know the sequence number of the last fragment, + * there are definitely still missing packets. Cheaper than + * the check below. + */ + return FALSE; + } + + + /* check if we have received the entire fragment + * this is easy since the list is sorted and the head is faked. + */ + max = 0; + for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { + if ( fd_i->offset==max ){ + max++; + } + } + /* max will now be datalen+1 if all fragments have been seen */ + + if (max <= fd_head->datalen) { + /* we have not received all packets yet */ + return FALSE; + } + + + if (max > (fd_head->datalen+1)) { + /* oops, too long fragment detected */ + fd->flags |= FD_TOOLONGFRAGMENT; + fd_head->flags |= FD_TOOLONGFRAGMENT; + } + + + /* we have received an entire packet, defragment it and + * free all fragments + */ + size=0; + last_fd=NULL; + for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { + if(!last_fd || last_fd->offset!=fd_i->offset){ + size+=fd_i->len; + } + last_fd=fd_i; + } + fd_head->data = g_malloc(size); + fd_head->len = size; /* record size for caller */ + + /* add all data fragments */ + last_fd=NULL; + for (dfpos=0,fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { + if (fd_i->len) { + if(!last_fd || last_fd->offset!=fd_i->offset){ + memcpy(fd_head->data+dfpos,fd_i->data,fd_i->len); + dfpos += fd_i->len; + } else { + /* duplicate/retransmission/overlap */ + fd_i->flags |= FD_OVERLAP; + fd_head->flags |= FD_OVERLAP; + if( (last_fd->len!=fd_i->datalen) + || memcmp(last_fd->data, fd_i->data, last_fd->len) ){ + fd->flags |= FD_OVERLAPCONFLICT; + fd_head->flags |= FD_OVERLAPCONFLICT; + } + } + last_fd=fd_i; + } + } + + /* we have defragmented the pdu, now free all fragments*/ + for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { + if(fd_i->data){ + g_free(fd_i->data); + fd_i->data=NULL; + } + } + + /* mark this packet as defragmented. + allows us to skip any trailing fragments */ + fd_head->flags |= FD_DEFRAGMENTED; + fd_head->reassembled_in=pinfo->fd->num; + + return TRUE; +} + +/* + * This function adds a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new entry + * is created in the hash table, otherwise this fragment is just added + * to the linked list of fragments for this packet. + * + * Returns a pointer to the head of the fragment data list if we have all the + * fragments, NULL otherwise. + * + * This function assumes frag_number being a block sequence number. + * The bsn for the first block is 0. + */ +fragment_data * +fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags) +{ + fragment_key key, *new_key; + fragment_data *fd_head; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + /* have we already seen this frame ?*/ + if (pinfo->fd->flags.visited) { + if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) { + return fd_head; + } else { + return NULL; + } + } + + if (fd_head==NULL){ + /* not found, this must be the first snooped fragment for this + * packet. Create list-head. + */ + fd_head=g_mem_chunk_alloc(fragment_data_chunk); + + /* head/first structure in list only holds no other data than + * 'datalen' then we don't have to change the head of the list + * even if we want to keep it sorted + */ + fd_head->next=NULL; + fd_head->datalen=0; + fd_head->offset=0; + fd_head->len=0; + fd_head->flags=FD_BLOCKSEQUENCE; + fd_head->data=NULL; + fd_head->reassembled_in=0; + + /* + * We're going to use the key to insert the fragment, + * so allocate a structure for it, and copy the + * addresses, allocating new buffers for the address + * data. + */ + new_key = g_mem_chunk_alloc(fragment_key_chunk); + COPY_ADDRESS(&new_key->src, &key.src); + COPY_ADDRESS(&new_key->dst, &key.dst); + new_key->id = key.id; + g_hash_table_insert(fragment_table, new_key, fd_head); + } + + if (fragment_add_seq_work(fd_head, tvb, offset, pinfo, + frag_number, frag_data_len, more_frags)) { + /* + * Reassembly is complete. + */ + return fd_head; + } else { + /* + * Reassembly isn't complete. + */ + return NULL; + } +} + +fragment_data * +fragment_add_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + void *v_act_id, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags) +{ + dcerpc_fragment_key key, *new_key; + fragment_data *fd_head; + e_uuid_t *act_id = (e_uuid_t *)v_act_id; + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + key.act_id = *act_id; + + fd_head = g_hash_table_lookup(fragment_table, &key); + + /* have we already seen this frame ?*/ + if (pinfo->fd->flags.visited) { + if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) { + return fd_head; + } else { + return NULL; + } + } + + if (fd_head==NULL){ + /* not found, this must be the first snooped fragment for this + * packet. Create list-head. + */ + fd_head=g_mem_chunk_alloc(fragment_data_chunk); + + /* head/first structure in list only holds no other data than + * 'datalen' then we don't have to change the head of the list + * even if we want to keep it sorted + */ + fd_head->next=NULL; + fd_head->datalen=0; + fd_head->offset=0; + fd_head->len=0; + fd_head->flags=FD_BLOCKSEQUENCE; + fd_head->data=NULL; + fd_head->reassembled_in=0; + + /* + * We're going to use the key to insert the fragment, + * so allocate a structure for it, and copy the + * addresses, allocating new buffers for the address + * data. + */ + new_key = g_mem_chunk_alloc(dcerpc_fragment_key_chunk); + COPY_ADDRESS(&new_key->src, &key.src); + COPY_ADDRESS(&new_key->dst, &key.dst); + new_key->id = key.id; + new_key->act_id = key.act_id; + g_hash_table_insert(fragment_table, new_key, fd_head); + } + + if (fragment_add_seq_work(fd_head, tvb, offset, pinfo, + frag_number, frag_data_len, more_frags)) { + /* + * Reassembly is complete. + */ + return fd_head; + } else { + /* + * Reassembly isn't complete. + */ + return NULL; + } +} + +/* + * This does the work for "fragment_add_seq_check()" and + * "fragment_add_seq_next()". + * + * This function assumes frag_number being a block sequence number. + * The bsn for the first block is 0. + * + * If "no_frag_number" is TRUE, it uses the next expected fragment number + * as the fragment number if there is a reassembly in progress, otherwise + * it uses 0. + * + * If "no_frag_number" is FALSE, it uses the "frag_number" argument as + * the fragment number. + * + * If this is the first fragment seen for this datagram, a new + * "fragment_data" structure is allocated to refer to the reassembled, + * packet, and: + * + * if "more_frags" is false and "frag_802_11_hack" is true, the + * structure is not added to the hash table, and not given any + * fragments to refer to, but is just returned - this is a special + * hack for the 802.11 dissector (see packet-80211.c); + * + * otherwise, this fragment is added to the linked list of fragments + * for this packet, and the "fragment_data" structure is put into + * the hash table. + * + * Otherwise, this fragment is just added to the linked list of fragments + * for this packet. + * + * If, after processing this fragment, we have all the fragments, + * "fragment_add_seq_check_work()" removes that from the fragment hash + * table if necessary and adds it to the table of reassembled fragments, + * and returns a pointer to the head of the fragment list. + * + * If this is the first fragment we've seen, and "more_frags" is false + * and "frag_802_11_hack" is true, "fragment_add_seq_check_work()" does + * nothing to the fragment data list, and returns a pointer to the head + * of that (empty) list. + * + * Otherwise, it returns NULL. + */ +static fragment_data * +fragment_add_seq_check_work(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags, + gboolean no_frag_number, gboolean frag_802_11_hack) +{ + reassembled_key reass_key; + fragment_key key, *new_key, *old_key; + gpointer orig_key, value; + fragment_data *fd_head, *fd; + + /* + * Have we already seen this frame? + * If so, look for it in the table of reassembled packets. + */ + if (pinfo->fd->flags.visited) { + reass_key.frame = pinfo->fd->num; + reass_key.id = id; + return g_hash_table_lookup(reassembled_table, &reass_key); + } + + /* create key to search hash with */ + key.src = pinfo->src; + key.dst = pinfo->dst; + key.id = id; + + if (!g_hash_table_lookup_extended(fragment_table, &key, + &orig_key, &value)) { + /* not found, this must be the first snooped fragment for this + * packet. Create list-head. + */ + fd_head=g_mem_chunk_alloc(fragment_data_chunk); + + /* head/first structure in list only holds no other data than + * 'datalen' then we don't have to change the head of the list + * even if we want to keep it sorted + */ + fd_head->next=NULL; + fd_head->datalen=0; + fd_head->offset=0; + fd_head->len=0; + fd_head->flags=FD_BLOCKSEQUENCE; + fd_head->data=NULL; + fd_head->reassembled_in=0; + + if ((no_frag_number || frag_802_11_hack) && !more_frags) { + /* + * This is the last fragment for this packet, and + * is the only one we've seen. + * + * Either we don't have sequence numbers, in which + * case we assume this is the first fragment for + * this packet, or we're doing special 802.11 + * processing, in which case we assume it's one + * of those reassembled packets with a non-zero + * fragment number (see packet-80211.c); just + * add the fragment to the table of reassembled + * packets, and return a pointer to the head of + * the list. + */ + fragment_reassembled(fd_head, pinfo, + reassembled_table, id); + return fd_head; + } + + /* + * We're going to use the key to insert the fragment, + * so allocate a structure for it, and copy the + * addresses, allocating new buffers for the address + * data. + */ + new_key = g_mem_chunk_alloc(fragment_key_chunk); + COPY_ADDRESS(&new_key->src, &key.src); + COPY_ADDRESS(&new_key->dst, &key.dst); + new_key->id = key.id; + g_hash_table_insert(fragment_table, new_key, fd_head); + + orig_key = new_key; /* for unhashing it later */ + + /* + * If we weren't given an initial fragment number, + * make it 0. + */ + if (no_frag_number) + frag_number = 0; + } else { + /* + * We found it. + */ + fd_head = value; + + /* + * If we weren't given an initial fragment number, + * use the next expected fragment number as the fragment + * number for this fragment. + */ + if (no_frag_number) { + for (fd = fd_head; fd != NULL; fd = fd->next) { + if (fd->next == NULL) + frag_number = fd->offset + 1; + } + } + } + + /* + * If we don't have all the data that is in this fragment, + * then we can't, and don't, do reassembly on it. + * + * If it's the first frame, handle it as an unfragmented packet. + * Otherwise, just handle it as a fragment. + * + * If "more_frags" isn't set, we get rid of the entry in the + * hash table for this reassembly, as we don't need it any more. + */ + if (!tvb_bytes_exist(tvb, offset, frag_data_len)) { + if (!more_frags) { + /* + * Remove this from the table of in-progress + * reassemblies, and free up any memory used for + * it in that table. + */ + old_key = orig_key; + fragment_unhash(fragment_table, old_key); + } + return frag_number == 0 ? fd_head : NULL; + } + + if (fragment_add_seq_work(fd_head, tvb, offset, pinfo, + frag_number, frag_data_len, more_frags)) { + /* + * Reassembly is complete. + * Remove this from the table of in-progress + * reassemblies, add it to the table of + * reassembled packets, and return it. + */ + + /* + * Remove this from the table of in-progress reassemblies, + * and free up any memory used for it in that table. + */ + old_key = orig_key; + fragment_unhash(fragment_table, old_key); + + /* + * Add this item to the table of reassembled packets. + */ + fragment_reassembled(fd_head, pinfo, reassembled_table, id); + return fd_head; + } else { + /* + * Reassembly isn't complete. + */ + return NULL; + } +} + +fragment_data * +fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags) +{ + return fragment_add_seq_check_work(tvb, offset, pinfo, id, + fragment_table, reassembled_table, frag_number, frag_data_len, + more_frags, FALSE, FALSE); +} + +fragment_data * +fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags) +{ + return fragment_add_seq_check_work(tvb, offset, pinfo, id, + fragment_table, reassembled_table, frag_number, frag_data_len, + more_frags, FALSE, TRUE); +} + +fragment_data * +fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_data_len, + gboolean more_frags) +{ + return fragment_add_seq_check_work(tvb, offset, pinfo, id, + fragment_table, reassembled_table, 0, frag_data_len, + more_frags, TRUE, FALSE); +} + +/* + * Process reassembled data; if we're on the frame in which the data + * was reassembled, put the fragment information into the protocol + * tree, and construct a tvbuff with the reassembled data, otherwise + * just put a "reassembled in" item into the protocol tree. + */ +tvbuff_t * +process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo, + char *name, fragment_data *fd_head, const fragment_items *fit, + gboolean *update_col_infop, proto_tree *tree) +{ + tvbuff_t *next_tvb; + gboolean update_col_info; + + if (fd_head != NULL && pinfo->fd->num == fd_head->reassembled_in) { + /* + * OK, we've reassembled this. + * Is this something that's been reassembled from more + * than one fragment? + */ + if (fd_head->next != NULL) { + /* + * Yes. + * Allocate a new tvbuff, referring to the + * reassembled payload. + */ + if (fd_head->flags & FD_BLOCKSEQUENCE) { + next_tvb = tvb_new_real_data(fd_head->data, + fd_head->len, fd_head->len); + } else { + next_tvb = tvb_new_real_data(fd_head->data, + fd_head->datalen, fd_head->datalen); + } + + /* + * Add the tvbuff to the list of tvbuffs to which + * the tvbuff we were handed refers, so it'll get + * cleaned up when that tvbuff is cleaned up. + */ + tvb_set_child_real_data_tvbuff(tvb, next_tvb); + + /* Add the defragmented data to the data source list. */ + add_new_data_source(pinfo, next_tvb, name); + + /* show all fragments */ + if (fd_head->flags & FD_BLOCKSEQUENCE) { + update_col_info = !show_fragment_seq_tree( + fd_head, fit, tree, pinfo, next_tvb); + } else { + update_col_info = !show_fragment_tree(fd_head, + fit, tree, pinfo, next_tvb); + } + } else { + /* + * No. + * Return a tvbuff with the payload. + */ + next_tvb = tvb_new_subset(tvb, offset, -1, -1); + pinfo->fragmented = FALSE; /* one-fragment packet */ + update_col_info = TRUE; + } + if (update_col_infop != NULL) + *update_col_infop = update_col_info; + } else { + /* + * We don't have the complete reassembled payload, or this + * isn't the final frame of that payload. + */ + next_tvb = NULL; + + /* + * If we know what frame this was reassembled in, + * and if there's a field to use for the number of + * the frame in which the packet was reassembled, + * add it to the protocol tree. + */ + if (fd_head != NULL && fit->hf_reassembled_in != NULL) { + proto_tree_add_uint(tree, + *(fit->hf_reassembled_in), tvb, + 0, 0, fd_head->reassembled_in); + } + } + return next_tvb; +} + +/* + * Show a single fragment in a fragment subtree. + */ +static void +show_fragment(fragment_data *fd, int offset, const fragment_items *fit, + proto_tree *ft, tvbuff_t *tvb) +{ + proto_item *fei=NULL; + int hf; + + if (fd->flags & (FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { + hf = *(fit->hf_fragment_error); + } else { + hf = *(fit->hf_fragment); + } + if (fd->len == 0) { + fei = proto_tree_add_uint_format(ft, hf, + tvb, offset, fd->len, + fd->frame, + "Frame: %u (no data)", + fd->frame); + } else { + fei = proto_tree_add_uint_format(ft, hf, + tvb, offset, fd->len, + fd->frame, + "Frame: %u, payload: %u-%u (%u bytes)", + fd->frame, + offset, + offset+fd->len-1, + fd->len); + } + PROTO_ITEM_SET_GENERATED(fei); + if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { + /* this fragment has some flags set, create a subtree + * for it and display the flags. + */ + proto_tree *fet=NULL; + + fet = proto_item_add_subtree(fei, *(fit->ett_fragment)); + if (fd->flags&FD_OVERLAP) { + fei=proto_tree_add_boolean(fet, + *(fit->hf_fragment_overlap), + tvb, 0, 0, + TRUE); + PROTO_ITEM_SET_GENERATED(fei); + } + if (fd->flags&FD_OVERLAPCONFLICT) { + fei=proto_tree_add_boolean(fet, + *(fit->hf_fragment_overlap_conflict), + tvb, 0, 0, + TRUE); + PROTO_ITEM_SET_GENERATED(fei); + } + if (fd->flags&FD_MULTIPLETAILS) { + fei=proto_tree_add_boolean(fet, + *(fit->hf_fragment_multiple_tails), + tvb, 0, 0, + TRUE); + PROTO_ITEM_SET_GENERATED(fei); + } + if (fd->flags&FD_TOOLONGFRAGMENT) { + fei=proto_tree_add_boolean(fet, + *(fit->hf_fragment_too_long_fragment), + tvb, 0, 0, + TRUE); + PROTO_ITEM_SET_GENERATED(fei); + } + } +} + +static gboolean +show_fragment_errs_in_col(fragment_data *fd_head, const fragment_items *fit, + packet_info *pinfo) +{ + if (fd_head->flags & (FD_OVERLAPCONFLICT + |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { + if (check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, + "[Illegal %s]", fit->tag); + return TRUE; + } + } + + return FALSE; +} + +/* This function will build the fragment subtree; it's for fragments + reassembled with "fragment_add()". + + It will return TRUE if there were fragmentation errors + or FALSE if fragmentation was ok. +*/ +gboolean +show_fragment_tree(fragment_data *fd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb) +{ + fragment_data *fd; + proto_tree *ft; + proto_item *fi; + + /* It's not fragmented. */ + pinfo->fragmented = FALSE; + + fi = proto_tree_add_item(tree, *(fit->hf_fragments), + tvb, 0, -1, FALSE); + PROTO_ITEM_SET_GENERATED(fi); + + ft = proto_item_add_subtree(fi, *(fit->ett_fragments)); + for (fd = fd_head->next; fd != NULL; fd = fd->next) + show_fragment(fd, fd->offset, fit, ft, tvb); + + return show_fragment_errs_in_col(fd_head, fit, pinfo); +} + +/* This function will build the fragment subtree; it's for fragments + reassembled with "fragment_add_seq()" or "fragment_add_seq_check()". + + It will return TRUE if there were fragmentation errors + or FALSE if fragmentation was ok. +*/ +gboolean +show_fragment_seq_tree(fragment_data *fd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb) +{ + guint32 offset, next_offset; + fragment_data *fd, *last_fd; + proto_tree *ft; + proto_item *fi; + + /* It's not fragmented. */ + pinfo->fragmented = FALSE; + + fi = proto_tree_add_item(tree, *(fit->hf_fragments), + tvb, 0, -1, FALSE); + PROTO_ITEM_SET_GENERATED(fi); + ft = proto_item_add_subtree(fi, *(fit->ett_fragments)); + offset = 0; + next_offset = 0; + last_fd = NULL; + for (fd = fd_head->next; fd != NULL; fd = fd->next){ + if (last_fd == NULL || last_fd->offset != fd->offset) { + offset = next_offset; + next_offset += fd->len; + } + last_fd = fd; + show_fragment(fd, offset, fit, ft, tvb); + } + + return show_fragment_errs_in_col(fd_head, fit, pinfo); +} diff --git a/epan/reassemble.h b/epan/reassemble.h new file mode 100644 index 0000000000..85c66942c9 --- /dev/null +++ b/epan/reassemble.h @@ -0,0 +1,244 @@ +/* reassemble.h + * Declarations of outines for {fragment,segment} reassembly + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* make sure that all flags that are set in a fragment entry is also set for + * the flags field of fd_head !!! + */ + +/* only in fd_head: packet is defragmented */ +#define FD_DEFRAGMENTED 0x0001 + +/* there are overlapping fragments */ +#define FD_OVERLAP 0x0002 + +/* overlapping fragments contain different data */ +#define FD_OVERLAPCONFLICT 0x0004 + +/* more than one fragment which indicates end-of data */ +#define FD_MULTIPLETAILS 0x0008 + +/* fragment contains data past the end of the datagram */ +#define FD_TOOLONGFRAGMENT 0x0010 + +/* fragment data not alloced, fd->data pointing to fd_head->data+fd->offset */ +#define FD_NOT_MALLOCED 0x0020 + +/* this flag is used to request fragment_add to continue the reassembly process */ +#define FD_PARTIAL_REASSEMBLY 0x0040 + +/* fragment offset is indicated by sequence number and not byte offset + into the defragmented packet */ +#define FD_BLOCKSEQUENCE 0x0100 + +typedef struct _fragment_data { + struct _fragment_data *next; + guint32 frame; + guint32 offset; + guint32 len; + guint32 datalen; /*Only valid in first item of list */ + guint32 reassembled_in; /* frame where this PDU was reassembled, + only valid in the first item of the list + and when FD_DEFRAGMENTED is set*/ + guint32 flags; + unsigned char *data; +} fragment_data; + +/* + * Initialize a fragment table. + */ +extern void fragment_table_init(GHashTable **fragment_table); +extern void dcerpc_fragment_table_init(GHashTable **fragment_table); + +/* + * Initialize a reassembled-packet table. + */ +extern void reassembled_table_init(GHashTable **reassembled_table); + +/* + * Free up all space allocated for fragment keys and data. + */ +void reassemble_init(void); + +/* + * This function adds a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new entry + * is created in the hash table, otherwise this fragment is just added + * to the linked list of fragments for this packet. + * The list of fragments for a specific datagram is kept sorted for + * easier handling. + * + * Returns a pointer to the head of the fragment data list if we have all the + * fragments, NULL otherwise. + */ +extern fragment_data *fragment_add(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags); +extern fragment_data *fragment_add_multiple_ok(tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 frag_offset, guint32 frag_data_len, gboolean more_frags); + +extern fragment_data *fragment_add_check(tvbuff_t *tvb, int offset, + packet_info *pinfo, guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_offset, + guint32 frag_data_len, gboolean more_frags); + +/* same as fragment_add() but this one assumes frag_number is a block + sequence number. note that frag_number is 0 for the first fragment. */ +extern fragment_data *fragment_add_seq(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +extern fragment_data * +fragment_add_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + void *act_id, + GHashTable *fragment_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +/* + * These functions add a new fragment to the fragment hash table. + * If this is the first fragment seen for this datagram, a new + * "fragment_data" structure is allocated to refer to the reassembled, + * packet, and: + * + * in "fragment_add_seq_802_11()", if "more_frags" is false, + * the structure is not added to the hash table, and not given + * any fragments to refer to, but is just returned; + * + * otherwise, this fragment is added to the linked list of fragments + * for this packet, and the "fragment_data" structure is put into + * the hash table. + * + * Otherwise, this fragment is just added to the linked list of fragments + * for this packet. + * + * If, after processing this fragment, we have all the fragments, they + * remove that from the fragment hash table if necessary and add it + * to the table of reassembled fragments, and return a pointer to the + * head of the fragment list. + * + * If this is the first fragment we've seen, and "more_frags" is false, + * "fragment_add_seq_802_11()" does nothing to the fragment data list, + * and returns a pointer to the head of that (empty) list. The other + * routines return NULL. + * + * Otherwise, they return NULL. + * + * "fragment_add_seq_check()" and "fragment_add_seq_802_11()" assume + * frag_number is a block sequence number. + * The bsn for the first block is 0. + * + * "fragment_add_seq_next()" is for protocols with no sequence number, + * and assumes fragments always appear in sequence. + */ +extern fragment_data * +fragment_add_seq_check(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +extern fragment_data * +fragment_add_seq_802_11(tvbuff_t *tvb, int offset, packet_info *pinfo, + guint32 id, GHashTable *fragment_table, + GHashTable *reassembled_table, guint32 frag_number, + guint32 frag_data_len, gboolean more_frags); + +extern fragment_data * +fragment_add_seq_next(tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 id, + GHashTable *fragment_table, GHashTable *reassembled_table, + guint32 frag_data_len, gboolean more_frags); + +/* to specify how much to reassemble, for fragmentation where last fragment can not be + * identified by flags or such. + * note that for FD_BLOCKSEQUENCE tot_len is the index for the tail fragment. + * i.e. since the block numbers start at 0, if we specify tot_len==2, that + * actually means we want to defragment 3 blocks, block 0, 1 and 2. + * + */ +extern void +fragment_set_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table, + guint32 tot_len); + +/* to resad whatever totlen previously set */ +extern guint32 +fragment_get_tot_len(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* + * This function will set the partial reassembly flag(FD_PARTIAL_REASSEMBLY) for a fh. + * When this function is called, the fh MUST already exist, i.e. + * the fh MUST be created by the initial call to fragment_add() before + * this function is called. Also note that this function MUST be called to indicate + * a fh will be extended (increase the already stored data). After calling this function, + * and if FD_DEFRAGMENTED is set, the reassembly process will be continued. + */ +extern void +fragment_set_partial_reassembly(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* This function is used to check if there is partial or completed reassembly state + * matching this packet. I.e. Are there reassembly going on or not for this packet? + */ +extern fragment_data * +fragment_get(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* This will free up all resources and delete reassembly state for this PDU. + * Except if the PDU is completely reassembled, then it would NOT deallocate the + * buffer holding the reassembled data but instead return the pointer to that + * buffer. + * + * So, if you call fragment_delete and it returns non-NULL, YOU are responsible to + * g_free() that buffer. + */ +extern unsigned char * +fragment_delete(packet_info *pinfo, guint32 id, GHashTable *fragment_table); + +/* hf_fragment, hf_fragment_error, and hf_reassembled_in should be + FT_FRAMENUM, the others should be FT_BOOLEAN +*/ +typedef struct _fragment_items { + gint *ett_fragment; + gint *ett_fragments; + + int *hf_fragments; + int *hf_fragment; + int *hf_fragment_overlap; + int *hf_fragment_overlap_conflict; + int *hf_fragment_multiple_tails; + int *hf_fragment_too_long_fragment; + int *hf_fragment_error; + int *hf_reassembled_in; + + char *tag; +} fragment_items; + +extern tvbuff_t * +process_reassembled_data(tvbuff_t *tvb, int offset, packet_info *pinfo, + char *name, fragment_data *fd_head, const fragment_items *fit, + gboolean *update_col_infop, proto_tree *tree); + +extern gboolean +show_fragment_tree(fragment_data *ipfd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb); + +extern gboolean +show_fragment_seq_tree(fragment_data *ipfd_head, const fragment_items *fit, + proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb); diff --git a/epan/xmlstub.c b/epan/xmlstub.c new file mode 100644 index 0000000000..6ceb9c32be --- /dev/null +++ b/epan/xmlstub.c @@ -0,0 +1,170 @@ +/* xmlstub.c + * Routines to parse XML files using libxml2. This stub + * exists so that the library can be loaded on systems that + * have it. + * + * $Id$ + * + * Copyright (c) 2001 by David Frascone + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998-2001 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +/* XML Stub routines */ +#define IN_XMLSTUB +#include "xmlstub.h" + +/* + * This routine will dynamically load libxml2 and will populate the + * XmlStub pointer structure. + * + * On any error, it will return non-zero, and it should be assumed that + * the current platform does not have dynamic library support, or does + * not have libxml2 installed. + */ +int +loadLibXML(void) +{ + GModule *handle; + gpointer symbol; + int error=FALSE; + + if (XmlStubInitialized) { + /* Did you ever get the feeling you've been here before? */ + + /* + * This is not thread safe. With threads, we'd need to + * synchronize all this so two threads can't initialize at once. + */ + return 0; + } + + /* Check to see if gmodule is supported */ + if (!g_module_supported()) { + g_warning("XMLStub: Modules are not supported. Not initializing XML Stub"); + return (-1); + } + + /* open the dll. Is this named something different + * under windows? Perhaps we should check . . . + */ + if ((handle = g_module_open(XML_LIBRARY, G_MODULE_BIND_LAZY)) == NULL) { + report_failure("XMLStub: Unable to open module " XML_LIBRARY ); + return (-1); + } + + /* + * Now that the library is open, copy all our relevant + * function pointers and integer pointers into our structure. + */ + if (!g_module_symbol(handle, "xmlParseFile", &symbol)) { + g_warning("Unable to find \"xmlParseFile\""); + error=TRUE; + } + XmlStub.xmlParseFile= (xmlDocPtr(*)(const char *))symbol; + + if (!g_module_symbol(handle, "xmlStrcmp", &symbol)) { + g_warning("Unable to find \"xmlStrcmp\""); + error=TRUE; + } + XmlStub.xmlStrcmp= (int (*)(const xmlChar *, const xmlChar *))symbol; + + if (!g_module_symbol(handle, "xmlCreatePushParserCtxt", &symbol)) { + g_warning("Unable to find \"xmlCreatePushParserCtxt\""); + error=TRUE; + } + XmlStub.xmlCreatePushParserCtxt=(xmlParserCtxtPtr (*) + (xmlSAXHandlerPtr, void *, const char *, + int, const char *)) symbol; + + if (!g_module_symbol(handle, "xmlParseChunk", &symbol)) { + g_warning("Unable to find \"xmlParseChunk\""); + error=TRUE; + } + XmlStub.xmlParseChunk=(int (*)(xmlParserCtxtPtr, const char *, int, int))symbol; + + if (!g_module_symbol(handle, "xmlFreeParserCtxt", &symbol)) { + g_warning("Unable to find \"xmlFreeParserCtxt\""); + error=TRUE; + } + XmlStub.xmlFreeParserCtxt=(void (*)(xmlParserCtxtPtr))symbol; + + if (!g_module_symbol(handle, "xmlDocGetRootElement", &symbol)) { + g_warning("Unable to find \"xmlDocGetRootElement\""); + error=TRUE; + } + XmlStub.xmlDocGetRootElement=(xmlNodePtr(*)(xmlDocPtr))symbol; + + if (!g_module_symbol(handle, "xmlFreeDoc", &symbol)) { + g_warning("Unable to find \"xmlFreeDoc\""); + error=TRUE; + } + XmlStub.xmlFreeDoc=(void (*)(xmlDocPtr))symbol; + + if (!g_module_symbol(handle, "xmlNodeListGetString", &symbol)) { + g_warning("Unable to find \"xmlNodeListGetString\""); + error=TRUE; + } + XmlStub.xmlNodeListGetString=(char * (*)(xmlDocPtr, xmlNodePtr, int))symbol; + + if (!g_module_symbol(handle, "xmlGetProp", &symbol)) { + g_warning("Unable to find \"xmlGetProp\""); + error=TRUE; + } + XmlStub.xmlGetProp=(char * (*)(xmlNodePtr, char *))symbol; + + if (!g_module_symbol(handle, "xmlKeepBlanksDefault", &symbol)) { + g_warning("Unable to find \"xmlKeepBlanksDefault\""); + error=TRUE; + } + XmlStub.xmlKeepBlanksDefault=(int(*)(int))symbol; + + if (!g_module_symbol(handle, "xmlSubstituteEntitiesDefault", &symbol)) { + g_warning("Unable to find \"xmlSubstituteEntitiesDefault\""); + error=TRUE; + } + XmlStub.xmlSubstituteEntitiesDefault=(int(*)(int))symbol; + +#ifdef ETHEREAL_XML_DO_VALIDITY_CHECKING + if (!g_module_symbol(handle, "xmlDoValidityCheckingDefaultValue", &symbol)) { + g_warning("Unable to find \"xmlDoValidityCheckingDefaultValue\""); + error=TRUE; + } + XmlStub.xmlDoValidityCheckingDefaultValue = (int *)symbol; +#endif + + /* + * Return if any of the above functions set our error flag. + * A flag was used, instead of returning immediately, so + * that *all* unresolved symbols would be printed. + */ + if (error) { + g_module_close(handle); + return (-1); + } + /* Set our global so that we don't try to load twice */ + XmlStubInitialized=1; + + return 0; /* Success! */ + +} /* loadLibXML */ diff --git a/epan/xmlstub.h b/epan/xmlstub.h new file mode 100644 index 0000000000..47a6d0a0ef --- /dev/null +++ b/epan/xmlstub.h @@ -0,0 +1,1123 @@ +/* + * This is part of tree.h from the libxml2 distribution. It is used + * for structure reference when dynamically linking to libxml. + * + * The GPL agreement for this file and for libxml2 can be found at + * http://www.xmlsoft.org + */ + +#include "config.h" + +/****************** specific to ethereal ********************************/ +/* + * Uncomment the following line to restore XML_DO_VALIDITY_CHECKING + * behavior which is causing issues on WIN32 platforms. See: + * http://www.ethereal.com/lists/ethereal-dev/200410/msg00194.html + */ +/* #define ETHEREAL_XML_DO_VALIDITY_CHECKING */ +/****************** From xml headers ************************************/ + +/* + * use those to be sure nothing nasty will happen if + * your library and includes mismatch + */ +#ifndef LIBXML2_COMPILING_MSCCDEF +extern void xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ +#define LIBXML_DOTTED_VERSION "2.3.8" +#define LIBXML_VERSION 20308 +#define LIBXML_VERSION_STRING "20308" +#define LIBXML_TEST_VERSION xmlCheckVersion(20308); + +/* + * Whether the trio support need to be configured in + */ +#if 0 +#define WITH_TRIO +#else +#define WITHOUT_TRIO +#endif + +/* + * Whether the FTP support is configured in + */ +#if 1 +#define LIBXML_FTP_ENABLED +#else +#define LIBXML_FTP_DISABLED +#endif + +/* + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#else +#define LIBXML_HTTP_DISABLED +#endif + +/* + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#else +#define LIBXML_HTML_DISABLED +#endif + +/* + * Whether the SGML Docbook support is configured in + */ +#if 1 +#define LIBXML_DOCB_ENABLED +#else +#define LIBXML_DOCB_DISABLED +#endif + +/* + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#else +#define LIBXML_XPATH_DISABLED +#endif + +/* + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#else +#define LIBXML_XPTR_DISABLED +#endif + +/* + * Whether XInclude is configured in + */ +#if 1 +#define LIBXML_XINCLUDE_ENABLED +#else +#define LIBXML_XINCLUDE_DISABLED +#endif + +/* + * Whether iconv support is available + */ +#ifdef HAVE_ICONV_H +#define LIBXML_ICONV_ENABLED +#include +#else +#define LIBXML_ICONV_DISABLED +#endif + +/* + * Whether Debugging module is configured in + */ +#if 1 +#define LIBXML_DEBUG_ENABLED +#else +#define LIBXML_DEBUG_DISABLED +#endif + +/* + * Whether the memory debugging is configured in + */ +#if 0 +#define DEBUG_MEMORY_LOCATION +#endif + +#ifndef LIBXML_DLL_IMPORT +#if defined(_WIN32) && !defined(STATIC) +#define LIBXML_DLL_IMPORT __declspec(dllimport) +#else +#define LIBXML_DLL_IMPORT +#endif +#endif + +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include +#endif +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + + +#define XML_XML_NAMESPACE \ + (const xmlChar *) "http://www.w3.org/XML/1998/namespace" + +/* + * The different element types carried by an XML tree + * + * NOTE: This is synchronized with DOM Level1 values + * See http://www.w3.org/TR/REC-DOM-Level-1/ + * + * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should + * be deprecated to use an XML_DTD_NODE. + */ +typedef enum { + XML_ELEMENT_NODE= 1, + XML_ATTRIBUTE_NODE= 2, + XML_TEXT_NODE= 3, + XML_CDATA_SECTION_NODE= 4, + XML_ENTITY_REF_NODE= 5, + XML_ENTITY_NODE= 6, + XML_PI_NODE= 7, + XML_COMMENT_NODE= 8, + XML_DOCUMENT_NODE= 9, + XML_DOCUMENT_TYPE_NODE= 10, + XML_DOCUMENT_FRAG_NODE= 11, + XML_NOTATION_NODE= 12, + XML_HTML_DOCUMENT_NODE= 13, + XML_DTD_NODE= 14, + XML_ELEMENT_DECL= 15, + XML_ATTRIBUTE_DECL= 16, + XML_ENTITY_DECL= 17, + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 +#ifdef LIBXML_DOCB_ENABLED + ,XML_DOCB_DOCUMENT_NODE= 21 +#endif +} xmlElementType; + +/* + * Size of an internal character representation. + * + * We use 8bit chars internal representation for memory efficiency, + * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle + * correctly non ISO-Latin input. + */ + +typedef unsigned char xmlChar; + +#ifndef _WIN32 +#ifndef CHAR +#define CHAR xmlChar +#endif +#endif + +#define BAD_CAST (xmlChar *) + +/* + * a DTD Notation definition + */ + +typedef struct _xmlNotation xmlNotation; +typedef xmlNotation *xmlNotationPtr; +struct _xmlNotation { + const xmlChar *name; /* Notation name */ + const xmlChar *PublicID; /* Public identifier, if any */ + const xmlChar *SystemID; /* System identifier, if any */ +}; + +/* + * a DTD Attribute definition + */ + +typedef enum { + XML_ATTRIBUTE_CDATA = 1, + XML_ATTRIBUTE_ID, + XML_ATTRIBUTE_IDREF , + XML_ATTRIBUTE_IDREFS, + XML_ATTRIBUTE_ENTITY, + XML_ATTRIBUTE_ENTITIES, + XML_ATTRIBUTE_NMTOKEN, + XML_ATTRIBUTE_NMTOKENS, + XML_ATTRIBUTE_ENUMERATION, + XML_ATTRIBUTE_NOTATION +} xmlAttributeType; + +typedef enum { + XML_ATTRIBUTE_NONE = 1, + XML_ATTRIBUTE_REQUIRED, + XML_ATTRIBUTE_IMPLIED, + XML_ATTRIBUTE_FIXED +} xmlAttributeDefault; + +typedef struct _xmlEnumeration xmlEnumeration; +typedef xmlEnumeration *xmlEnumerationPtr; +struct _xmlEnumeration { + struct _xmlEnumeration *next; /* next one */ + const xmlChar *name; /* Enumeration name */ +}; + +typedef struct _xmlAttribute xmlAttribute; +typedef xmlAttribute *xmlAttributePtr; +struct _xmlAttribute { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + struct _xmlAttribute *nexth; /* next in hash table */ + xmlAttributeType atype; /* The attribute type */ + xmlAttributeDefault def; /* the default */ + const xmlChar *defaultValue; /* or the default value */ + xmlEnumerationPtr tree; /* or the enumeration tree if any */ + const xmlChar *prefix; /* the namespace prefix if any */ + const xmlChar *elem; /* Element holding the attribute */ +}; + +/* + * a DTD Element definition. + */ +typedef enum { + XML_ELEMENT_CONTENT_PCDATA = 1, + XML_ELEMENT_CONTENT_ELEMENT, + XML_ELEMENT_CONTENT_SEQ, + XML_ELEMENT_CONTENT_OR +} xmlElementContentType; + +typedef enum { + XML_ELEMENT_CONTENT_ONCE = 1, + XML_ELEMENT_CONTENT_OPT, + XML_ELEMENT_CONTENT_MULT, + XML_ELEMENT_CONTENT_PLUS +} xmlElementContentOccur; + +typedef struct _xmlElementContent xmlElementContent; +typedef xmlElementContent *xmlElementContentPtr; +struct _xmlElementContent { + xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ + xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ + const xmlChar *name; /* Element name */ + struct _xmlElementContent *c1; /* first child */ + struct _xmlElementContent *c2; /* second child */ + struct _xmlElementContent *parent; /* parent */ +}; + +typedef enum { + XML_ELEMENT_TYPE_UNDEFINED = 0, + XML_ELEMENT_TYPE_EMPTY = 1, + XML_ELEMENT_TYPE_ANY, + XML_ELEMENT_TYPE_MIXED, + XML_ELEMENT_TYPE_ELEMENT +} xmlElementTypeVal; + +typedef struct _xmlElement xmlElement; +typedef xmlElement *xmlElementPtr; +struct _xmlElement { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ + const xmlChar *name; /* Element name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlElementTypeVal etype; /* The type */ + xmlElementContentPtr content; /* the allowed element content */ + xmlAttributePtr attributes; /* List of the declared attributes */ + const xmlChar *prefix; /* the namespace prefix if any */ +}; + +/* + * An XML namespace. + * Note that prefix == NULL is valid, it defines the default namespace + * within the subtree (until overriden). + * + * XML_GLOBAL_NAMESPACE is now deprecated for good + * xmlNsType is unified with xmlElementType + */ + +#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL +typedef xmlElementType xmlNsType; + +typedef struct _xmlNs xmlNs; +typedef xmlNs *xmlNsPtr; +struct _xmlNs { + struct _xmlNs *next; /* next Ns link for this node */ + xmlNsType type; /* global or local */ + const xmlChar *href; /* URL for the namespace */ + const xmlChar *prefix; /* prefix for the namespace */ +}; + +/* + * An XML DtD, as defined by parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + void *notations; /* Hash table for notations if any */ + void *elements; /* Hash table for elements if any */ + void *attributes; /* Hash table for attributes if any */ + void *entities; /* Hash table for entities if any */ + const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ + void *pentities; /* Hash table for param entities if any */ +}; + +/* + * A attribute of an XML node. + */ +typedef struct _xmlAttr xmlAttr; +typedef xmlAttr *xmlAttrPtr; +struct _xmlAttr { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ + const xmlChar *name; /* the name of the property */ + struct _xmlNode *children; /* the value of the property */ + struct _xmlNode *last; /* NULL */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlAttr *next; /* next sibling link */ + struct _xmlAttr *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlAttributeType atype; /* the attribute type if validating */ +}; + +/* + * An XML ID instance. + */ + +typedef struct _xmlID xmlID; +typedef xmlID *xmlIDPtr; +struct _xmlID { + struct _xmlID *next; /* next ID */ + const xmlChar *value; /* The ID name */ + xmlAttrPtr attr; /* The attribut holding it */ +}; + +/* + * An XML IDREF instance. + */ + +typedef struct _xmlRef xmlRef; +typedef xmlRef *xmlRefPtr; +struct _xmlRef { + struct _xmlRef *next; /* next Ref */ + const xmlChar *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribut holding it */ +}; + +/* + * A buffer structure + */ + +typedef enum { + XML_BUFFER_ALLOC_DOUBLEIT, + XML_BUFFER_ALLOC_EXACT +} xmlBufferAllocationScheme; + +typedef struct _xmlBuffer xmlBuffer; +typedef xmlBuffer *xmlBufferPtr; +struct _xmlBuffer { + xmlChar *content; /* The buffer content UTF8 */ + unsigned int use; /* The buffer size used */ + unsigned int size; /* The buffer size */ + xmlBufferAllocationScheme alloc; /* The realloc method */ +}; + +/* + * A node in an XML tree. + */ +typedef struct _xmlNode xmlNode; +typedef xmlNode *xmlNodePtr; +struct _xmlNode { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* type number, must be second ! */ + const xmlChar *name; /* the name of the node, or the entity */ + struct _xmlNode *children; /* parent->childs link */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ +#ifndef XML_USE_BUFFER_CONTENT + xmlChar *content; /* the content */ +#else + xmlBufferPtr content; /* the content in a buffer */ +#endif + + /* End of common part */ + struct _xmlAttr *properties;/* properties list */ + xmlNs *nsDef; /* namespace definitions on this node */ +}; + +/* + * An XML document. + */ +typedef struct _xmlDoc xmlDoc; +typedef xmlDoc *xmlDocPtr; +struct _xmlDoc { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ + char *name; /* name/filename/URI of the document */ + struct _xmlNode *children; /* the document tree */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* autoreference to itself */ + + /* End of common part */ + int compression;/* level of zlib compression */ + int standalone; /* standalone document (no external refs) */ + struct _xmlDtd *intSubset; /* the document internal subset */ + struct _xmlDtd *extSubset; /* the document external subset */ + struct _xmlNs *oldNs; /* Global namespace, the old way */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* external initial encoding, if any */ + void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ + const xmlChar *URL; /* The URI for that document */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ +}; + +/** + * Predefined values for some standard encodings + * Libxml don't do beforehand translation on UTF8, ISOLatinX + * It also support UTF16 (LE and BE) by default. + * + * Anything else would have to be translated to UTF8 before being + * given to the parser itself. The BOM for UTF16 and the encoding + * declaration are looked at and a converter is looked for at that + * point. If not found the parser stops here as asked by the XML REC + * Converter can be registered by the user using xmlRegisterCharEncodingHandler + * but the currentl form doesn't allow stateful transcoding (a serious + * problem agreed !). If iconv has been found it will be used + * automatically and allow stateful transcoding, the simplest is then + * to be sure to enable icon and to provide iconv libs for the encoding + * support needed. + */ +typedef enum { + XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ + XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ + XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ + XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ + XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ + XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ + XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ + XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ + XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ + XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ + XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ + XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ + XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ + XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ + XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ + XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ + XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ + XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ + XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ + XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ + XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ + XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ +} xmlCharEncoding; + +/** + * xmlCharEncodingInputFunc: + * @out: a pointer ot an array of bytes to store the UTF-8 result + * @outlen: the lenght of @out + * @in: a pointer ot an array of chars in the original encoding + * @inlen: the lenght of @in + * + * Take a block of chars in the original encoding and try to convert + * it to an UTF-8 block of chars out. + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * as the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of ocetes consumed. + */ +typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen); + + +/** + * xmlCharEncodingOutputFunc: + * @out: a pointer ot an array of bytes to store the result + * @outlen: the lenght of @out + * @in: a pointer ot an array of UTF-8 chars + * @inlen: the lenght of @in + * + * Take a block of UTF-8 chars in and try to convert it to an other + * encoding. + * Note: a first call designed to produce heading info is called with + * in = NULL. If stateful this should also initialize the encoder state + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * as the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of ocetes consumed. + */ +typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen); + + +/* + * Block defining the handlers for non UTF-8 encodings. + * If iconv is supported, there is two extra fields + */ + +typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; +typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; +struct _xmlCharEncodingHandler { + char *name; + xmlCharEncodingInputFunc input; + xmlCharEncodingOutputFunc output; +#ifdef LIBXML_ICONV_ENABLED + iconv_t iconv_in; + iconv_t iconv_out; +#endif /* LIBXML_ICONV_ENABLED */ +}; + +typedef int (*xmlInputMatchCallback) (char const *filename); +typedef void * (*xmlInputOpenCallback) (char const *filename); +typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len); +typedef void (*xmlInputCloseCallback) (void * context); + +typedef struct _xmlParserInputBuffer xmlParserInputBuffer; +typedef xmlParserInputBuffer *xmlParserInputBufferPtr; +struct _xmlParserInputBuffer { + void* context; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 */ + xmlBufferPtr raw; /* if encoder != NULL buffer for raw input */ +}; + + +/* + * Those are the functions and datatypes for the library output + * I/O structures. + */ + +typedef int (*xmlOutputMatchCallback) (char const *filename); +typedef void * (*xmlOutputOpenCallback) (char const *filename); +typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer, + int len); +typedef void (*xmlOutputCloseCallback) (void * context); + +typedef struct _xmlOutputBuffer xmlOutputBuffer; +typedef xmlOutputBuffer *xmlOutputBufferPtr; +struct _xmlOutputBuffer { + void* context; + xmlOutputWriteCallback writecallback; + xmlOutputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ + xmlBufferPtr conv; /* if encoder != NULL buffer for output */ + int written; /* total number of byte written */ +}; + +#define XML_DEFAULT_VERSION "1.0" + +/** + * an xmlParserInput is an input flow for the XML processor. + * Each entity parsed is associated an xmlParserInput (except the + * few predefined ones). This is the case both for internal entities + * - in which case the flow is already completely in memory - or + * external entities - in which case we use the buf structure for + * progressive reading and I18N conversions to the internal UTF-8 format. + */ + +typedef void (* xmlParserInputDeallocate)(xmlChar *); +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; +struct _xmlParserInput { + /* Input buffer */ + xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ + + const char *filename; /* The file analyzed, if any */ + const char *directory; /* the directory/base of teh file */ + const xmlChar *base; /* Base of the array to parse */ + const xmlChar *cur; /* Current char being parsed */ + const xmlChar *end; /* end of the arry to parse */ + int length; /* length if known */ + int line; /* Current line */ + int col; /* Current column */ + int consumed; /* How many xmlChars already consumed */ + xmlParserInputDeallocate free; /* function to deallocate the base */ + const xmlChar *encoding; /* the encoding string for entity */ + const xmlChar *version; /* the version string for entity */ + int standalone; /* Was that entity marked standalone */ +}; + +/** + * the parser can be asked to collect Node informations, i.e. at what + * place in the file they were detected. + * NOTE: This is off by default and not very well tested. + */ +typedef struct _xmlParserNodeInfo xmlParserNodeInfo; +typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; + +struct _xmlParserNodeInfo { + const struct _xmlNode* node; + /* Position & line # that text that created the node begins & ends on */ + unsigned long begin_pos; + unsigned long begin_line; + unsigned long end_pos; + unsigned long end_line; +}; + +typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; +typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; +struct _xmlParserNodeInfoSeq { + unsigned long maximum; + unsigned long length; + xmlParserNodeInfo* buffer; +}; + +/* + * Validation state added for non-determinist content model + */ +typedef struct _xmlValidState xmlValidState; +typedef xmlValidState *xmlValidStatePtr; + +/** + * an xmlValidCtxt is used for error reporting when validating + */ + +typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...); +typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...); + +typedef struct _xmlValidCtxt xmlValidCtxt; +typedef xmlValidCtxt *xmlValidCtxtPtr; +struct _xmlValidCtxt { + void *userData; /* user specific data block */ + xmlValidityErrorFunc error; /* the callback in case of errors */ + xmlValidityWarningFunc warning; /* the callback in case of warning */ + + /* Node analysis stack used when validating within entities */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int finishDtd; /* finished validating the Dtd ? */ + xmlDocPtr doc; /* the document */ + int valid; /* temporary validity check result */ + + /* state state used for non-determinist content validation */ + xmlValidState *vstate; /* current state */ + int vstateNr; /* Depth of the validation stack */ + int vstateMax; /* Max depth of the validation stack */ + xmlValidState *vstateTab; /* array of validation states */ +}; + +typedef struct _xmlLink xmlLink; +typedef xmlLink *xmlLinkPtr; + +typedef struct _xmlList xmlList; +typedef xmlList *xmlListPtr; + +typedef void (*xmlListDeallocator) (xmlLinkPtr lk); +typedef int (*xmlListDataCompare) (const void *data0, const void *data1); +typedef int (*xmlListWalker) (const void *data, const void *user); + +/* + * ALl notation declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlNotationTable; +typedef xmlNotationTable *xmlNotationTablePtr; + +/* + * ALl element declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlElementTable; +typedef xmlElementTable *xmlElementTablePtr; + +/* + * ALl attribute declarations are stored in a table + * there is one table per DTD + */ + +typedef struct _xmlHashTable xmlAttributeTable; +typedef xmlAttributeTable *xmlAttributeTablePtr; + +/* + * ALl IDs attributes are stored in a table + * there is one table per document + */ + +typedef struct _xmlHashTable xmlIDTable; +typedef xmlIDTable *xmlIDTablePtr; + +/* + * ALl Refs attributes are stored in a table + * there is one table per document + */ + +typedef struct _xmlHashTable xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + +/* helper */ +xmlChar * xmlSplitQName2 (const xmlChar *name, + xmlChar **prefix); + +/** + * The parser is now working also as a state based parser + * The recursive one use the stagte info for entities processing + */ +typedef enum { + XML_PARSER_EOF = -1, /* nothing is to be parsed */ + XML_PARSER_START = 0, /* nothing has been parsed */ + XML_PARSER_MISC, /* Misc* before int subset */ + XML_PARSER_PI, /* Whithin a processing instruction */ + XML_PARSER_DTD, /* within some DTD content */ + XML_PARSER_PROLOG, /* Misc* after internal subset */ + XML_PARSER_COMMENT, /* within a comment */ + XML_PARSER_START_TAG, /* within a start tag */ + XML_PARSER_CONTENT, /* within the content */ + XML_PARSER_CDATA_SECTION, /* within a CDATA section */ + XML_PARSER_END_TAG, /* within a closing tag */ + XML_PARSER_ENTITY_DECL, /* within an entity declaration */ + XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ + XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ + XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ + XML_PARSER_EPILOG, /* the Misc* after the last end tag */ + XML_PARSER_IGNORE /* within an IGNORED section */ +} xmlParserInputState; + +/** + * The parser context. + * NOTE This doesn't completely defines the parser state, the (current ?) + * design of the parser uses recursive function calls since this allow + * and easy mapping from the production rules of the specification + * to the actual code. The drawback is that the actual function call + * also reflect the parser state. However most of the parsing routines + * takes as the only argument the parser context pointer, so migrating + * to a state based parser for progressive parsing shouldn't be too hard. + */ +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; +struct _xmlParserCtxt { + struct _xmlSAXHandler *sax; /* The SAX handler */ + void *userData; /* For SAX interface only, used by DOM build */ + xmlDocPtr myDoc; /* the document being built */ + int wellFormed; /* is the document well formed */ + int replaceEntities; /* shall we replace entities ? */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* the declared encoding, if any */ + int standalone; /* standalone document */ + int html; /* an HTML(1)/Docbook(2) document */ + + /* Input stream stack */ + xmlParserInputPtr input; /* Current input stream */ + int inputNr; /* Number of current input streams */ + int inputMax; /* Max number of input streams */ + xmlParserInputPtr *inputTab; /* stack of inputs */ + + /* Node analysis stack only used for DOM building */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int record_info; /* Whether node info should be kept */ + xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ + + int errNo; /* error code */ + + int hasExternalSubset; /* reference and external subset */ + int hasPErefs; /* the internal subset has PE refs */ + int external; /* are we parsing an external entity */ + + int valid; /* is the document valid */ + int validate; /* shall we try to validate ? */ + xmlValidCtxt vctxt; /* The validity context */ + + xmlParserInputState instate; /* current type of input */ + int token; /* next char look-ahead */ + + char *directory; /* the data directory */ + + /* Node name stack */ + xmlChar *name; /* Current parsed Node */ + int nameNr; /* Depth of the parsing stack */ + int nameMax; /* Max depth of the parsing stack */ + xmlChar * *nameTab; /* array of nodes */ + + long nbChars; /* number of xmlChar processed */ + long checkIndex; /* used by progressive parsing lookup */ + int keepBlanks; /* ugly but ... */ + int disableSAX; /* SAX callbacks are disabled */ + int inSubset; /* Parsing is in int 1/ext 2 subset */ + xmlChar * intSubName; /* name of subset */ + xmlChar * extSubURI; /* URI of external subset */ + xmlChar * extSubSystem; /* SYSTEM ID of external subset */ + + /* xml:space values */ + int * space; /* Should the parser preserve spaces */ + int spaceNr; /* Depth of the parsing stack */ + int spaceMax; /* Max depth of the parsing stack */ + int * spaceTab; /* array of space infos */ + + int depth; /* to prevent entity substitution loops */ + xmlParserInputPtr entity; /* used to check entities boundaries */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ + int nodelen; /* Those two fields are there to */ + int nodemem; /* Speed up large node parsing */ + int pedantic; /* signal pedantic warnings */ + void *_private; /* For user data, libxml won't touch it */ + + int loadsubset; /* should the external subset be loaded */ +}; + +/** + * a SAX Locator. + */ +typedef struct _xmlSAXLocator xmlSAXLocator; +typedef xmlSAXLocator *xmlSAXLocatorPtr; +struct _xmlSAXLocator { + const xmlChar *(*getPublicId)(void *ctx); + const xmlChar *(*getSystemId)(void *ctx); + int (*getLineNumber)(void *ctx); + int (*getColumnNumber)(void *ctx); +}; + +/* + * The different valid entity types + */ +typedef enum { + XML_INTERNAL_GENERAL_ENTITY = 1, + XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, + XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, + XML_INTERNAL_PARAMETER_ENTITY = 4, + XML_EXTERNAL_PARAMETER_ENTITY = 5, + XML_INTERNAL_PREDEFINED_ENTITY = 6 +} xmlEntityType; + +/* + * An unit of storage for an entity, contains the string, the value + * and the linkind data needed for the linking in the hash table. + */ + +typedef struct _xmlEntity xmlEntity; +typedef xmlEntity *xmlEntityPtr; +struct _xmlEntity { +#ifndef XML_WITHOUT_CORBA + void *_private; /* for Corba, must be first ! */ +#endif + xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlChar *orig; /* content without ref substitution */ + xmlChar *content; /* content or ndata if unparsed */ + int length; /* the content length */ + xmlEntityType etype; /* The entity type */ + const xmlChar *ExternalID; /* External identifier for PUBLIC */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ + + struct _xmlEntity *nexte; /* unused */ + const xmlChar *URI; /* the full URI as computed */ +}; + +/* + * ALl entities are stored in an hash table + * there is 2 separate hash tables for global and parmeter entities + */ + +typedef struct _xmlHashTable xmlEntitiesTable; +typedef xmlEntitiesTable *xmlEntitiesTablePtr; + +/* + * External functions : + */ + +/** + * a SAX handler is bunch of callbacks called by the parser when processing + * of the input generate data or structure informations. + */ + +typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, + const xmlChar *publicId, const xmlChar *systemId); +typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID); +typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID); +typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, + const xmlChar *name); +typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, + const xmlChar *name); +typedef void (*entityDeclSAXFunc) (void *ctx, + const xmlChar *name, int type, const xmlChar *publicId, + const xmlChar *systemId, xmlChar *content); +typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId); +typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem, + const xmlChar *name, int type, int def, + const xmlChar *defaultValue, xmlEnumerationPtr tree); +typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name, + int type, xmlElementContentPtr content); +typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, + const xmlChar *name, const xmlChar *publicId, + const xmlChar *systemId, const xmlChar *notationName); +typedef void (*setDocumentLocatorSAXFunc) (void *ctx, + xmlSAXLocatorPtr loc); +typedef void (*startDocumentSAXFunc) (void *ctx); +typedef void (*endDocumentSAXFunc) (void *ctx); +typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar **atts); +typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name); +typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name, + const xmlChar *value); +typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name); +typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch, + int len); +typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, + const xmlChar *ch, int len); +typedef void (*processingInstructionSAXFunc) (void *ctx, + const xmlChar *target, const xmlChar *data); +typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value); +typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len); +typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...); +typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...); +typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...); +typedef int (*isStandaloneSAXFunc) (void *ctx); +typedef int (*hasInternalSubsetSAXFunc) (void *ctx); +typedef int (*hasExternalSubsetSAXFunc) (void *ctx); + +typedef struct _xmlSAXHandler xmlSAXHandler; +typedef xmlSAXHandler *xmlSAXHandlerPtr; +struct _xmlSAXHandler { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; +}; + +/** + * External entity loaders types + */ +typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL, + const char *ID, + xmlParserCtxtPtr context); + +/* + * Compatibility naming layer with libxml1 + */ +#ifndef xmlChildrenNode +#define xmlChildrenNode children +#define xmlRootNode children +#endif + + +/*********************Xml routines and function pointers */ +#ifdef IN_XMLSTUB +#define XML_EXTERN +#else +#define XML_EXTERN extern +#endif + +typedef struct { + /* Functions */ + xmlDocPtr (*xmlParseFile)(const char *filename); + int (*xmlStrcmp)(const xmlChar *str1, const xmlChar *str2); + xmlParserCtxtPtr (*xmlCreatePushParserCtxt)(xmlSAXHandlerPtr, void *, const char *, + int, const char *); + int (*xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int); + void (*xmlFreeParserCtxt)(xmlParserCtxtPtr); + xmlNodePtr (*xmlDocGetRootElement)(xmlDocPtr); + void (*xmlFreeDoc)(xmlDocPtr); + char *(*xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int); + char *(*xmlGetProp)(xmlNodePtr, char *); + int (*xmlKeepBlanksDefault)(int); + int (*xmlSubstituteEntitiesDefault)(int); +#ifdef ETHEREAL_XML_DO_VALIDITY_CHECKING + int *xmlDoValidityCheckingDefaultValue; +#endif +} XML_STUB; + +XML_EXTERN XML_STUB XmlStub; +XML_EXTERN int XmlStubInitialized; + +#ifdef _WIN32 +/* We're in windows, use the windows filename */ +#define XML_LIBRARY "libxml2.dll" +#else +#define XML_LIBRARY "libxml2.so" +#endif + +/* + * This needs to be called before the library is used. It + * returns zero on success. Any non-zero return means that + * either dynamic libraries are not supported, or that libxml + * is not installed on the current system. (Or it's not in + * the LD path) + */ +int loadLibXML(void); + + + -- cgit v1.2.3