2007-11-11
Passing packets from kernel land to userland - libipq and C
Based on my earlier entry, I got the C sample code working. Hopefully you will know what to do from the remarks in the code:
/*
* This code is GPL.
*/
/*
* Compiling: $ gcc -I/usr/include/libnetfilter_queue -L/usr/lib/libnetfilter_queue_libipq.so -o libipq_test_01 libipq_test_01.c -lipq
*
* You will require the following iptables rules BEFORE running this program:
*
* iptables -F
* iptables -A INPUT -j QUEUE
* iptables -A OUTPUT -j QUEUE
* iptables -A INPUT -j ACCEPT
* iptables -A OUTPUT -j ACCEPT
*
*/
#include
#include
#include
#define BUFSIZE 2048
static void die(struct ipq_handle *h)
{
ipq_perror("passer");
ipq_destroy_handle(h);
exit(1);
}
int main(int argc, char **argv)
{
int status;
unsigned char buf[BUFSIZE];
struct ipq_handle *h;
h = ipq_create_handle(0, PF_INET);
if (!h)
die(h);
status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
if (status < 0)
die(h);
fprintf( stderr, "Starting...\n" );
do{
status = ipq_read(h, buf, BUFSIZE, 0);
if (status < 0)
die(h);
switch (ipq_message_type(buf)) {
case NLMSG_ERROR:
fprintf(stderr, "Received error message %d\n",
ipq_get_msgerr(buf));
break;
case IPQM_PACKET: {
fprintf( stderr, "Processed packet\n" );
ipq_packet_msg_t *m = ipq_get_packet(buf);
status = ipq_set_verdict(h, m->packet_id,
NF_ACCEPT, 0, NULL);
if (status < 0)
die(h);
break;
}
default:
fprintf(stderr, "Unknown message type!\n");
break;
}
} while (1);
ipq_destroy_handle(h);
return 0;
}
2007-11-10
Passing packets from kernel land to userland - libipq and Perl
I have been looking at packet sniffing for various applications for a while now. Problem is that my needs are more "real time/in-line" than "post capture processing" (ala libpcap and friends).
So here are some notes on my progress. Consider this part 1.
Since I am using Linux exclusively, I had another look at Netfilter. I discovered basically two tools I could use:
The later seems to be a replacement for libipq, but I could not find a lot of documentation and implementation notes, so I stick with libipq for now.
Since I am more confident in Perl, I was delighted to find a Perl interface to libipq - perlipq.
On Debian based systems, ensure you have the following packages installed:
Here is a simple test you can do to see the interface in action. First create a basic firewall script (fw.sh) with the following:
Next, create a Perl script (test.pl):
To start the monitoring, run the initial firewall script, then run the above Perl script.
To stop the script, simply press CTRL+C. All networking should also stop as the script no longer passes the accept back.
To reset the firewall script, run:
That's it.
I still have a number of things I want to do, including:
Additional Resources:
So here are some notes on my progress. Consider this part 1.
Since I am using Linux exclusively, I had another look at Netfilter. I discovered basically two tools I could use:
The later seems to be a replacement for libipq, but I could not find a lot of documentation and implementation notes, so I stick with libipq for now.
Since I am more confident in Perl, I was delighted to find a Perl interface to libipq - perlipq.
On Debian based systems, ensure you have the following packages installed:
- iptables
- libiptables-ipv4-ipqueue-perl
Here is a simple test you can do to see the interface in action. First create a basic firewall script (fw.sh) with the following:
#!/bin/sh
iptables -F
iptables -A INPUT -j ACCEPT
iptables -A OUTPUT -j ACCEPT
iptables -t mangle -F
iptables -t mangle -A OUTPUT -p tcp -j QUEUE
Next, create a Perl script (test.pl):
#!/usr/bin/perl
package passer;
use strict;
$^W = 1;
use IPTables::IPv4::IPQueue qw(:constants);
use NetPacket::IP;
sub main
{
my ($queue, $msg);
$queue = new IPTables::IPv4::IPQueue() or die IPTables::IPv4::IPQueue->errstr;
$queue->set_mode( IPQ_COPY_PACKET, 1500 );
while (1) {
$msg = $queue->get_message() or die IPTables::IPv4::IPQueue->errstr;
my $pl = $msg->payload();
my $len = $msg->data_len();
eval {
my $ip = NetPacket::IP->decode( $pl );
my $ipsrc = $ip->{src_ip};
my $ipdest = $ip->{dest_ip};
print " > from $ipsrc to $ipdest -=> $len\n";
};
$queue->set_verdict($msg->packet_id(), NF_ACCEPT) > 0 or die IPTables::IPv4::IPQueue->errstr;
}
}
main();
To start the monitoring, run the initial firewall script, then run the above Perl script.
To stop the script, simply press CTRL+C. All networking should also stop as the script no longer passes the accept back.
To reset the firewall script, run:
# iptables -t mangle -F ; iptables -F
That's it.
I still have a number of things I want to do, including:
- Use NetPacket::TCP to get SRC and DST ports
- Load test (how is network performance influenced?)
- During output, I only saw packets leaving the firewall (SRC was the FW, and DST was the client, although the client initiated the session - weird). I need to investigate this, as I am no iptables expert :-)
- Do it in C? (http://www.imchris.org/projects/libipq.html)
Additional Resources: