netl_module - netl API.
netl modules allow a user with a pretty basic understanding of C write
his own additions to netl , while relying on the existing power of the
netl API. there are currently three types of netl modules, and
they shall be described in the following sections, but they all have a
few attributes in common which will be described here. the netl
distribution comes with a number of modules, which you will likely want
to look at. netl by default relies rather heavily on modules in the
netl distribution.
a netl module is just a dynamic object file (.so) similar to the
dynamic libraries that you file in your library directories
(/lib/libc.so.6.1) for example. netl decides at run time which
modules need to be loaded by reading the configuration file (see
netl.conf (5) ) or by command line rules (see netl (8) ), and then
executes the appropriate action based on that configuration.
a .so file can be created by creating a C module, and compiling it using
the gcc (1) -shared option. depending on the module type, there will
need to be various subroutines defined. any module (regardless of type)
may define functions which take no arguments construct() and destruct().
these functions will be called when the module is loaded and deallocated
respectively.
if you have perl, then you can use the netlcc (1) front end to compile
netl modules. if installed correctly, you can give it a netl module
source code without having to know where the various libraries and header
files are located on the system.
by default, netl (8) will search the directly /usr/local/lib/netl for
modules (you can specify a different directly with the -L option). once
you have created a netl module, you will likely want to move it into
there so that it can be automatically loaded.
a netl process will always have exactly one input module when running.
this is the code which actually grabs the packets from the network so
that they can then be filtered and dealt configuration file. when
porting netl to a new system, one will typically only have to write a
new input module, as the rest of the code is fairly portable ANSI C.
a netl input module must define at least two functions:
void
prepare (char *dev)
this code (if necessary) will prepare the device for later reading.
typically, this routine will place the promiscuous mode.
int
grab (char *buf)
this code actually grabs the ethernet frame from the network and writes
it into the buffer *buf. *buf will be allocated by the netl system to be
large enough for your typical ethernet frame.
a good example of a netl input module is the linux-ether input module
which comes with the netl distribution. it is a working
implementation for linux. all input modules must be put in a directory
called `in' under the directory where netl searches for modules.
typically this means /usr/local/lib/netl/in.
a filter module decides if the ethernet frame passed to it is worthy of
note. this is how the protocol filters are implemented. you can program
you filter to do with the packet as you please (e.g. directly log to
syslogd or dump to a file), but a better design would be to pass the
packet (if it is a `hit') to the output module specified by the
particular rule.
when loading a user netl filter module, you will have to prefix it with
an ampersand ('&') character to indicate that it is not an `official'
module. some of the modules netl ships with are in this state, not
because they are defective, but because they haven't been implemented by
the compiler (for more information on the compiler, see netlcc (1) ).
a filter module should include (in this order) these header files which
come with the netl distribution: netl/global.h netl/ether.h netl/ip.h
netl/config.h
a filter module should also have a structure of type configlist called
req, which most likely can be ignored. this structure is largely used
for protocol filters only.
void check (u8 *dg, size_t len) is where the packet gets sent. u8 * is
a eight bit integer pointer, and dg is the pointer to the datagram. len
is the actual length of the datagram.
all filter modules must be placed in a directory called `filt' under the
directory where netl searches for modules. typically this means
/usr/local/lib/netl/filt.
here is an example module which logs pings and pongs (a pong is my
private term for an ICMP_ECHOREPLY which is what gets sent back to you
when you ping a host).
to compile this module,
% netlcc ping.c
and then copy it into the module directory at the correct place.
% cp ping.so /usr/local/lib/netl/filt
and you can try it out by running (as root) netl thus:
# netl -z 'null &ping'
here is a more complicated module, which i use on my system.
notice the use of structures such as iphdr, udphdr and the like. it is
useful to take a look at netl/ip.h as this contains most of the
structures useful for IPv4.
the last type of module is used for output. once the packet has been
deemed interesting by whatever filter module, it is passed to an output
module. once again, output modules must live in a directory called `out'
where ever netl is searching for modules. this is usually
/usr/local/lib/netl/out.
a netl output module is sometimes also refered to an action module, since
the output modules are the ones which actually act once a packet has been
filtered.
when loading a user netl action module, you will have to prefix it with
an at sign ('@') character to indicate that it is not an `official'
module. some of the modules netl ships with are in this state, not
because they are defective, but because they haven't been implemented by
the compiler (for more information on the compiler, see netlcc (1) ).
possible uses for this type of module include an X interface which sends
pop up messages to a user when someone is trying to hack into his machine.
this is just an idea.
an output module should define an integer action_done which is used by
the protocol filters to keep it from logging or dumping a particular
frame more than once, while allowing a frame to be logged and dumped by
different rules. in general, set action_done to TRUE immediately when
action () is called.
void action (u8 *dg, struct configitem *cf, size_t len) is called
directly by whichever filter module is in use. once again, dg is the
pointer to the datagram and len is the length of that datagram. cf is a
pointer to a config item which can for the most part be ignored. the one
useful portion of the configitem is the member logname which is the
requirement name= you specified in the configuration file (see
netl.conf (5) ). cf->logname is the desired value.
there are copious examples that come with the netl distribution, but
none really worth going over at the moment.
netl (8) , netl.conf (5) , netlcc (1) , netl_install (1) ,
netl_module (1) , neta (1) , hwpassive (8) , hwlookup (1) ,
dcp (1) and xd (1)
there are almost certainly bugs, please report them to me. send bugs and
bug fixes to netl@netl.org. the netl home page is at
http://www.netl.org,which should contain up to date information on
netl .
i have attempted to write pretty readable documentation, however, i'm not
really the best technically writer. if you are, maybe we could
colaborate?
Copyright 1996, 1997, 1999 Graham THE Ollis
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.
Graham THE Ollis You can contact the netl team at netl@netl.org.
NAME
DESCRIPTION
INPUT MODULE
FILTER MODULE
/*==============================================================================
| ping
| log pings (ICMP_ECHO) and pongs (ICMP_ECHOREPLY)
|
| Copyright (C) 1997 Graham THE Ollis <ollisg@netl.org>
|
| 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.
|=============================================================================*/
#include <stdio.h>
#include "netl/global.h"
#include "netl/filter.h"
#include "netl/ether.h"
#include "netl/ip.h"
#include "netl/action.h"
#include "netl/config.h"
#include "netl/io.h"
#include "netl/resolve.h"
struct configlist req;
/*==============================================================================
| check icmp
|=============================================================================*/
void
check(u8 *dg, size_t len)
{
iphdr *ip = (iphdr *) &dg[14];
icmphdr *h = (icmphdr *) &dg[(ip->ihl << 2) + 14];
if(((machdr*)dg)->type != MACTYPE_IPDG)
return;
if(ip->version != IP_VERSION)
return;
if(ip->protocol != PROTOCOL_ICMP)
return;
if(h->type == 8)
log("ping %s => %s", ip2string(ip->saddr), ip2string(ip->daddr));
if(h->type == 0)
log("pong %s => %s", ip2string(ip->saddr), ip2string(ip->daddr));
}
/*==============================================================================
| gnr
| stadard rules for the Graham New Republic
|
| Copyright (C) 1997 Graham THE Ollis <ollisg@netl.org>
|
| 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.
|=============================================================================*/
#include <stdio.h>
#include "netl/global.h"
#include "netl/filter.h"
#include "netl/ether.h"
#include "netl/ip.h"
#include "netl/action.h"
#include "netl/config.h"
#include "netl/io.h"
#include "netl/resolve.h"
struct configlist req;
#define mynet 0x0a0a0a00
/*==============================================================================
| check icmp
|=============================================================================*/
void
check(u8 *dg, size_t len)
{
iphdr *ip = (iphdr *) &dg[14];
union { icmphdr i; tcphdr t; udphdr u; } *h = (void *) &dg[(ip->ihl << 2) + 14];
u32 us = searchbyname("local");
if(((machdr*)dg)->type != MACTYPE_IPDG)
return;
if(ip->version != IP_VERSION)
return;
if(ip->daddr != us)
return;
if((ntohl(ip->saddr) & mynet) == mynet)
return;
if(ip->protocol == PROTOCOL_ICMP) {
if(h->i.type == 8)
log("ping %s => %s", ip2string(ip->saddr), ip2string(ip->daddr));
if(h->i.type == 0)
log("pong %s => %s", ip2string(ip->saddr), ip2string(ip->daddr));
}
else if(ip->protocol == PROTOCOL_UDP) {
if(ntohs(h->u.dest) >= 33434)
log("traceroute %s => %s (%d)", ip2string(ip->saddr), ip2string(ip->daddr), ntohs(h->u.dest));
}
else if(ip->protocol == PROTOCOL_TCP &&
h->t.fin == 0 &&
h->t.syn == 1 &&
h->t.rst == 0 &&
h->t.psh == 0 &&
h->t.ack == 0 &&
h->t.urg == 0) {
char *prot;
switch(ntohs(h->t.dest)) {
case 21 : prot = "ftp"; break;
case 22 : prot = "ssh"; break;
case 23 : prot = "telnet"; break;
case 25 : prot = "smtp"; break;
case 70 : prot = "gopher"; break;
case 79 : prot = "finger"; break;
case 80 : prot = "www"; break;
case 109: prot = "pop2"; break;
case 110: prot = "pop3"; break;
case 113: prot = "auth"; break;
default :
if(h->t.source)
prot = "ftp reply";
else
prot = "unknown_tcp";
break;
}
log("%s %s:%d => %s:%d", prot,
ip2string(ip->saddr),
ntohs(h->t.source),
ip2string(ip->daddr),
ntohs(h->t.dest));
}
else if(ip->protocol == PROTOCOL_TCP &&
h->t.fin == 1 &&
h->t.syn == 0 &&
h->t.rst == 0 &&
h->t.psh == 0 &&
h->t.ack == 0 &&
h->t.urg == 0) {
log("fin %s:%d => %s:%d",
ip2string(ip->saddr),
ntohs(h->t.source),
ip2string(ip->daddr),
ntohs(h->t.dest));
}
else if(ip->protocol == PROTOCOL_TCP) {
/* nothing */
}
else if(ip->protocol == PROTOCOL_IGNP) {
log("ignp %s => %s",
ip2string(ip->saddr),
ip2string(ip->daddr));
}
else {
log("unknown %s => %s",
ip2string(ip->saddr),
ip2string(ip->daddr));
}
}
OUTPUT MODULE
SEE ALSO
BUGS
COPYING
AUTHOR
Contact Information
1999 CORE software international