$Id: modules_howto.txt,v 1.3 2005/06/26 11:23:20 mederchik Exp $

This document describes how to add your own module to xprobe

Xprobe2 Modules Howto
---------------------

To write a module for xprobe2, do following:

create a class which will inherit Xprobe_module:

#include "xprobe.h"
#include "xprobe_module.h"
#include "xprobe_module_hdlr.h"
#include "target.h"
#include "interface.h"
#define _XPROBE_MODULE
#include "xplib.h"

class Your_Module: public Xprobe_Module {
    private:
		void generate_signature(Target *, ICMP *, ICMP *)
		/* or
		void generate_signature(Target *, TCP *, TCP *) */
    public:
        Test_Mod(void) : Xprobe_Module(XPROBE_MODULE_ALIVETEST, "YOUR_MODULE NAME") { /*your constructor*/ }
        
        /* or just 
        Test_Mod(void) : Xprobe_Module("YOUR_MODULE NAME")  { your constructor } */
        ~Test_Mod(void) { return; }
        int init(void);
        int parse_keyword(int os_id, char *keyword, char *value);
        int exec(Target *tg, OS_Matrix *os);
        int fini(void);
};


the first argument in constructor signifies type of function which your
module is going to perform. "ALIVETESTS" are modules which testify
remote system reachability. "OSTESTS" - modules which do actual
fingerprinting.

and create following function:

int your_module_init(Xprobe_Module_Hdlr *pt) {

    int mod_id;
    Your_Module *mod = new Your_Module;

    xprobe_mdebug(XPROBE_DEBUG_MODULES, "Initializing the YOUR_MODULE module\n");
    pt->register_module(mod);
    /* keywords which you will be parsing in parse_keyword routine */
    pt->add_keyword(mod->get_id(), "keyword1");
    pt->add_keyword(mod->get_id(), "keyword2");
    pt->add_keyword(mod->get_id(), "keyword3");

return OK;
}

Following methods of class you will have to write yourself:

init()
------
init() -- prepare all the data, sockets whatever you will need to use.

parse_keywords()
----------------
parse_keywords(int os_id, char *keyword, char *value); we will call it if we see
keywords which you registered for your module, appearing for OS
fingerprint with id OS_ID. You will suppose to parse the keyword and
store the result in internal format (whichever you wish to choose) which
will represent OS-id, your test results according to the keyword, you
parsed for this OS, and score, which ranks how the given 'fingerprint'
matches the signature if the test results match. Possible variants for
the score are:
XPROBE_MATCH_YES, XPROBE_MATCH_NO, XPROBE_MATCH_PROBABLY_YES, XPROBE_MATCH_PROBABLY_NO

exec()
------
exec(Target *tg, OS_Matrix *os)-- you  perform your tests
against the target here, and then submit us results, how much each OSid,
which you saw/parsed signature for, matches the target which you examined.
use follwing function to do that:

OS_Matrix->add_result(this->get_id(), int OS_id,int score);

All the information regarding target system you obtain through a class
'Target' (see target.h for details), more over the communications with
the core system you perform through target methods as well. You should
be able to get all the data you need, if missing something, let me know.

Here are the most useful functions:

tg->get_addr() -- returns in_addr struct of target
tg->get_interface() -- returns char ptr to interface name
tg->get_inetface_addr() - returns address of the interface through which
you connect to the target.
tg->get_port(IPPROTO_TCP, XPROBE_TARGETP_OPEN) (or CLOSED, or FILTERED)
-- will give you a port number (or -1 if unknown) which you asked for.

you can also use tg->add_port() to set port status, if you found it
during the test.

tg->get_distance() and tg->set_distance() will return or set (for use of other
modules) ttl distance to the target system.

tg->get_ttl(type) - returns ttl for particular type of packet (if
known). See target.h for pre-defined types (tcp syn+ack, tcp rst, etc)

tg->set_ttl(type, ttl) - sets ttl for particular type of packet.

*Note:
 for reachability tests modules, OS_id, should always be 1. As we don't
have signatures to be parsed. parse_keywords() routine should be dummy
and you don't have to register any particular keywords unless you
expect parameters from config file.

**Note:
If your module has keywords that would only have meaning if one of the keywords
is set to specific value, as in following example:

	icmp_addrmask_reply = n
	icmp_addrmask_reply_ttl = <255
	icmp_addrmask_reply_ip_id = !0

'icmp_addrmask_reply_ttl' and 'icmp_addrmask_reply_ip_id' depend on the value of
'icmp_addrmask_reply'. So if accoring to the fingerprint the should be no reply
from the target, module has to generate two additional matches using:

OS_Matrix::add_result()

in order for target to get 100% match

fini()
------

deallocate all the memory which you allocated here. Close all the
sockets. Clean up everything. Destructor for your module will be called
right after. You don't have to delete your module object instance
itself, which you allocated in init function, we will do that for you.

generate_signature()
--------------------

private method that will generate signature for the given target, in
your exec() method, you need to check bool Target->generate_sig(), if
method returns true then you need to generate signature (i.e. call
generate_signature() method, where using one of following Target
methods:
		void signature(string& key, string& val);
		void signature(const char *, const char *);

you add keyword-value pairs to the Target object).

User Interface
--------------

Currently only command line/text interface is implemented. However for
further compatibility we have Interface() class which has particular
methods to output the data. We insist on using these in your code.

Later other interfaces might be developed (or you could develop these
yourself) this will save the hassle of porting your module to every new
interface.

Declare following:
extern Interface *ui;

use our user interface routines to generate output:

xprobe_debug(XPROBE_DEBUG_MODULES, "fmt string: %s", arg); to print
debug messages.
xprobe_mdebug(XPROBE_DEBUG_MODULES, "something"); to print single string
debug messages.

ui->msg("message: %s", args); to print messages (prefix them with [x] [module])
ui->log("something"); to log data
ui->error("...", blah); to report errors..
ui->perror("something"); use instead of perror();
ui->verbose(verbosity_level, "msg",..) -- (controlled with -v option,
1,2,3 .. are possible levels)



Compilation
-----------

to include the module into our source you have to do following:

1) add your init function ot xpmodules/static_modules.h like this:


...
typedef int(* xprobe_module_init_t)(Xprobe_Module_Hdlr *);

xprobe_module_init_t mod_init_funcs[]= {
    test_mod_init, 
    your_module_init,
    NULL};


2) place your module into:
    alive_probe directory (create subdirectory if you care, there).
Create Makefile.in to compile your modules and edit
xpmodules/Makefile.in to link your objects to modules.a library
file. You can create your own archive of objects with ar, just don't run
runlib on it and let us add your achive to ours.

3) test that everything builds properly. Send me complains if it doesn't
;-)
