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 --- Makefile.common | 7 +- asn1.c | 1085 --------------------- asn1.h | 150 --- 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 +++++++++++++++++++++ follow.c | 336 ------- follow.h | 57 -- gtk/follow_dlg.c | 2 +- plugins/asn1/packet-asn1.c | 2 +- plugins/plugin_api.h | 4 +- plugins/plugin_api_list.c | 4 +- ptvcursor.c | 116 --- ptvcursor.h | 80 -- reassemble.c | 1833 ----------------------------------- reassemble.h | 244 ----- xmlstub.c | 170 ---- xmlstub.h | 1123 --------------------- 75 files changed, 5265 insertions(+), 5265 deletions(-) delete mode 100644 asn1.c delete mode 100644 asn1.h 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 delete mode 100644 follow.c delete mode 100644 follow.h delete mode 100644 ptvcursor.c delete mode 100644 ptvcursor.h delete mode 100644 reassemble.c delete mode 100644 reassemble.h delete mode 100644 xmlstub.c delete mode 100644 xmlstub.h diff --git a/Makefile.common b/Makefile.common index 4adc7dfa7a..d47c72d02d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -28,11 +28,9 @@ DISSECTOR_SUPPORT_INCLUDES = \ aftypes.h \ arcnet_pids.h \ - asn1.h \ bridged_pids.h \ chdlctypes.h \ etypes.h \ - follow.h \ format-oid.h \ greproto.h \ iax2_codec_type.h \ @@ -43,14 +41,11 @@ DISSECTOR_SUPPORT_INCLUDES = \ nlpid.h \ oui.h \ ppptypes.h \ - ptvcursor.h \ - reassemble.h \ rpc_defrag.h \ rtp_pt.h \ sctpppids.h \ smb.h \ - x264_prt_id.h \ - xmlstub.h + x264_prt_id.h # "BUILT_SOURCES" are built before any "make all" or "make check" targets. BUILT_SOURCES = \ diff --git a/asn1.c b/asn1.c deleted file mode 100644 index 8edd59bcb8..0000000000 --- a/asn1.c +++ /dev/null @@ -1,1085 +0,0 @@ -/* 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 "asn1.h" - -/* - * 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/asn1.h b/asn1.h deleted file mode 100644 index 5d751ff7fd..0000000000 --- a/asn1.h +++ /dev/null @@ -1,150 +0,0 @@ -/* 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/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); + + + diff --git a/follow.c b/follow.c deleted file mode 100644 index 19e14303b2..0000000000 --- a/follow.c +++ /dev/null @@ -1,336 +0,0 @@ -/* 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/follow.h b/follow.h deleted file mode 100644 index 013519d43e..0000000000 --- a/follow.h +++ /dev/null @@ -1,57 +0,0 @@ -/* 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/gtk/follow_dlg.c b/gtk/follow_dlg.c index 3c37663678..7055e31201 100644 --- a/gtk/follow_dlg.c +++ b/gtk/follow_dlg.c @@ -46,7 +46,7 @@ #include "colors.h" #include "file.h" #include "follow_dlg.h" -#include "follow.h" +#include #include "dlg_utils.h" #include "keys.h" #include "globals.h" diff --git a/plugins/asn1/packet-asn1.c b/plugins/asn1/packet-asn1.c index 9f78479d52..0d94a87cb6 100644 --- a/plugins/asn1/packet-asn1.c +++ b/plugins/asn1/packet-asn1.c @@ -84,7 +84,7 @@ #include #include #include -#include "asn1.h" +#include #include "plugins/plugin_api_defs.h" diff --git a/plugins/plugin_api.h b/plugins/plugin_api.h index 238fa6bb2a..d99d5ff627 100644 --- a/plugins/plugin_api.h +++ b/plugins/plugin_api.h @@ -45,13 +45,13 @@ #include #include #include -#include "reassemble.h" +#include #include #include #include #include #include -#include "asn1.h" +#include #include #include #include diff --git a/plugins/plugin_api_list.c b/plugins/plugin_api_list.c index f88993af66..4a2aef7760 100644 --- a/plugins/plugin_api_list.c +++ b/plugins/plugin_api_list.c @@ -32,7 +32,7 @@ #include #include #include -#include "reassemble.h" +#include #include #include #include @@ -43,7 +43,7 @@ #include #include #include -#include "asn1.h" +#include #include #include diff --git a/ptvcursor.c b/ptvcursor.c deleted file mode 100644 index cde56022f0..0000000000 --- a/ptvcursor.c +++ /dev/null @@ -1,116 +0,0 @@ -/* 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/ptvcursor.h b/ptvcursor.h deleted file mode 100644 index 6467bcdea9..0000000000 --- a/ptvcursor.h +++ /dev/null @@ -1,80 +0,0 @@ -/* 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/reassemble.c b/reassemble.c deleted file mode 100644 index 4d968a95d0..0000000000 --- a/reassemble.c +++ /dev/null @@ -1,1833 +0,0 @@ -/* 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 "reassemble.h" - -#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/reassemble.h b/reassemble.h deleted file mode 100644 index 85c66942c9..0000000000 --- a/reassemble.h +++ /dev/null @@ -1,244 +0,0 @@ -/* 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/xmlstub.c b/xmlstub.c deleted file mode 100644 index 6ceb9c32be..0000000000 --- a/xmlstub.c +++ /dev/null @@ -1,170 +0,0 @@ -/* 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/xmlstub.h b/xmlstub.h deleted file mode 100644 index 47a6d0a0ef..0000000000 --- a/xmlstub.h +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * 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