Erwan Lemonnier

NAME

XML::IDMEF - A module for building/parsing IDMEF messages

QUICK START

Below is an example of an Alert IDMEF message.

  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE IDMEF-Message PUBLIC "-//IETF//DTD RFC XXXX IDMEF v1.0//EN" "idmef-message.dtd">
  <IDMEF-Message>
    <Alert>
      <Analyzer model="myids"/>
      <Target>
        <Node>
          <name>mynode</name>
        </Node>
      </Target>
      <AdditionalData meaning="data2" type="string">value2</AdditionalData>
      <AdditionalData meaning="data1" type="string">value1</AdditionalData>
    </Alert>
  </IDMEF-Message>

The previous IDMEF message can be built with the following code snipset:

    use XML::IDMEF;   

    my $idmef = new XML::IDMEF();  

    $idmef->add("AlertTargetNodename", "mynode");
    $idmef->add("AlertAdditionalData", "value1", "data1"); 
    $idmef->add("AlertAdditionalData", "value2", "data2");
    $idmef->add("AlertAnalyzermodel", "myids");

    print $idmef->out();

To automatically insert an Alert ident tag and set the CreateTime class to the current time, add the 2 lines:

    $idmef->create_ident();
    $idmef->create_time();

and you will get (for example):

  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE IDMEF-Message PUBLIC "-//IETF//DTD RFC XXXX IDMEF v1.0//EN" "idmef-message.dtd">
  <IDMEF-Message>
    <Alert ident="00003EDDDB4F10115110000780D0002">
      <Analyzer model="myids"/>
      <CreateTime ntpstamp="0xc28859cf.0x0">2003-06-04-T11:43:11Z</CreateTime>
      <Target>
        <Node>
          <name>mynode</name>
        </Node>
      </Target>
      <AdditionalData meaning="data2" type="string">value2</AdditionalData>
      <AdditionalData meaning="data1" type="string">value1</AdditionalData>
    </Alert>
  </IDMEF-Message>

DESCRIPTION

IDMEF.pm is an interface for simply creating and parsing IDMEF messages. IDMEF is an XML based protocol designed mainly for representing Intrusion Detection (IDS) alert messages (http://www.silicondefense.com/idwg/).

IDMEF.pm is compliant with IDMEF v1.0, and hence provides calls for building Alert, ToolAlert, CorrelationAlert, OverflowAlert and Heartbeat IDMEF messages.

This API has been designed for simplifying the task of translating a key-value based format to its idmef representation, which is the most common situation when writing a log export module for a given IDS software. A typical session involves the creation of a new IDMEF message, the initialisation of some of its fields and the addition of new IDMEF tags to this message, while parsing some other native message.

An interface to load and parse an IDMEF message is also provided.

The API used in XML::IDMEF is in no way standard. It does not follow any of the SAX or DOM philosophy, since it is neither based on a tree representation nor on an event oriented parser (at least as seen from the outside). It instead gives a linear approach toward the XML object, and uses inbuilt knowledge about a given XML DTD (IDMEF in our case) to make proper choices when building the message. This simplifies the task of building weel formed XML messages, by taking care on your behalf of tasks such as building intermediary nodes in an XML tree, or inserting nodes in the right, DTD compliant order.

This module contains a generic XML DTD parser and includes a simplified node based representation of the IDMEF DTD. It can hence easily be upgraded or extended to support new XML nodes or other DTDs. For information on how to use the XML::IDMEF API with other XML DTDs, read the documentation in the source code :) Yet, beware that the internal DTD representation is a *simplified* DTD, and can not translate all the subtilities that may be defined in XML DTDs. This representation is enough for representing most simple DTDs, such as IDMEF, but not for more complex DTDs. In particular, it considers all attributes as of type CDATA, and does not support complex children ordering and occurence policies.

This code is distributed under the BSD license.

EXPORT

    extend_dtd  
    set_doctype_name
    set_doctype_sysid
    set_doctype_pubid

AUTHOR

Erwan Lemonnier - erwan@cpan.org

Contributor: David Maciejak

LICENSE

This code is released under the BSD license.

SEE ALSO

XML::DOM, XML::Parser

SYNOPSIS

