|
|
Contents
- Iptables Basics
- Using Ethereal
- File Hierarchy
- Template for User-space Extension
- Example 1: The simplest ipqueue
- Example 2: A quick way to build a user-space
extension
- Useful Tools and References
- Notes
- Iptables Basics
A good reference is the man page, you can get the answers
by using "man iptables" or "iptables
-h" in many cases.
For tutorials on netfilter/iptables, please refer to the tutorial
section on netfilter offical web page.
- Using Ethereal
- Run Ethereal.
- Set up a capture.
Menu -> Capture -> Start
Choose Interface: any / lo / eth0 / ...
Set Filter: type, for example,"icmp and host 127.0.0.1" in the filter field
Set Display Options: real time update / auto-scroll
OK
|
|
- File Hierarchy
$(ROOTDIR)
src/router/ipqext/ipqextd.c ipqext.c ... extensions/ipqext_template/ipqext_template.c ipqext_test1/ipqext_test1.c nfmod/ lib/
include/...
bin/...
scripts/preinit killdaemon flushtables simple_queue test1_queue
|
|
- Template for User-space Extension
The template for user-space extension can be found in ipqext_template.c.
It is ready for compilation and execution. To write a new extension,
a quick method is to copy an instance of the template code and
then do a blind replacement of every word "template" to the name
of the new extension.
#define _IPQEXT_EXTENSION_
// uncomment the following line to switch on the debug messages
// #define __DEBUG__
...
/*
* define extension name here
*
* extension name must match with the output module name
* ( i.e. ipqext_{extension name} )
*/
const char extension_name[] = "template";
...
|
|
Extension Information Structure
Each extension contains this structure to store its internal data
and a set of function pointers. The default structure declaration
needs not to be changed unless the function mapping of the extension
is altered.
static ipqext_t ext = {
prev : NULL, // should not be altered
next : NULL, // should not be altered
handle : NULL, // should not be altered
active : 0, // should not be altered
name : extension_name,
version : "1.0",
groupmask : 0, // should not be altered
init : &init,
fini : &fini,
proc : &proc,
start : &start,
stop : &stop,
reset : &reset,
info : &info,
help : &help,
};
|
|
Packet Processing Function
In proc function, you can define your own packet processing
routine. Each filtered packet is passed to this function as a pointer
to a packet message structure, which is declared as follows:
typedef struct ipq_packet_msg {
unsigned long packet_id; /* ID of queued packet */
unsigned long mark; /* Netfilter mark value */
long timestamp_sec; /* Packet arrival time (seconds) */
long timestamp_usec; /* Packet arrvial time (+useconds) */
unsigned int hook; /* Netfilter hook we rode in on */
char indev_name[IFNAMSIZ]; /* Name of incoming interface */
char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */
unsigned short hw_protocol; /* Hardware protocol (network order) */
unsigned short hw_type; /* Hardware type */
unsigned char hw_addrlen; /* Hardware address length */
unsigned char hw_addr[8]; /* Hardware address */
size_t data_len; /* Length of packet data */
unsigned char payload[0]; /* Optional packet data */
} ipq_packet_msg_t;
What we are most interested in is the payload field of the
packet message. For any IP packet, the payload field stores the
IP header, other network protocol header and data as a plain buffer.
We can directly manipulate the content of this buffer.
/*
* packet processing function
*
* return: NF_ACCEPT packet is accepted and leaves ipqext immediately
* NF_QUEUE packet is queued for further ipqext processing
* NF_DROP packet is explicitly dropped
*
* negative verdict to indicate packet is altered
*/
int proc(ipq_packet_msg_t *m)
{
unsigned int retval = NF_QUEUE;
// put packet processing code here
return retval;
}
|
|
Extension Start/Stop/Reset Function
The start/stop/reset function is executed when an extension start/stop/reset
command is issued by the extension manager. These functions should
return 0 on success, -1 or nonzero value on error.
int start() { ... }
int stop() { ... }
int reset() { ... }
|
|
Extension Information/Help Function
The info/help function is executed when an extension info/help command
is issued by the extension manager. These functions should return
a pointer to a char buffer or NULL. The info function is used to
retrieve the status/information of an extension during its execution.
The help function is used to display the usage of an extension (which
is not necessarily added or activated by the daemon). Both of them
use a char buffer as the medium for message passing.
char infobuf[] = " info here ";
const char* info()
{
...
return infobuf;
}
const char helpbuf[] = " help here ";
const char* help()
{
...
return helpbuf;
}
|
|
Extension Initial Pass Function
This function is executed after the extension manager issues an
add/delete command and the extension initialization function is
called. All parameters are passed to the extension as a string,
thus user is responsible for parsing the parameters. For instnace,
if the extension manager issues the following command to the daemon:
ipqext -A dummy param1,param2,param3
The string "param1,param2,param3" will be passed as a fixed-size
char buffer to the initial pass function.
int init_pass(void *handle, char *param, int paramlen)
{
// set module handle
ext.handle = handle;
// parse parameter buffer
return 0;
}
|
|
Extension Initialization/Finalization Function
The initialization/finalization function is executed after the extension
manager issues an add/delete command. These functions should return
0 on success, -1 or nonzero value on error.
int init()
{
// initalization codes here
// register function must always be the last call
ipqext_register(&ext);
return 0;
}
int fini()
{
// unregister function must always be the first call
ipqext_unregister(&ext);
// finialization codes here
return 0;
}
|
|
Module(Shared Object) Initialization/Finalization Function
These functions are defined in shared object modules. The initialization/finalization
function is executed after the extension manager loads/unloads an
extension. They are not used (left blank) in most cases, the extension
initialization and finalization functions should be used instead.
void _init(void) {}
void _fini(void) {}
|
|
- Example 1: The simplest ipqueue
- Download the archive "tuto.tar.gz"
and un-tar it.
- Modify ipqtest.c and then compile it.
$ cd ~/tuto/src/router/test
modify ipqtest.c ...
$ make clean
$ make
|
|
- Load ipqueue and filter a particular kind of packet with iptables.
$ ~/tuto/script/simple_queue
or
$ modprobe ip_queue
$ iptables -A INPUT -p icmp -j QUEUE
|
|
- Run the simple ipqueue program.
- Do a simple test
- Example 2: A quick way to build a user-space extension
- Compile the ipqueue extension daemon and manager.
cd ~/tuto/src/router/ipqext
make clean
make
|
|
- Clone a instance of ipqext_template as ipqext_test1. Rename
the cloned copy as ipqext_test1.c and then do a blind replacement
(i.e. convert every word "template" to "test1") in both C source
file and Makefile.
- Modify ipqext_test1.c and then compile it as an extension
module.
$ cd tuto/src/router/ipqext/extension/ipqext_test1
modify ipqext_test1.c ...
$ make clean
$ make
|
|
- Set up the environment and then run the daemon.
$ ~/tuto/scripts/preinit
$ ~/tuto/bin/ipqextd -e ~/tuto/bin/extension
|
|
- Load ipqueue and filter a particular kind of packet with iptables.
$ ~/tuto/script/test1_queue
or
$ modprobe ip_queue
$ iptables -t mangle -A INPUT -p icmp -j MARK --set-mark 1
$ iptables -A INPUT -p icmp -m mark ! --mark 0x0 -j QUEUE
|
|
- Load and activate the extension.
$ cd ~/tuto/bin
$ ipqext -A test1
$ ipqext -G test1 1
$ ipqext -S test1
|
|
- Do a simple test
- Unload the extension, kill the daemon and flush all rules
in iptables.
$ ~/tuto/bin/ipqext -X test1
$ ~/tuto/scripts/killdaemon
$ ~/tuto/scripts/flushtables
|
|
- Useful Tools and References
- The netfilter/iptables
project
- Notes
- Why do I get an error message when my program trys to bind
ipqueue?
Please check if there is already a process which binds the ipqueue.
Also, check whether ip_queue modules is loaded by using "lsmod",
load it when necessary using "modprobe ip_queue".
- Why do I get an netlink socket error message?
In many cases, it is due to queue overflow in the ipqueue
module. The packet retrival rate of your program is not as fast
as the packet en-queuing rate. One simple and quick solution is
to enlarge the kernel receive buffer as follow:
echo 655360 > /proc/sys/net/core/rmem_max
echo 655360 > /proc/sys/net/core/rmem_default
|
|
If the above method can't help, you need to modify your program
to make it more efficient in packet retrival or swtich to kernel
extension.
|
|