In the following, function calls and function parameters are passed in a perl object-oriented fashion. Hence, some functions (object methods) are said to not take any argument, while they in fact take an IDMEF object as first argument. Refer to the examples in case of confusion. The functions listed at the end (xml_encode, xml_decode, byte_to_string are on the other hand class methods, and should not be called on an IDMEF object.

Rather than returning with non null error codes, these API calls will raise an exception if an error is encountered. These exceptions will either come from XML::DOM or XML::IDMEF, depending on at which level they occured. Exceptions generated by XML::IDMEF are normally caused by you trying to create an XML message that is not a valid IDMEF message. In practice, it means these methods will croak if you try to do something that goes against the IDMEF DTD. So take care of putting all your IDMEF generation code inside 'eval {};' blocks.

OBJECT METHODS

new()

ARGS none.
RETURN

a new empty IDMEF message.

DESC

new creates and returns a new empty but valid IDMEF message, ie containing an xml and a doctype declarations. Use add(), create_ident() and create_time() to add fields to this message.

EXAMPLES
 my $idmef = new XML::IDMEF;

$idmef->in([PATH|STRING])

ARGS

PATH|STRING: either an IDMEF message as a string or a path to a file containing an IDMEF message.

RETURN

the IDMEF object corresponding to this IDMEF message.

DESC

in creates a new IDMEF message from either a string STRING or a file located at the path PATH. If no argument is provided, an empty IDMEF message is created and returned. If the parsed message does not contain any xml or doctype declarations, the missing declarations will be added.

EXAMPLES
 my $idmef = (new XML::IDMEF)->in("idmef.file");
 my $idmef = $idmef->in("<IDMEF-Message/>");

$idmef->out()

ARGS none.
RETURN

a string representing this IDMEF object.

DESC

out returns the IDMEF message as a string.

EXAMPLES
 print $idmef->out;

$idmef->create_ident()

ARGS none.
RETURN nothing.
DESC

create_ident generates a unique IDMEF ident tag and inserts it into this IDMEF message. The tag is generated based on the local time, a random number, the process pid and an internal counter. If the IDMEF message does not yet have a type, it will become 'Alert' by default.

EXAMPLES
 $idmef->create_ident();

$idmef->create_time([$epoch])

ARGS

$epoch: optional. an epoch time (time in secunds since January 1, 1970, UTC).

RETURN nothing.
DESC

create_time sets the IDMEF CreateTime node to the current time (if no epoch argument is provided), or to the time corresponding to the epoch value provided. It sets both the ntpstamp and the UTC time stamps of CreateTime.

EXAMPLES
 $idmef->create_time();

$idmef->get_type()

ARGS none.
RETURN

the type of this IDMEF message, as a string.

DESC

get_type returns the type of this IDMEF message as a string. An 'Alert' IDMEF message would for example return "Alert".

EXAMPLES
 $string_type = $idmef->get_type();

$idmef->add($tagpath, $value)

ARGS

$idmef: a hash representation of an IDMEF message, as received from new or in.

$tagpath: a string obtained by concatenating the names of the nested XML tags, from the Alert tag down to the closest tag to value.

$value: the value (content of a tag, or value of an attribute) of the last tag given in tagpath.

RETURN

0 if the field was correctly added. Otherwise it croaks, because the node you wanted to add goes against the IDMEF DTD. Use 'eval {};' blocks to catch this exceptions.

DESC

Each IDMEF content/value of a given IDMEF message node can be created through an appropriate add() call. A 'tagpath' is a string obtained by concatenating the names of the XML nodes from the top 'Alert' node down to the attribute or content whose value we want to set. Hence, in the example given in introduction, the tagpath for setting the value of the Alert Analyzer model attribute is 'AlertAnalyzermodel'.

The add call was designed for easily building a new IDMEF message while parsing a log file, or any data based on a key-value format.

DISCUSSION

add is used for creating all the nodes along a given tag path, and setting the content of the last node, or one of its attributes. add can also be used to create a new empty IDMEF node by calling add with the appropriate tag path and no value.

When one tag path occurs multiple times in an IDMEF object, the add calls only affects the last one created.

DUPLICATED TAG PATH

add cannot be used to change the value of an already existing content or attribute. If you run add on an attribute that already exists, XML::IDMEF will try to duplicate one of the parent nodes of the attribute, and set the attribute to the new node hence created. If the IDMEF DTD does not allow this node path to be duplicated, XML::IDMEF croaks. The same stands true when trying to add a content to a node path where the node already has a content. XML::IDMEF will try to duplicate this node path.

SPECIAL CASE: AdditionalData

AdditionalData is a special tag requiring at least 2 add() calls to build a valid node. In case of multiple AdditionalData delarations, take care of building AdditionalData nodes one at a time.

As a response to this issue, the 'add("AlertAdditionalData", "value")' call accepts an extended syntax compared with other calls:

   add("AlertAdditionalData", <value>);   
      => add the content <value> to Alert AdditionalData

   add("AlertAdditionalData", <value>, <meaning>); 
      => same as:  (type "string" is assumed by default)
         add("AlertAdditionalData", <value>); 
         add("AlertAdditionalDatameaning", <meaning>); 
         add("AlertAdditionalDatatype", "string");

   add("AlertAdditionalData", <value>, <meaning>, <type>); 
      => same as: 
         add("AlertAdditionalData", <value>); 
         add("AlertAdditionalDatameaning", <meaning>); 
         add("AlertAdditionalDatatype", <type>);

The use of add("AlertAdditionalData", <arg1>, <arg2>, <arg3>) is prefered to the simple add call, since it creates the whole AdditionalData node at once. In the case of multiple arguments add("AlertAdditionalData"...), the returned value is 1 if the type key was inserted, 0 otherwise.

EXAMPLES
 my $idmef = new XML::IDMEF();

 $idmef->add("Alertimpact", "<value>");     

 $idmef->add($idmef, "AlertTargetUserUserIdname", "<value>");

 # AdditionalData case:
 # DO:
 $idmef->add("AlertAdditionalData", "value");           # creating first AdditionalData node
 $idmef->add("AlertAdditionalDatatype", "string");      
 $idmef->add("AlertAdditionalDatameaning", "meaning");  

 $idmef->add("AlertAdditionalData", "value2");          # creating second AdditionalData node
 $idmef->add("AlertAdditionalDatatype", "string");      
 $idmef->add("AlertAdditionalDatameaning", "meaning2"); 

 # or BETTER:
 $idmef->add("AlertAdditionalData", "value", "meaning", "string");  
 $idmef->add("AlertAdditionalData", "value2", "meaning2");          

$idmef->set($tagpath, $value)

ARGS

$idmef: a hash representation of an IDMEF message, as received from new or in.

$tagpath: a string obtained by concatenating the names of the nested XML tags, from the Alert tag down to the closest tag to value, and leading to either a valid IDMEF attribute or a valid content node.

$value: the value (content of a tag, or value of an attribute) of the last tag given in tagpath.

RETURN

0 if the field was correctly changed. Otherwise it croaks, because the node you wanted to add goes against the IDMEF DTD. Use 'eval {};' blocks to catch this exceptions.

DESC

The set() call follows the first occurence of the node path described by <tagpath> and attempts at changing the corresponding content or attribute value. If the first occurence of <tagpath> does not lead to any existing node or attribute, set() croaks. Check first with contains() that the node or attribute exists. If you want to create an attribute value or a node content where there was none, use add() and not set().

RESTRICTIONS

set() only allows you to reach and change the attribute or content of the first occurence of a given tagpath (ie the last one created). If this tagpath occurs multiple time, you will not be able to modify the other occurences. Yet this should be able for most applications. Furthermore, set() cannot be used to create any new value/content.

EXAMPLES
 my $idmef = new XML::IDMEF();

 $idmef->add("AlertAdditionalData", "value");           # content add first
 $idmef->add("AlertAdditionalDatatype", "string");      # ok
 $idmef->add("AlertAdditionalDatameaning", "meaning");  # ok

 # change AdditionalData's content value
 $idmef->set("AlertAdditionalData", "new value");

$idmef->get($tagpath)

ARGS

$idmef: a hash representation of an IDMEF message, as received from new or in.

$tagpath: a string obtained by concatenating the names of the nested XML tags, from the Alert tag down to the closest tag to value, and leading to either a valid IDMEF attribute or a valid content node.

RETURN

a string: the content of the node or value of the attribute, undef if there is no such value, and croaks if error.

DESC

The get() call follows the first occurence of the node path described by $tagpath and attempts at retrieving the corresponding content or attribute value. If the first occurence of $tagpath does not lead to any existing node, get() returns undef. But this does not mean that the value does not exists in an other occurence of the pagpath.

get() only allows you to reach and retrieve the attribute or content of the first occurence of a given tagpath. If this tagpath occurs multiple time, you will not be able to retrieve the other occurences. Yet this should be able for most applications.

EXAMPLES
 my $idmef = new XML::IDMEF();

 $idmef->add("AlertAdditionalData", "value", "meaning"); 

 # get AdditionalData's content value
 $idmef->get("AlertAdditionalData");

$idmef->contains($tagpath)

ARGS

$tagpath: a tagpath (see add).

RETURN

1 if there exists in this idmef message a value associated to the given tagpath. 0 otherwise.

DESC

contains is a test function, used to determine whether a value has already been set at a given tagpath.

$idmef->to_hash()

ARGS none.
RETURN

the IDMEF message flattened inside a hash.

DESC

to_hash returns a hash enumerating all the contents and attributes of this IDMEF message. Each key is a concatenated sequence of XML tags (a 'tagpath', see add()) leading to the content/attribute, and the corresponding value is an array containing the content/attribute itself. In case of multiple occurences of one 'tagpath', the corresponding values are listed as elements of the array (See the example).

EXAMPLES
 <IDMEF-message version="0.5">
   <Alert ident="myalertidentity">
     <Target>
       <Node category="dns">
         <name>node2</name>
       </Node>
     </Target>
     <AdditionalData meaning="datatype1">data1</AdditionalData>
     <AdditionalData meaning="datatype2">data2</AdditionalData>
   </Alert>
 </IDMEF-message>
 
 becomes:
  
 { "version"                    => [ "0.5" ],
   "Alertident"                 => [ "myalertidentity" ],
   "AlertTargetNodecategory"    => [ "dns" ],
   "AlertTargetNodename"        => [ "node2" ],
   "AlertAdditionalDatameaning" => [ "datatype1", "datatype2" ],   # meaning & contents are
   "AlertAdditionalData"        => [ "type1", "type2" ],           # listed in same order
 }

CLASS METHODS

COMMENT

The following class methods are designed to access the DTD and XML engine on top of which XML::IDMEF is built. These calls allows you to use the XML::IDMEF API calls to generate/parse other XML formats than IDMEF, by loading a given DTD representation into XML::IDMEF and changing the corresponding DOCTYPE declarations. Avoid using these calls if you can, as they are little documented and subject to changes. No support will be provided on how to use them, and the documentation lies in the source code :)

set_doctype_name($string)

ARGS

$string: a DOCTYPE name

DESC

Sets the name field in the XML DOCTYPE declaration of XML messages generated by XML::IDMEF. 'IDMEF-Message' is the default.

set_doctype_sysid($string)

ARGS

$string: a DOCTYPE system ID

DESC

Sets the system ID field in the XML DOCTYPE declaration of XML messages generated by XML::IDMEF. 'idmef-message.dtd' is the default.

set_doctype_pubid($string)

ARGS

$string: a DOCTYPE public ID

DESC

Sets the public ID field in the XML DOCTYPE declaration of XML messages generated by XML::IDMEF. '-//IETF//DTD RFC XXXX IDMEF v1.0//EN' is the default.

extend_dtd($IDMEF-class, $Extended-subclass)

ARGS

$IDMEF-class: a pseudo representation of an XML DTD that either extands IDMEF or represent a completly different XML protocol.

$Extended-subclass: the name of the new DTD's root. 'IDMEF-Message' is the default if no value provided.

RETURN nothing. croaks if the provided pseudo-DTD contains incoherencies.
DESC

extend_dtd is used to extend the IDMEF DTD by changing the definition of some IDMEF nodes and/or adding newnodes. It can also be used to load a completly new DTD representation in XML::IDMEF's XML engine, hence making it possible to use the XML::IDMEF API to generate and parse other XML formats then IDMEF. Internally, the IDMEF.pm module is built around a DTD parser, which reads an XML DTD (written in a proprietary but straightforward format) and provides calls to build and parse XML messages compliant with this DTD. This DTD parser and its API could be used for (almost) any other XML format than IDMEF, provided that the appropriate DTD gets loaded in the module, and that the DTD can be represented in the pseudo-DTD format used internally by the module. The format of the pseudo-DTD representation is complex and subject to changes. Yet, if you really wish to use these functionalities, you will find proper documentation in the module source code.

Example: to add a new node called hexdata to the AdditionalData node, do:

    my $ext_dtd = {
        "AdditionalData" => {
            ATTRIBUTES  => { "type" => ["string", "boolean", "byte", "character", 
                                        "date-time", "integer", "ntpstamp",
                                        "portlist", "real", "xml"],
                             "meaning" => [],
                           },
            CONTENT     => ANY,
            CHILDREN    => ["hexdata"],
        }, 
        "hexdata"        => { CONTENT => PCDATA },
    };
    extend_dtd($ext_dtd, "IDMEF-Message");

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 2145:

You forgot a '=back' before '=head2'

Around line 2507:

You forgot a '=back' before '=head2'