mirror of https://github.com/tLDP/LDP
3015 lines
91 KiB
Plaintext
3015 lines
91 KiB
Plaintext
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
|
|
|
|
<article id="qlibiptc" lang="en">
|
|
|
|
<articleinfo>
|
|
<title>Querying libiptc HOWTO</title>
|
|
<author>
|
|
<firstname>Leonardo</firstname>
|
|
<surname>Balliache</surname>
|
|
<affiliation>
|
|
<address>
|
|
<email>
|
|
leonardo@opalsoft.net
|
|
</email>
|
|
</address>
|
|
</affiliation>
|
|
</author>
|
|
<pubdate>Version 0.1 - April 30, 2002</pubdate>
|
|
<revhistory>
|
|
<revision>
|
|
<revnumber>0.1</revnumber>
|
|
<date>2002-04-30</date>
|
|
<authorinitials>lb</authorinitials>
|
|
<revremark>
|
|
Initial release.
|
|
</revremark>
|
|
</revision>
|
|
</revhistory>
|
|
</articleinfo>
|
|
|
|
<sect1 id="legal" label="1">
|
|
<title>Legal Notice</title>
|
|
<para>
|
|
This document is free; 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 document 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 can get a copy of the GNU GPL
|
|
<ulink url="http://www.gnu.org/copyleft/gpl.html">here</ulink>.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="translat" label="2">
|
|
<title>Translations</title>
|
|
<para>
|
|
If you want to translate this document you are free to do so. However,
|
|
you will need to do the following:
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Check first that another version of the document doesn't already
|
|
exist at your local LDP.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Maintain all sections (including 'Legal Notice', 'Translation',
|
|
'Credits', etc., etc.) of the document.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
No need to ask me to translate! You just have to let me know
|
|
(if you want) about your translation.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
<para>
|
|
Thank for your translation.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="disclaim" label="3">
|
|
<title>Disclaimer</title>
|
|
<para>
|
|
I took this <quote>disclaimer</quote> from
|
|
<ulink url="http://qos.ittc.ukans.edu/howto/howto.html">
|
|
Linux-Advance Networking Overview</ulink> by
|
|
Saravanan Radhakrishnan (08-1999) because it applies in my own case:
|
|
</para>
|
|
<para>
|
|
All the text in this document is completely based on my understanding
|
|
of implementations of various features. I have read some documents and
|
|
have seen the code myself, and I described them based on my understanding.
|
|
If the reader notices any concept description which appears to be contrary
|
|
to their understanding of the concept, the issue can be taken up for
|
|
discussion and corrections will be made to the document as necessary. I
|
|
would appreciate any suggestions and comments made in order to improve the
|
|
quality of this document.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="credits" label="4">
|
|
<title>Credits</title>
|
|
<para>
|
|
I want to thank the following people and organizations who had helped me,
|
|
directly or not, to make this document possible:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
My wife Cielo and my sons Jose, Dario and Gustavo by their patient and
|
|
support.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://www.tldp.org">Linux Documentation Project</ulink>
|
|
for publishing and uploading my document.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The site <ulink url="http://www.docum.org">http://www.docum.org</ulink>
|
|
drived by Stef Coene that give me some ideas for writing this document.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Paul <quote>Rusty</quote> Rusell who write the kernel firewall code,
|
|
the excelent package <emphasis>iptables</emphasis> and the
|
|
associated library <emphasis>libiptc</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Harald Welte who write the utility <emphasis>iptables-save</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Alexey Kuznetsov who write the kernel queue discipline code and the
|
|
excelent package <emphasis>iproute2</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Tabatha Persad from the
|
|
<ulink url="http://www.tldp.org">Linux Documentation Project</ulink>
|
|
who revised my english syntax and writing, gave me several ideas to
|
|
improve the content and encouraged me to learn and use DocBook to write
|
|
the final version of this document.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect1>
|
|
|
|
<sect1 id="object" label="5">
|
|
<title>Objectives</title>
|
|
<para>
|
|
This HOWTO explains how to use the <emphasis>libiptc</emphasis> library
|
|
included in the <emphasis>iptables</emphasis> package. This document can
|
|
show you how to use short C or C++ programs to query the internal structure
|
|
of the firewalling code, to check chains and rules, packet and byte counters,
|
|
and in a second phase, if you are a little <quote>brave</quote>, to modify
|
|
them.
|
|
</para>
|
|
<para>
|
|
You can find the latest version of this document at
|
|
<ulink url="http://opalsoft.net/qos/libiptc/qlibiptc.html">
|
|
Querying libiptc HOWTO.html</ulink>.
|
|
</para>
|
|
<para>
|
|
If you have suggestions to help make this document better, please submit
|
|
your ideas to me at the following address:
|
|
<ulink url="mailto:leonardo@opalsoft.net">leonardo@opalsoft.net</ulink>.
|
|
</para>
|
|
<para>
|
|
While I wrote this HOWTO, I developed a simple bandwith meter using
|
|
user-defined chains to get the data to be measured. This idea was conceived
|
|
looking at <command>monitor.pl</command>, a simple perl program for bandwith
|
|
measurement, written by Stef Coene at
|
|
<ulink url="http://www.docum.org">http://www.docum.org</ulink>.
|
|
I recommend this site to people interested in bandwidth control and
|
|
measurement.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="whatis"label="6">
|
|
<title>What is libiptc?</title>
|
|
<para>
|
|
<emphasis>libiptc</emphasis> is the library that is used to communicate
|
|
with netfilter, the internal kernel code in charge of firewalling and packet
|
|
filtering. This code and <emphasis>iptables</emphasis> were written by Paul
|
|
<quote>Rusty</quote> Russell. <emphasis>iptables</emphasis> was developed
|
|
using <emphasis>libiptc</emphasis> calls to get the job done.
|
|
</para>
|
|
<para>
|
|
If you want to have more information about <emphasis>iptables</emphasis>,
|
|
<emphasis>libiptc</emphasis> and the firewalling code, have a look at
|
|
links at the end of this document.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="howdidi" label="7">
|
|
<title>How did I obtain this knowledge?</title>
|
|
<para>
|
|
Just looking at code in <emphasis>iptables 1.2.6</emphasis> package and
|
|
especially at program <emphasis>iptables-save.c</emphasis> that use
|
|
<emphasis>libiptc</emphasis> to dump information from firewalling
|
|
kernel code.
|
|
</para>
|
|
<para>
|
|
I will try to be very pragmatic and clear in order to make this HOWTO
|
|
useful.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="previous" label="8">
|
|
<title>Previous knowledge and system requirements</title>
|
|
<para>
|
|
You have to have some previous knowledge to follow this document:
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>Very important:</emphasis>
|
|
You must know how to use the <emphasis>iptables</emphasis> package as a
|
|
user, such as how to create or list rules and user chains. You do not need
|
|
to be a firewall expert, but you should know how to use
|
|
<emphasis>iptables</emphasis> fluently.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
You have to have kernel sources installed in your system, in
|
|
<filename>/usr/src/linux</filename> as usual.
|
|
</para>
|
|
<para>
|
|
I am using a <emphasis>2.4.16</emphasis> kernel in a
|
|
<emphasis>SuSE 7.1</emphasis> Linux environment. You need
|
|
<emphasis>2.4.x</emphasis> kernel code to follow this HOWTO, preferably kernel
|
|
<emphasis>2.4.16</emphasis>. For <emphasis>SuSE</emphasis> you can
|
|
get the kernel sources at
|
|
<ulink url="ftp://ftp.gwdg.de/pub/linux/suse/ftp.suse.com/suse/i386/update/">
|
|
ftp://ftp.gwdg.de/pub/linux/suse/ftp.suse.com/suse/i386/update</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
You have to know how to compile the kernel if you have to update your kernel
|
|
version. After activating the netfilter options using
|
|
<command>make menuconfig</command>, you
|
|
must compile and install the kernel as usual.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Reboot your new kernel using <command>init 6</command>. Ensure that you
|
|
backup a copy of your previous kernel in <emphasis>lilo</emphasis> in case
|
|
you encounter a problem and need to retrace your steps.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Be sure that your new <emphasis>2.4.x</emphasis> kernel is running fine.
|
|
To install <emphasis>iptables-1.2.6</emphasis> you will need to patch the
|
|
kernel again (and re-compile and install it), and it is better if you follow
|
|
the previous two steps to ensure that your kernel is running right before
|
|
applying new iptables patches.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</sect1>
|
|
|
|
<sect1 id="install" label="9">
|
|
<title>Installing iptables + libiptc</title>
|
|
<para>
|
|
To install <emphasis>libiptc</emphasis> follow these steps:
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Download <emphasis>iptables-1.2.6.tar.bz2</emphasis> from
|
|
<ulink url="http://netfilter.samba.org/">http://netfilter.samba.org/</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Copy the <emphasis>iptables</emphasis> tar file into
|
|
<filename>/usr/local/src</filename>:
|
|
</para>
|
|
<screen>
|
|
bash# <command>cp iptables-1.2.6.tar.bz2 /usr/local/src</command>
|
|
</screen>
|
|
</listitem>
|
|
<listitem>
|
|
<para> Unpack:</para>
|
|
<screen>
|
|
bash# <command>tar xjvf iptables-1.2.6.tar.bz2</command>
|
|
</screen>
|
|
</listitem>
|
|
<listitem>
|
|
<para> Go into the iptables directory:</para>
|
|
<screen>
|
|
bash# <command>cd iptables-1.2.6</command>
|
|
</screen>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Check to see if your kernel needs some aditional patches with:
|
|
</para>
|
|
<screen>
|
|
bash# <command>make pending-patches</command> <emphasis>KERNEL_DIR=/usr/src/linux</emphasis>
|
|
</screen>
|
|
<para>
|
|
If your kernel source is located somewhere other than in
|
|
<filename>/usr/src/linux</filename>, replace the kernel source directory in
|
|
the command line above with your source directory.
|
|
</para>
|
|
<para>
|
|
Be careful with this option. This command invokes
|
|
<emphasis>patch-o-matic</emphasis>, a new patch verification utility by
|
|
Rusty Russell. The utility will show you a list of new patches (some
|
|
proposed, some submitted, some accepted) available for your kernel source.
|
|
As Rusty himself says, <quote>Some of these new patches have bugs</quote>,
|
|
and you do not have to apply all of them.
|
|
</para>
|
|
<para>
|
|
Read the information showed for each patch carefully and answer with
|
|
<keycap>y</keycap> (apply the patch) or <keycap>N</keycap> (skip this patch).
|
|
In some cases answering <keycap>y</keycap> will try to apply the patch, but
|
|
if the patch finds some differences between your sources, it will be
|
|
skipped and the next new one presented.
|
|
</para>
|
|
<para>
|
|
I did not apply any of the proposed patches and kept my kernel in its
|
|
original state before continuing to the next step.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Make the iptables package with:
|
|
</para>
|
|
<screen>
|
|
bash# <command>make</command> <emphasis>KERNEL_DIR=/usr/src/linux</emphasis>
|
|
</screen>
|
|
<para>
|
|
Again, if your kernel source is not at <filename>/usr/src/linux</filename>,
|
|
replace the kernel source directory in the command above.
|
|
</para>
|
|
<para>
|
|
If all goes right the compiler will finish without errors.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Before the next step, check to see if you have installed iptables package by
|
|
typing:
|
|
</para>
|
|
<screen>
|
|
bash# <command>rpm -q iptables</command>
|
|
</screen>
|
|
<para>
|
|
If the iptables rpm is installed, you will see the name and version of the
|
|
package, similar to:
|
|
</para>
|
|
<para>
|
|
<emphasis>iptables-1.1.2-13</emphasis>
|
|
</para>
|
|
<para>
|
|
In this case un-install with:
|
|
</para>
|
|
<screen>
|
|
bash# <command>rpm -e iptables</command>
|
|
</screen>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Install the new created package:
|
|
</para>
|
|
<screen>
|
|
bash# <command>make install</command> <emphasis>KERNEL_DIR=/usr/src/linux</emphasis>
|
|
</screen>
|
|
<para>
|
|
Again, check your kernel source directory.
|
|
</para>
|
|
<para>
|
|
This command will install the binaries (<emphasis>iptables, iptables-save,
|
|
iptables-restore</emphasis>) in <filename>/usr/local/sbin</filename>, the manuals
|
|
in <filename>/usr/local/man/man8</filename> and the modules in
|
|
<filename>/usr/local/lib/iptables</filename>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Finally install the headers, development libraries and associated
|
|
development man pages, with:
|
|
</para>
|
|
<screen>
|
|
bash# <command>make install-devel</command>
|
|
</screen>
|
|
<para>
|
|
This command will install the <emphasis>libiptc</emphasis> library
|
|
in <filename>/usr/local/lib</filename>.
|
|
</para>
|
|
<para>
|
|
I think something must be wrong with this command. It does not install all
|
|
headers files properly, so you must install them yourself using:
|
|
</para>
|
|
<screen>
|
|
bash# <command>cd /usr/local/src/iptables-1.2.6</command>
|
|
bash# <command>cp include/iptables.h /usr/local/include</command>
|
|
bash# <command>cp include/iptables_common.h /usr/local/include</command>
|
|
bash# <command>mkdir /usr/local/include/libiptc</command>
|
|
bash# <command>cp include/libiptc/libiptc.h /usr/local/include/libiptc</command>
|
|
bash# <command>cp include/libiptc/ipt_kernel_headers.h /usr/local/include/libiptc</command>
|
|
bash# <command>cp iptables.o /usr/local/lib</command>
|
|
</screen>
|
|
<para>
|
|
<filename>iptables.o</filename> is needed above to compile programs to get
|
|
rule information from netfilter.
|
|
</para>
|
|
<para>
|
|
Now you are ready to create programs that can communicate directly with libiptc.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</sect1>
|
|
|
|
<sect1 id="howtoprg" label="10">
|
|
<title>How to create your program(s)</title>
|
|
<para>
|
|
Create your program(s) in <filename>/usr/local/src</filename>;
|
|
this way you will not have problems with gcc looking for files in the "include" section.
|
|
</para>
|
|
<para>
|
|
Your program(s) would be something like this:
|
|
</para>
|
|
<screen>
|
|
/* My program */
|
|
|
|
#include <getopt.h>
|
|
#include <sys/errno.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
#include <time.h>
|
|
#include "libiptc/libiptc.h"
|
|
#include "iptables.h"
|
|
|
|
int main(void)
|
|
{
|
|
<emphasis>
|
|
/* Use always this part for your programs .... From here ... **** */
|
|
</emphasis>
|
|
iptc_handle_t h;
|
|
const char *chain = NULL;
|
|
const char *tablename = NULL;
|
|
|
|
program_name = "my_program";
|
|
program_version = NETFILTER_VERSION;
|
|
<emphasis>
|
|
/* .... To here .... ******************************************** */
|
|
</emphasis>
|
|
|
|
<emphasis>
|
|
/* From here you write your own code */
|
|
</emphasis>
|
|
.... your code ...
|
|
....
|
|
....
|
|
|
|
} /* main */
|
|
</screen>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The "include" section is <emphasis>a must</emphasis> in your c/c++ program(s).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If you are using c++ do not forget to write extern "C" for
|
|
these include.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect1>
|
|
|
|
<sect1 id="qfunction" label="11">
|
|
<title>Functions to query libiptc</title>
|
|
<para>
|
|
This section explains which functions allow you to query libiptc. We will use
|
|
the header file of <emphasis>libiptc</emphasis>,
|
|
file <filename>usr/local/include/libiptc/libiptc.h</filename>,
|
|
containing prototypes of each function as a reference to develop our explanation.
|
|
</para>
|
|
<para>
|
|
I have also included a brief description (when available) taken from
|
|
<ulink url="http://netfilter.samba.org/documentation/HOWTO/">
|
|
Linux netfilter Hacking HOWTO</ulink> within each function explanation.
|
|
</para>
|
|
<sect2 label="11.1">
|
|
<title>iptc_init</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_init
|
|
</seg>
|
|
<seg>
|
|
Takes a snapshot of the rules.
|
|
</seg>
|
|
<seg>
|
|
iptc_handle_t iptc_init(const char *tablename)
|
|
</seg>
|
|
<seg>
|
|
This function must be called as initiator before any other function can be
|
|
called.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>tablename</emphasis> is the name of the table we need to query
|
|
and/or modify; this could be <emphasis>filter</emphasis>,
|
|
<emphasis>mangle</emphasis>, <emphasis>nat</emphasis>, etc.
|
|
</seg>
|
|
<seg>
|
|
Pointer to a structure of type <emphasis>iptc_handle_t</emphasis> that must
|
|
be used as main parameter for the rest of functions we will call
|
|
from <emphasis>libiptc</emphasis>. <emphasis>iptc_init</emphasis> returns the
|
|
pointer to the structure or NULL if it fails. If this happens you can invoke
|
|
<emphasis>iptc_strerror</emphasis> to get information about the error.
|
|
See below.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
<para>
|
|
Have a look at this section of code in file <filename>iptables-save.c</filename>
|
|
for how to invoke this function:
|
|
</para>
|
|
<screen>
|
|
h = iptc_init(tablename);
|
|
if (!h)
|
|
exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",iptc_strerror(errno));
|
|
</screen>
|
|
</sect2>
|
|
<sect2 label="11.2">
|
|
<title>iptc_strerror</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_strerror
|
|
</seg>
|
|
<seg>
|
|
Translates error numbers into more human-readable form.
|
|
</seg>
|
|
<seg>
|
|
const char *iptc_strerror(int err)
|
|
</seg>
|
|
<seg>
|
|
This function returns a more meaningful explanation of a failure code in
|
|
the iptc library. If a function fails, it will always set
|
|
<emphasis>errno</emphasis>. This value can be passed to
|
|
<emphasis>iptc_strerror()</emphasis> to yield an error message.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>err</emphasis> is an integer indicating the error number.
|
|
</seg>
|
|
<seg>
|
|
Char pointer containing the error description.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="11.3">
|
|
<title>iptc_first_chain</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_first_chain
|
|
</seg>
|
|
<seg>
|
|
Iterator functions to run through the chains.
|
|
</seg>
|
|
<seg>
|
|
const char *iptc_first_chain(iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function returns the first chain name in the table.
|
|
</seg>
|
|
<seg>
|
|
Pointer to a structure of type <emphasis>iptc_handle_t</emphasis> that was
|
|
obtained by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Char pointer to the name of the chain.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="11.4">
|
|
<title>iptc_next_chain</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_next_chain
|
|
</seg>
|
|
<seg>
|
|
Iterator functions to run through the chains.
|
|
</seg>
|
|
<seg>
|
|
const char *iptc_next_chain(iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function returns the next chain name in the table; NULL means
|
|
no more chains.
|
|
</seg>
|
|
<seg>
|
|
Pointer to a structure of type <emphasis>iptc_handle_t</emphasis> that was
|
|
obtained by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Char pointer to the name of the chain.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
<para>
|
|
These two previous functions allow to us to iterate through the chains of the table
|
|
getting the name of each of the chains; <emphasis>iptc_first_chain</emphasis>
|
|
returns the name of the first chain of the table; <emphasis>iptc_next_chain</emphasis>
|
|
returns the name of next chains and NULL when the function reaches the end.
|
|
</para>
|
|
<para>
|
|
We can create <emphasis>Program #1</emphasis> to exercise our understanding of
|
|
these previous four functions:
|
|
</para>
|
|
<screen>
|
|
/*
|
|
* How to use libiptc- program #1
|
|
* /usr/local/src/p1.c
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
#include <sys/errno.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
#include <time.h>
|
|
#include "libiptc/libiptc.h"
|
|
#include "iptables.h"
|
|
|
|
int main(void)
|
|
{
|
|
iptc_handle_t h;
|
|
const char *chain = NULL;
|
|
const char *tablename = "filter";
|
|
|
|
program_name = "p1";
|
|
program_version = NETFILTER_VERSION;
|
|
|
|
h = iptc_init(tablename);
|
|
if ( !h ) {
|
|
printf("Error initializing: %s\n", iptc_strerror(errno));
|
|
exit(errno);
|
|
}
|
|
|
|
for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) {
|
|
printf("%s\n", chain);
|
|
}
|
|
|
|
exit(0);
|
|
|
|
} /* main */
|
|
</screen>
|
|
<para>
|
|
Write this program and save it as <filename>p1.c</filename>
|
|
in <filename>/usr/local/src</filename>.
|
|
</para>
|
|
<para>
|
|
Now write this <quote>bash</quote> script to simplify the compiling process:
|
|
</para>
|
|
<screen>
|
|
#!/bin/bash
|
|
|
|
gcc -Wall -Wunused -DNETFILTER_VERSION=\"1.2.6\" -rdynamic -o $1 $1.c \
|
|
/usr/local/lib/iptables.o /usr/local/lib/libiptc.a -ldl
|
|
</screen>
|
|
<para>
|
|
Save it as <filename>ipt-cc</filename> and do not forget to
|
|
<emphasis>chmod 0700 ipt-cc</emphasis>.
|
|
</para>
|
|
<para>
|
|
Now compile your <emphasis>p1</emphasis> program:
|
|
</para>
|
|
<screen>
|
|
bash# <command>./ipt-cc p1</command>
|
|
</screen>
|
|
<para>
|
|
And run it:
|
|
</para>
|
|
<screen>
|
|
bash# <command>./p1</command>
|
|
</screen>
|
|
<para>
|
|
You will get:
|
|
</para>
|
|
<screen>
|
|
INPUT
|
|
FORWARD
|
|
OUTPUT
|
|
</screen>
|
|
<para>
|
|
These are the three built-in iptables chains.
|
|
</para>
|
|
<para>
|
|
Now create some new chains using iptables and run your program again:
|
|
</para>
|
|
<screen>
|
|
bash# <command>iptables -N chain_1</command>
|
|
bash# <command>iptables -N chain_2</command>
|
|
bash# <command>./p1</command>
|
|
</screen>
|
|
<para>
|
|
You will get:
|
|
</para>
|
|
<screen>
|
|
INPUT
|
|
FORWARD
|
|
OUTPUT
|
|
chain_1
|
|
chain_2
|
|
</screen>
|
|
<para>
|
|
Try to generate an error initializing tablename to <emphasis>myfilter</emphasis>
|
|
instead of <emphasis>filter</emphasis>. When you compile and execute your program
|
|
again, you will get:
|
|
</para>
|
|
<screen>
|
|
<emphasis>Error initializing: Table does not exist (do you need to insmod?)</emphasis>
|
|
</screen>
|
|
<para>
|
|
<emphasis>iptables</emphasis> informs you that <emphasis>myfilter</emphasis> does
|
|
not exist as a table.
|
|
</para>
|
|
</sect2>
|
|
<sect2 label="11.5">
|
|
<title>iptc_is_chain</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_is_chain
|
|
</seg>
|
|
<seg>
|
|
Check if a chain exists.
|
|
</seg>
|
|
<seg>
|
|
int iptc_is_chain(const char *chain, const iptc_handle_t handle)
|
|
</seg>
|
|
<seg>
|
|
This function checks to see if the chain described in the parameter
|
|
<emphasis>chain</emphasis> exists in the table.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer containing the name of
|
|
the chain we want to check to. <emphasis>handle</emphasis> is a pointer to a
|
|
structure of type <emphasis>iptc_handle_t</emphasis> that was
|
|
obtained by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
integer value 1 (true) if the chain exists; integer value 0 (false)
|
|
if the chain does not exist.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="11.6">
|
|
<title>iptc_builtin</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_builtin
|
|
</seg>
|
|
<seg>
|
|
Is this a built-in chain?
|
|
</seg>
|
|
<seg>
|
|
int iptc_builtin(const char *chain, const iptc_handle_t handle)
|
|
</seg>
|
|
<seg>
|
|
This function is used to check if a given chain name is a built-in
|
|
chain or not.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer containing the name of
|
|
the chain we want to check to. <emphasis>handle</emphasis> is a pointer to a
|
|
structure of type <emphasis>iptc_handle_t</emphasis> that was
|
|
obtained by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if the given chain name is the name
|
|
of a builtin chain; returns integer value 0 (false) is not.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="11.7">
|
|
<title>iptc_first_rule</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_first_rule
|
|
</seg>
|
|
<seg>
|
|
Get first rule in the given chain.
|
|
</seg>
|
|
<seg>
|
|
const struct ipt_entry *iptc_first_rule(const char *chain, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function returns a pointer to the first rule in the given chain
|
|
name; NULL for an empty chain.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer containing the name of
|
|
the chain we want to get the rules to. <emphasis>handle</emphasis> is a
|
|
pointer to a structure of type <emphasis>iptc_handle_t</emphasis> that was
|
|
obtained by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns a pointer to an <emphasis>ipt_entry</emphasis> structure
|
|
containing information about the first rule of the chain. See below
|
|
for an explanation of this structure.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="11.8">
|
|
<title>iptc_next_rule</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_next_rule
|
|
</seg>
|
|
<seg>
|
|
Get the next rule in the given chain.
|
|
</seg>
|
|
<seg>
|
|
const struct ipt_entry *iptc_next_rule(const struct ipt_entry *prev, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function returns a pointer to the next rule in the given chain
|
|
name; NULL means the end of the chain.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>prev</emphasis> is a pointer to a structure of type
|
|
<emphasis>ipt_entry</emphasis> that must be obtained first by a previous call to
|
|
the function <emphasis>iptc_first_rule</emphasis>. In order to get the second
|
|
and subsequent rules you have to pass a pointer to the structure containing the
|
|
information about the previous rule of the chain. <emphasis>handle</emphasis> is
|
|
a pointer to a structure of type <emphasis>iptc_handle_t</emphasis> that was
|
|
obtained by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns a pointer to an <emphasis>ipt_entry</emphasis> structure
|
|
containing information about the next rule of the chain. See below
|
|
for an explanation of this structure.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="11.9">
|
|
<title>iptc_get_target</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_get_target
|
|
</seg>
|
|
<seg>
|
|
Get a pointer to the target name of this entry.
|
|
</seg>
|
|
<seg>
|
|
const char *iptc_get_target(const struct ipt_entry *e, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function gets the target of the given rule. If it is an extended
|
|
target, the name of that target is returned. If it is a jump to another chain,
|
|
the name of that chain is returned. If it is a verdict (eg. DROP), that name
|
|
is returned. If it has no target (an accounting-style rule), then the empty
|
|
string is returned. Note that this function should be used instead of using
|
|
the value of the <emphasis>verdict</emphasis> field of the
|
|
<emphasis>ipt_entry</emphasis> structure directly, as it offers the above further
|
|
interpretations of the standard verdict.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>e</emphasis> is a pointer to a structure of type
|
|
<emphasis>ipt_entry</emphasis> that must be obtained first by a previous call to
|
|
the function <emphasis>iptc_first_rule</emphasis> or the function
|
|
<emphasis>iptc_next_rule</emphasis>. <emphasis>handle</emphasis> is
|
|
a pointer to a structure of type <emphasis>iptc_handle_t</emphasis> that was
|
|
obtained by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns a char pointer to the target name. See <emphasis>Description</emphasis>
|
|
above for more information.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
<para>
|
|
Now it is time to explain the <emphasis>ipt_entry</emphasis> structure; these pieces
|
|
of code are taken from <emphasis>iptables</emphasis> package sources:
|
|
</para>
|
|
<screen>
|
|
/* Internet address. */
|
|
struct in_addr {
|
|
__u32 s_addr;
|
|
};
|
|
|
|
/* Yes, Virginia, you have to zero the padding. */
|
|
struct ipt_ip {
|
|
/* Source and destination IP addr */
|
|
struct in_addr src, dst;
|
|
/* Mask for src and dest IP addr */
|
|
struct in_addr smsk, dmsk;
|
|
char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
|
|
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
|
|
|
|
/* Protocol, 0 = ANY */
|
|
u_int16_t proto;
|
|
|
|
/* Flags word */
|
|
u_int8_t flags;
|
|
/* Inverse flags */
|
|
u_int8_t invflags;
|
|
};
|
|
|
|
struct ipt_counters
|
|
{
|
|
u_int64_t pcnt, bcnt; /* Packet and byte counters */
|
|
};
|
|
|
|
/* This structure defines each of the firewall rules. Consists of 3
|
|
parts which are 1) general IP header stuff 2) match specific
|
|
stuff 3) the target to perform if the rule matches */
|
|
struct ipt_entry
|
|
{
|
|
struct ipt_ip ip;
|
|
|
|
/* Mark with fields that we care about. */
|
|
unsigned int nfcache;
|
|
|
|
/* Size of ipt_entry + matches */
|
|
u_int16_t target_offset;
|
|
/* Size of ipt_entry + matches + target */
|
|
u_int16_t next_offset;
|
|
|
|
/* Back pointer */
|
|
unsigned int comefrom;
|
|
|
|
/* Packet and byte counters. */
|
|
struct ipt_counters counters;
|
|
|
|
/* The matches (if any), then the target. */
|
|
unsigned char elems[0];
|
|
};
|
|
</screen>
|
|
<para>
|
|
An <emphasis>ipt_entry</emphasis> structure contains:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
An <emphasis>ipt_ip</emphasis> structure containing (for the rule) the
|
|
source address and netmask <emphasis>(ip.src.s_addr, ip.smsk.s_addr)</emphasis>,
|
|
the destination address and netmask <emphasis>(ip.dst.s_addr, ip.dmsk.s_addr)</emphasis>,
|
|
the protocol <emphasis>(ip.proto)</emphasis>, a flags field <emphasis>(invflags)</emphasis>
|
|
to check for inverse <emphasis>(!)</emphasis> selections
|
|
<emphasis>(eg. ! 192.168.2.0/24, ! eth0, ! tcp, etc)</emphasis>, the input
|
|
interface <emphasis>(iniface)</emphasis>, the output interface
|
|
<emphasis>(outiface)</emphasis>, the input <emphasis>(iniface_mask)</emphasis>
|
|
and output <emphasis>(outiface_mask)</emphasis> interface masks and the
|
|
<emphasis>flags</emphasis> field to check for fragmented packets.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
An <emphasis>ipt_counters</emphasis> structure containing the packet
|
|
<emphasis>(pcnt)</emphasis> and byte <emphasis>(bcnt)</emphasis> counter
|
|
of the rule. This information is important for bandwidth measurement.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>target_offset</emphasis> that is used to get the target information
|
|
of the rule.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Unknown fields: <emphasis>nfcache, comefrom, elems, next_offset</emphasis>.
|
|
If someone can give me a feedback about these fields I would be grateful.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
A simple way to work with all this information is to borrow
|
|
some functions from <filename>iptables-save.c</filename> by Paul
|
|
Russell and Harald Welte.
|
|
</para>
|
|
<para>
|
|
Here is another sample program <emphasis>Program #2</emphasis> written with
|
|
a lot of help from Russell-Welte:
|
|
</para>
|
|
<screen>
|
|
/*
|
|
* How to use libiptc- program #2
|
|
* /usr/local/src/p1.c
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
#include <sys/errno.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
#include <time.h>
|
|
#include "libiptc/libiptc.h"
|
|
#include "iptables.h"
|
|
|
|
<emphasis>
|
|
/* Here begins some of the code taken from iptables-save.c **************** */
|
|
</emphasis>
|
|
#define IP_PARTS_NATIVE(n) \
|
|
(unsigned int)((n)>>24)&0xFF, \
|
|
(unsigned int)((n)>>16)&0xFF, \
|
|
(unsigned int)((n)>>8)&0xFF, \
|
|
(unsigned int)((n)&0xFF)
|
|
|
|
#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
|
|
|
|
/* This assumes that mask is contiguous, and byte-bounded. */
|
|
static void
|
|
print_iface(char letter, const char *iface, const unsigned char *mask,
|
|
int invert)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (mask[0] == 0)
|
|
return;
|
|
|
|
printf("-%c %s", letter, invert ? "! " : "");
|
|
|
|
for (i = 0; i < IFNAMSIZ; i++) {
|
|
if (mask[i] != 0) {
|
|
if (iface[i] != '\0')
|
|
printf("%c", iface[i]);
|
|
} else {
|
|
/* we can access iface[i-1] here, because
|
|
* a few lines above we make sure that mask[0] != 0 */
|
|
if (iface[i-1] != '\0')
|
|
printf("+");
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf(" ");
|
|
}
|
|
|
|
/* These are hardcoded backups in iptables.c, so they are safe */
|
|
struct pprot {
|
|
char *name;
|
|
u_int8_t num;
|
|
};
|
|
|
|
/* FIXME: why don't we use /etc/protocols ? */
|
|
static const struct pprot chain_protos[] = {
|
|
{ "tcp", IPPROTO_TCP },
|
|
{ "udp", IPPROTO_UDP },
|
|
{ "icmp", IPPROTO_ICMP },
|
|
{ "esp", IPPROTO_ESP },
|
|
{ "ah", IPPROTO_AH },
|
|
};
|
|
|
|
static void print_proto(u_int16_t proto, int invert)
|
|
{
|
|
if (proto) {
|
|
unsigned int i;
|
|
const char *invertstr = invert ? "! " : "";
|
|
|
|
for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
|
|
if (chain_protos[i].num == proto) {
|
|
printf("-p %s%s ",
|
|
invertstr, chain_protos[i].name);
|
|
return;
|
|
}
|
|
|
|
printf("-p %s%u ", invertstr, proto);
|
|
}
|
|
}
|
|
|
|
static int print_match(const struct ipt_entry_match *e,
|
|
const struct ipt_ip *ip)
|
|
{
|
|
struct iptables_match *match
|
|
= find_match(e->u.user.name, TRY_LOAD);
|
|
|
|
if (match) {
|
|
printf("-m %s ", e->u.user.name);
|
|
|
|
/* some matches don't provide a save function */
|
|
if (match->save)
|
|
match->save(ip, e);
|
|
} else {
|
|
if (e->u.match_size) {
|
|
fprintf(stderr,
|
|
"Can't find library for match `%s'\n",
|
|
e->u.user.name);
|
|
exit(1);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* print a given ip including mask if neccessary */
|
|
static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
|
|
{
|
|
if (!mask && !ip)
|
|
return;
|
|
|
|
printf("%s %s%u.%u.%u.%u",
|
|
prefix,
|
|
invert ? "! " : "",
|
|
IP_PARTS(ip));
|
|
|
|
if (mask != 0xffffffff)
|
|
printf("/%u.%u.%u.%u ", IP_PARTS(mask));
|
|
else
|
|
printf(" ");
|
|
}
|
|
|
|
/* We want this to be readable, so only print out neccessary fields.
|
|
* Because that's the kind of world I want to live in. */
|
|
static void print_rule(const struct ipt_entry *e,
|
|
iptc_handle_t *h, const char *chain, int counters)
|
|
{
|
|
struct ipt_entry_target *t;
|
|
const char *target_name;
|
|
|
|
/* print counters */
|
|
if (counters)
|
|
printf("[%llu:%llu] ", e->counters.pcnt, e->counters.bcnt);
|
|
|
|
/* print chain name */
|
|
printf("-A %s ", chain);
|
|
|
|
/* Print IP part. */
|
|
print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
|
|
e->ip.invflags & IPT_INV_SRCIP);
|
|
|
|
print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
|
|
e->ip.invflags & IPT_INV_DSTIP);
|
|
|
|
print_iface('i', e->ip.iniface, e->ip.iniface_mask,
|
|
e->ip.invflags & IPT_INV_VIA_IN);
|
|
|
|
print_iface('o', e->ip.outiface, e->ip.outiface_mask,
|
|
e->ip.invflags & IPT_INV_VIA_OUT);
|
|
|
|
print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
|
|
|
|
if (e->ip.flags & IPT_F_FRAG)
|
|
printf("%s-f ",
|
|
e->ip.invflags & IPT_INV_FRAG ? "! " : "");
|
|
|
|
/* Print matchinfo part */
|
|
if (e->target_offset) {
|
|
IPT_MATCH_ITERATE(e, print_match, &e->ip);
|
|
}
|
|
|
|
/* Print target name */
|
|
target_name = iptc_get_target(e, h);
|
|
if (target_name && (*target_name != '\0'))
|
|
printf("-j %s ", target_name);
|
|
|
|
/* Print targinfo part */
|
|
t = ipt_get_target((struct ipt_entry *)e);
|
|
if (t->u.user.name[0]) {
|
|
struct iptables_target *target
|
|
= find_target(t->u.user.name, TRY_LOAD);
|
|
|
|
if (!target) {
|
|
fprintf(stderr, "Can't find library for target `%s'\n",
|
|
t->u.user.name);
|
|
exit(1);
|
|
}
|
|
|
|
if (target->save)
|
|
target->save(&e->ip, t);
|
|
else {
|
|
/* If the target size is greater than ipt_entry_target
|
|
* there is something to be saved, we just don't know
|
|
* how to print it */
|
|
if (t->u.target_size !=
|
|
sizeof(struct ipt_entry_target)) {
|
|
fprintf(stderr, "Target `%s' is missing "
|
|
"save function\n",
|
|
t->u.user.name);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
<emphasis>
|
|
/* Here ends some of the code taken from iptables-save.c ****************** */
|
|
</emphasis>
|
|
|
|
int main(void)
|
|
{
|
|
iptc_handle_t h;
|
|
const struct ipt_entry *e;
|
|
const char *chain = NULL;
|
|
const char *tablename = "filter";
|
|
const int counters = 1;
|
|
|
|
program_name = "p2";
|
|
program_version = NETFILTER_VERSION;
|
|
|
|
/* initialize */
|
|
h = iptc_init(tablename);
|
|
if ( !h ) {
|
|
printf("Error initializing: %s\n", iptc_strerror(errno));
|
|
exit(errno);
|
|
}
|
|
|
|
/* print chains and their rules */
|
|
for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) {
|
|
printf("%s\n", chain);
|
|
for (e = iptc_first_rule(chain, &h); e; e = iptc_next_rule(e, &h)) {
|
|
print_rule(e, &h, chain, counters);
|
|
}
|
|
}
|
|
|
|
exit(0);
|
|
|
|
} /* main */
|
|
</screen>
|
|
<para>
|
|
The function <emphasis>print_rule</emphasis> borrowed from
|
|
<filename>iptables-save.c</filename> prints the information
|
|
about a rule into a readable form using:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>print_ip</emphasis> to print the addresses,
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>print_iface</emphasis> to print the interfaces,
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>print_proto</emphasis> to print the protocols,
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>iptc_get_target</emphasis> to get and print the targets
|
|
(using <emphasis>save</emphasis>).
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
In <emphasis>main</emphasis> we iterate through each chain and
|
|
for each one we iterate through each rule printing it.
|
|
</para>
|
|
<para>
|
|
The arguments of <emphasis>print_rule</emphasis> are:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
e = pointer to an <emphasis>ipt_entry</emphasis> structure containing
|
|
information about the rule.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
h = pointer to an <emphasis>iptc_handle_t</emphasis> structure returned by
|
|
<emphasis>iptc_init</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
chain = name of the chain.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
counters = 0: do not print counters; 1: print them.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
OK, compile and run program <emphasis>p2</emphasis>:
|
|
</para>
|
|
<screen>
|
|
bash# <command>./ipt-cc p2</command>
|
|
bash# <command>./p2</command>
|
|
</screen>
|
|
<para>
|
|
You will get:
|
|
</para>
|
|
<screen>
|
|
INPUT
|
|
FORWARD
|
|
OUTPUT
|
|
chain_1
|
|
chain_2
|
|
</screen>
|
|
<para>
|
|
Now modify the environment using <emphasis>iptables</emphasis> to add some rules:
|
|
</para>
|
|
<screen>
|
|
bash# <command>iptables -A INPUT -p tcp -i eth0 -s ! 192.168.1.1 --dport 20 -j ACCEPT</command>
|
|
bash# <command>iptables -A chain_1 -p udp -o eth1 -s 192.168.2.0/24 --sport 33 -j DROP</command>
|
|
</screen>
|
|
<para>
|
|
Now if you run again <emphasis>p2</emphasis> you will get:
|
|
</para>
|
|
<screen>
|
|
INPUT
|
|
[0:0] -A INPUT -s ! 192.168.1.1 -i eth0 -p tcp -m tcp --dport 20 -j ACCEPT
|
|
FORWARD
|
|
OUTPUT
|
|
chain_1
|
|
[0:0] -A chain_1 -s 192.168.2.0/255.255.255.0 -o eth1 -p udp -m udp --sport 33 -j DROP
|
|
chain_2
|
|
</screen>
|
|
<para>
|
|
We have now rules printed for <emphasis>INPUT</emphasis> and
|
|
<emphasis>chain_1</emphasis> chains. The numbers in the
|
|
brackets at left are packet and byte counters respectively.
|
|
</para>
|
|
</sect2>
|
|
<sect2 label="11.10">
|
|
<title>iptc_get_policy</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_get_policy
|
|
</seg>
|
|
<seg>
|
|
Get the policy of a given built-in chain.
|
|
</seg>
|
|
<seg>
|
|
const char *iptc_get_policy(const char *chain, struct ipt_counters *counter, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function gets the policy of a built-in chain, and fills in the
|
|
<emphasis>counters</emphasis> argument with the hit statistics on
|
|
that policy.
|
|
</seg>
|
|
<seg>
|
|
You have to pass as arguments the name of the built-in chain you want
|
|
to get the policy to, a pointer to an <emphasis>ipt_counters</emphasis>
|
|
structure to be filled by the function and the
|
|
<emphasis>iptc_handle_t</emphasis> structure identifying the table we are
|
|
working to. The <emphasis>ipt_counters</emphasis> structure was explained
|
|
in previous section; do not forget that <emphasis>iptc_handle_t</emphasis>
|
|
must be obtained by a previous call to the function <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns a char pointer to the policy name.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
<para>
|
|
Using pieces of programs 1 and 2 we can write <emphasis>program #3</emphasis>:
|
|
</para>
|
|
<screen>
|
|
/*
|
|
* How to use libiptc- program #3
|
|
* /usr/local/src/p3.c
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
#include <sys/errno.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
#include <time.h>
|
|
#include "libiptc/libiptc.h"
|
|
#include "iptables.h"
|
|
|
|
int main(void)
|
|
{
|
|
iptc_handle_t h;
|
|
const char *chain = NULL;
|
|
const char *policy = NULL;
|
|
const char *tablename = "filter";
|
|
struct ipt_counters counters;
|
|
|
|
program_name = "p3";
|
|
program_version = NETFILTER_VERSION;
|
|
|
|
/* initialize */
|
|
h = iptc_init(tablename);
|
|
if ( !h ) {
|
|
printf("Error initializing: %s\n", iptc_strerror(errno));
|
|
exit(errno);
|
|
}
|
|
|
|
/* print built-in chains, their policies and counters */
|
|
printf("BUILT-IN POLICY PKTS-BYTES\n");
|
|
printf("-----------------------------\n");
|
|
for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) {
|
|
if ( !iptc_builtin(chain, h) )
|
|
continue;
|
|
if ( (policy = iptc_get_policy(chain, &counters, &h)) )
|
|
printf("%-10s %-10s [%llu:%llu]\n",
|
|
chain, policy, counters.pcnt, counters.bcnt);
|
|
}
|
|
|
|
exit(0);
|
|
|
|
} /* main */
|
|
</screen>
|
|
<para>
|
|
OK, compile and run program <emphasis>p3</emphasis>:
|
|
</para>
|
|
<screen>
|
|
bash# <command>./ipt-cc p3</command>
|
|
bash# <command>./p3</command>
|
|
</screen>
|
|
<para>
|
|
You will get something like this:
|
|
</para>
|
|
<screen>
|
|
BUILT-IN POLICY PKTS-BYTES
|
|
----------------------------
|
|
INPUT ACCEPT [0:0]
|
|
FORWARD ACCEPT [0:0]
|
|
OUTPUT ACCEPT [0:0]
|
|
</screen>
|
|
</sect2>
|
|
<sect2 label="11.11">
|
|
<title>iptc_read_counter</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_read_counter
|
|
</seg>
|
|
<seg>
|
|
Read counters of a rule in a chain.
|
|
</seg>
|
|
<seg>
|
|
struct ipt_counters *iptc_read_counter(const ipt_chainlabel chain,
|
|
unsigned int rulenum, iptc_handle_t *handle);
|
|
</seg>
|
|
<seg>
|
|
This function read and returns packet and byte counters of the entry
|
|
rule in chain <emphasis>chain</emphasis> positioned at
|
|
<emphasis>rulenum</emphasis>. Counters are returned in a pointer to a
|
|
type structure <emphasis>ipt_counters</emphasis>. Rule numbers start at
|
|
1 for the first rule.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be readed; <emphasis>rulenum</emphasis> is an integer value defined the
|
|
position in the chain of rules of the rule which counters will be read.
|
|
<emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call to
|
|
<emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns a pointer to an <emphasis>ipt_counters</emphasis> structure
|
|
containing the byte and packet counters readed.
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="mfunction" label="12">
|
|
<title>Functions to modify firewalling rules and statistics</title>
|
|
<para>
|
|
For those of you who are a little brave, <emphasis>libiptc</emphasis>
|
|
has a group of functions to directly modify the firewalling rules and
|
|
statistics <emphasis>(use of iptables is really the safest way)</emphasis>.
|
|
</para>
|
|
<para>
|
|
These functions are not covered by this HOWTO and I will limit myself
|
|
to presenting improved information taken from
|
|
<filename>libiptc.h</filename> and the
|
|
<ulink url="http://netfilter.samba.org/documentation/HOWTO/">
|
|
Linux netfilter Hacking HOWTO</ulink> by Rusty Russell.
|
|
</para>
|
|
<sect2 label="12.1">
|
|
<title>iptc_commit</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_commit
|
|
</seg>
|
|
<seg>
|
|
Makes the actual changes.
|
|
</seg>
|
|
<seg>
|
|
int iptc_commit(iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
The tables that you change are not written back until the
|
|
<emphasis>iptc_commit()</emphasis> function is called. This means it
|
|
is possible for two library users operating on the same chain to race
|
|
each other; locking would be required to prevent this, and it is not
|
|
currently done. There is no race with counters, however; counters are
|
|
added back in to the kernel in such a way that counter increments
|
|
between the reading and writing of the table still show up in the new
|
|
table. <emphasis>To protect the status of the system you must commit
|
|
your changes</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call
|
|
to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.2">
|
|
<title>iptc_insert_entry</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_insert_entry
|
|
</seg>
|
|
<seg>
|
|
Insert a new rule in a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_insert_entry(const ipt_chainlabel chain, const struct ipt_entry *e,
|
|
unsigned int rulenum, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function insert a rule defined in structure type
|
|
<emphasis>ipt_entry</emphasis> in chain <emphasis>chain</emphasis> into
|
|
position defined by integer value <emphasis>rulenum</emphasis>. Rule numbers
|
|
start at 1 for the first rule.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be modified; <emphasis>e</emphasis> is a pointer to a structure of type
|
|
<emphasis>ipt_entry</emphasis> that contains information about the rule to
|
|
be inserted. The programmer must fill the fields of this structure with
|
|
values required to define his or her rule before passing the pointer as
|
|
parameter to the function. <emphasis>rulenum</emphasis> is an integer
|
|
value defined the position in the chain of rules where the new rule will
|
|
be inserted. Rule numbers start at 1 for the first rule.
|
|
<emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call to
|
|
<emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.3">
|
|
<title>iptc_replace_entry</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_replace_entry
|
|
</seg>
|
|
<seg>
|
|
Replace an old rule in a chain with a new one.
|
|
</seg>
|
|
<seg>
|
|
int iptc_replace_entry(const ipt_chainlabel chain, const struct ipt_entry *e,
|
|
unsigned int rulenum, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function replace the entry rule in chain <emphasis>chain</emphasis>
|
|
positioned at <emphasis>rulenum</emphasis> with the rule defined in structure
|
|
type <emphasis>ipt_entry</emphasis>. Rule numbers start at 1 for the first rule.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be modified; <emphasis>e</emphasis> is a pointer to a structure of type
|
|
<emphasis>ipt_entry</emphasis> that contains information about the rule to
|
|
be inserted. The programmer must fill the fields of this structure with
|
|
values required to define his or her rule before passing the pointer as
|
|
parameter to the function. <emphasis>rulenum</emphasis> is an integer
|
|
value defined the position in the chain of rules where the old rule will
|
|
be replaced by the new one. Rule numbers start at 1 for the first rule.
|
|
<emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call to
|
|
<emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.4">
|
|
<title>iptc_append_entry</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_append_entry
|
|
</seg>
|
|
<seg>
|
|
Append a new rule in a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_append_entry(const ipt_chainlabel chain, const struct ipt_entry *e,
|
|
iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function append a rule defined in structure type
|
|
<emphasis>ipt_entry</emphasis> in chain <emphasis>chain</emphasis>
|
|
(equivalent to insert with rulenum = length of chain).
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be modified; <emphasis>e</emphasis> is a pointer to a structure of type
|
|
<emphasis>ipt_entry</emphasis> that contains information about the rule to
|
|
be appended. The programmer must fill the fields of this structure with
|
|
values required to define his or her rule before passing the pointer as
|
|
parameter to the function. <emphasis>handle</emphasis> is a pointer to a
|
|
structure of type <emphasis>iptc_handle_t</emphasis> that was obtained by
|
|
a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.5">
|
|
<title>iptc_delete_num_entry</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_delete_num_entry
|
|
</seg>
|
|
<seg>
|
|
Delete a rule in a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_delete_num_entry(const ipt_chainlabel chain, unsigned int rulenum,
|
|
iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function delete the entry rule in chain <emphasis>chain</emphasis>
|
|
positioned at <emphasis>rulenum</emphasis>. Rule numbers start at 1 for the
|
|
first rule.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be modified; <emphasis>rulenum</emphasis> is an integer value defined the
|
|
position in the chain of rules where the rule will be deleted.
|
|
<emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call to
|
|
<emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.6">
|
|
<title>iptc_flush_entries</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_flush_entries
|
|
</seg>
|
|
<seg>
|
|
Empty a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_flush_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function flushes the rule entries in the given chain (ie. empties chain).
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be flushed; <emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call to
|
|
<emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.7">
|
|
<title>iptc_zero_entries</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_zero_entries
|
|
</seg>
|
|
<seg>
|
|
Zeroes the chain counters.
|
|
</seg>
|
|
<seg>
|
|
int iptc_zero_entries(const ipt_chainlabel chain, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function zeroes the counters in the given chain.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain
|
|
which counters will be zero; <emphasis>handle</emphasis> is a pointer
|
|
to a structure of type <emphasis>iptc_handle_t</emphasis> that was obtained
|
|
by a previous call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.8">
|
|
<title>iptc_create_chain</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_create_chain
|
|
</seg>
|
|
<seg>
|
|
Create a new chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function create a new chain in the table.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain
|
|
to be created; <emphasis>handle</emphasis> is a pointer to a structure
|
|
of type <emphasis>iptc_handle_t</emphasis> that was obtained by a previous
|
|
call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.9">
|
|
<title>iptc_delete_chain</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_delete_chain
|
|
</seg>
|
|
<seg>
|
|
Delete a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_delete_chain(const ipt_chainlabel chain, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function delete the chain identified by the char pointer
|
|
<emphasis>chain</emphasis> in the table.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain
|
|
to be deleted; <emphasis>handle</emphasis> is a pointer to a structure
|
|
of type <emphasis>iptc_handle_t</emphasis> that was obtained by a previous
|
|
call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.10">
|
|
<title>iptc_rename_chain</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_rename_chain
|
|
</seg>
|
|
<seg>
|
|
Rename a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_rename_chain(const ipt_chainlabel oldname, const ipt_chainlabel newname,
|
|
iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function rename the chain identified by the char pointer
|
|
<emphasis>oldname</emphasis> to a new name <emphasis>newname</emphasis>
|
|
in the table.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>oldname</emphasis> is a char pointer to the name of the chain
|
|
to be renamed, <emphasis>newname</emphasis> is the new name;
|
|
<emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous
|
|
call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.11">
|
|
<title>iptc_set_policy</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_set_policy
|
|
</seg>
|
|
<seg>
|
|
Set the policy in a built-in chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_set_policy(const ipt_chainlabel chain, const ipt_chainlabel policy,
|
|
struct ipt_counters *counters, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function set the policy in chain <emphasis>chain</emphasis> to the
|
|
value represented by the char pointer <emphasis>policy</emphasis>. If you
|
|
want to set at the same time the counters of the chain, fill those values
|
|
in a structure of type <emphasis>ipt_counters</emphasis> and pass a pointer
|
|
to it as parameter <emphasis>counters</emphasis>. Be careful: the chain
|
|
<emphasis>must be</emphasis> a built-in chain.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be modified; <emphasis>policy</emphasis> is a char pointer to the name of
|
|
the policy to be set. <emphasis>counters</emphasis> is a pointer to an
|
|
<emphasis>ipt_counters</emphasis> structure to be used to set the counters
|
|
of the chain. <emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call to
|
|
<emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.12">
|
|
<title>iptc_zero_counter</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_zero_counter
|
|
</seg>
|
|
<seg>
|
|
Zero counters of a rule in a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_zero_counter(const ipt_chainlabel chain, unsigned int rulenum,
|
|
iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function zero packet and byte counters of the entry rule in chain
|
|
<emphasis>chain</emphasis> positioned at <emphasis>rulenum</emphasis>.
|
|
Rule numbers start at 1 for the first rule.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be modified; <emphasis>rulenum</emphasis> is an integer value defined the
|
|
position in the chain of rules of the rule which counters will be zero.
|
|
<emphasis>handle</emphasis> is a pointer to a structure of type
|
|
<emphasis>iptc_handle_t</emphasis> that was obtained by a previous call to
|
|
<emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
<sect2 label="12.13">
|
|
<title>iptc_set_counter</title>
|
|
<segmentedlist>
|
|
<segtitle>Name</segtitle>
|
|
<segtitle>Usage</segtitle>
|
|
<segtitle>Prototype</segtitle>
|
|
<segtitle>Description</segtitle>
|
|
<segtitle>Parameters</segtitle>
|
|
<segtitle>Returns</segtitle>
|
|
<seglistitem>
|
|
<seg>
|
|
iptc_set_counter
|
|
</seg>
|
|
<seg>
|
|
Set counters of a rule in a chain.
|
|
</seg>
|
|
<seg>
|
|
int iptc_set_counter(const ipt_chainlabel chain, unsigned int rulenum,
|
|
struct ipt_counters *counters, iptc_handle_t *handle)
|
|
</seg>
|
|
<seg>
|
|
This function set packet and byte counters of the entry rule in chain
|
|
<emphasis>chain</emphasis> positioned at <emphasis>rulenum</emphasis>
|
|
with values passed in a type structure <emphasis>ipt_counters</emphasis>.
|
|
Rule numbers start at 1 for the first rule.
|
|
</seg>
|
|
<seg>
|
|
<emphasis>chain</emphasis> is a char pointer to the name of the chain to
|
|
be modified; <emphasis>rulenum</emphasis> is an integer value defined the
|
|
position in the chain of rules of the rule which counters will be set.
|
|
<emphasis>counters</emphasis> is a pointer to an
|
|
<emphasis>ipt_counters</emphasis> structure to be used to set the counters
|
|
of the rule; the programmer must fill the fields of this structure with
|
|
values to be set. <emphasis>handle</emphasis> is a pointer to a structure
|
|
of type <emphasis>iptc_handle_t</emphasis> that was obtained by a previous
|
|
call to <emphasis>iptc_init</emphasis>.
|
|
</seg>
|
|
<seg>
|
|
Returns integer value 1 (true) if successful; returns integer value 0
|
|
(false) if fails. In this case <emphasis>errno</emphasis> is set to the
|
|
error number generated. Use <emphasis>iptc_strerror</emphasis> to get a
|
|
meaningful information about the problem. If errno == 0, it means there
|
|
was a version error (ie. upgrade <emphasis>libiptc</emphasis>).
|
|
</seg>
|
|
</seglistitem>
|
|
</segmentedlist>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
<sect1 id="bmeter" label="13">
|
|
<title>Bandwidth meter</title>
|
|
<para>
|
|
In this chapter I am going to develop a simple bandwidth meter using
|
|
the following functions from <emphasis>libiptc</emphasis>:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
To initialize the system:
|
|
<emphasis>iptc_handle_t iptc_init(const char *tablename)</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
To catch from errors:
|
|
<emphasis>const char *iptc_strerror(int err)</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
To iterate through the chains of the table:
|
|
<emphasis>const char *iptc_first_chain(iptc_handle_t *handle)</emphasis> and
|
|
<emphasis>const char *iptc_next_chain(iptc_handle_t *handle)</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
To read packet and byte counters for a specific rule:
|
|
<emphasis>struct ipt_counters *iptc_read_counter(const ipt_chainlabel chain,
|
|
unsigned int rulenum, iptc_handle_t *handle)</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
Also the function <emphasis>gettimeofday</emphasis> will be used to
|
|
measure elapsed time and the function <emphasis>getopt</emphasis> to
|
|
get options from the command line.
|
|
</para>
|
|
<para>
|
|
I don't know really if the term <emphasis>bandwidth meter</emphasis> is
|
|
well used here. I interpret <emphasis>bandwidth</emphasis> as a reference to
|
|
a flow capacity; perhaps a better term could be <emphasis>flow meter</emphasis>.
|
|
</para>
|
|
<para>
|
|
Here is the <emphasis>bandwidth meter</emphasis> <filename>bw.c</filename>.
|
|
It's well commented to be easy followed by everyone:
|
|
</para>
|
|
<screen>
|
|
/*
|
|
* How to use libiptc- program #4
|
|
* /usr/local/src/bw.c
|
|
* By Leonardo Balliache - 04.09.2002
|
|
* e-mail: leonardo@opalsoft.net
|
|
* --WELL COMMENTED-- to be easy followed by everyone.
|
|
*/
|
|
|
|
/* include files required */
|
|
#include <getopt.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/time.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <dlfcn.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include "libiptc/libiptc.h"
|
|
#include "iptables.h"
|
|
|
|
/* colors to differentiate chains measures */
|
|
#define RED "\033[41m\033[37m"
|
|
#define GREEN "\033[42m\033[30m"
|
|
#define ORANGE "\033[43m\033[30m"
|
|
#define BLUE "\033[44m\033[37m"
|
|
#define MAGENTA "\033[45m\033[37m"
|
|
#define CYAN "\033[46m\033[30m"
|
|
#define WHITE "\033[47m\033[30m"
|
|
#define BLACK "\033[40m\033[37m"
|
|
#define RESET "\033[00m"
|
|
|
|
/* maximum number of chains to be processed */
|
|
#define MAXUSERCHAINS 7
|
|
|
|
/* time between measures in seconds; adjust as you like */
|
|
#define SLEEPTIME 1
|
|
|
|
/* structure to count bytes per chain */
|
|
struct bwcnt {
|
|
int start; /* the chain was initialized */
|
|
u_int64_t icnt; /* bytes through; previous measure */
|
|
u_int64_t ocnt; /* bytes through; current measure */
|
|
double bw; /* bandwitdh (flow) on this chain */
|
|
};
|
|
|
|
/* function to calculate differences of time in seconds.
|
|
* micro-seconds precision.
|
|
*/
|
|
double delta(struct timeval a, struct timeval b)
|
|
{
|
|
if (a.tv_usec & b.tv_usec) {
|
|
a.tv_sec--;
|
|
a.tv_usec += 1000000;
|
|
}
|
|
return a.tv_sec-b.tv_sec + (a.tv_usec-b.tv_usec)/1000000.0;
|
|
}
|
|
|
|
/* main function */
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int i, j, ok;
|
|
double totbw;
|
|
iptc_handle_t h;
|
|
int c, act_bw = 0;
|
|
const char *chain = NULL;
|
|
const char *tablename = "filter";
|
|
struct timeval ti, to;
|
|
struct bwcnt bw[MAXUSERCHAINS];
|
|
struct ipt_counters *counters;
|
|
char *col[9] = { RED,GREEN,ORANGE,BLUE,MAGENTA,CYAN,WHITE,BLACK,RESET };
|
|
|
|
program_name = "bw";
|
|
program_version = NETFILTER_VERSION;
|
|
|
|
/* check options
|
|
* we have 2 options:
|
|
* -c = display current flow (each SLEEPTIME).
|
|
* -a = display average flow (from start); default option.
|
|
*/
|
|
while ((c = getopt (argc, argv, "ac")) != -1)
|
|
switch (c) {
|
|
case 'a':
|
|
act_bw = 0;
|
|
break;
|
|
case 'c':
|
|
act_bw = 1;
|
|
break;
|
|
case '?':
|
|
if (isprint(optopt))
|
|
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
|
|
else
|
|
fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt);
|
|
exit(1);
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
/* initialize array of chains */
|
|
memset(&bw, 0, MAXUSERCHAINS * sizeof(struct bwcnt));
|
|
|
|
/* get time to start meter on variable ti */
|
|
gettimeofday(&ti, NULL);
|
|
|
|
/* fire meter loop */
|
|
if ( act_bw )
|
|
printf("Displaying current flow values ...\n");
|
|
else
|
|
printf("Displaying average flow values ...\n");
|
|
|
|
/* forever loop; abort the program with ^C */
|
|
while ( 1 ) {
|
|
/* you have to initialize for each measure to be done */
|
|
if ( !(h = iptc_init(tablename)) ) {
|
|
printf("Error initializing: %s\n", iptc_strerror(errno));
|
|
exit(errno);
|
|
}
|
|
ok = 0; /* we start a new loop */
|
|
gettimeofday(&to, NULL); /* have a time shoot */
|
|
|
|
/* iterate through each chain of the table */
|
|
for (chain = iptc_first_chain(&h), i = 0;
|
|
chain;
|
|
chain = iptc_next_chain(&h)) {
|
|
if ( iptc_builtin(chain, h) )
|
|
continue; /* if it is a built-in chain, ignore it */
|
|
|
|
/* ok, read the counters of this chain */
|
|
if ( !(counters = iptc_read_counter(chain, 0, &h)) ) {
|
|
printf("Error reading %s: %s\n", chain, iptc_strerror(errno));
|
|
exit(errno);
|
|
}
|
|
|
|
/* check that we do not have more chains than we can process */
|
|
if ( i >= MAXUSERCHAINS ) {
|
|
printf("Maximum of %d user chains exceeded!!\n", MAXUSERCHAINS);
|
|
exit(1);
|
|
}
|
|
|
|
/* this chain counter has not been initialized; initialize it */
|
|
if ( bw[i].start == 0 ) {
|
|
bw[i].icnt = counters->bcnt;
|
|
bw[i].start = 1;
|
|
}
|
|
|
|
/* this chain has a previous measure; take the current one */
|
|
else {
|
|
bw[i].ocnt = counters->bcnt;
|
|
if ( bw[i].ocnt == bw[i].icnt ) /* no new bytes flowing? */
|
|
bw[i].bw = 0; /* flow is zero */
|
|
else
|
|
/* flow in this chain is:
|
|
* current bytes count (bw[i].octn) *minus*
|
|
* previous bytes count (bw[i].icnt) *divided by*
|
|
* 128.0 to convert bytes to kbits *and divided by*
|
|
* difference in times in seconds *to get*
|
|
* flow in kbits/sec that is what we want.
|
|
*/
|
|
bw[i].bw = (bw[i].ocnt - bw[i].icnt) / (128.0 * delta(to, ti));
|
|
|
|
/* do you want current flow of this chain? initialize previous
|
|
* bytes count to current bytes count; we get the flow in last
|
|
* SLEEPTIME elapsed time.
|
|
*/
|
|
if ( act_bw )
|
|
bw[i].icnt = bw[i].ocnt;
|
|
ok = 1; /* ok, we have some measure to show */
|
|
}
|
|
++i; /* next chain, please */
|
|
}
|
|
|
|
/* we iterate and i == 0; we do not have user chains at all */
|
|
if ( i == 0 ) {
|
|
printf("No user chains to meter!!\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* do you want to measure current flow? initialize previous time
|
|
* to actual time; we get the time elapsed in last SLEEPTIME.
|
|
*/
|
|
if ( act_bw )
|
|
ti = to;
|
|
|
|
/* do we have something to show? ok, display it */
|
|
if ( ok ) {
|
|
totbw = 0;
|
|
for ( j = 0; j < i; ++j ) {
|
|
totbw = totbw + bw[j].bw; /* calculate total flow */
|
|
}
|
|
printf("%s%6.1fk:%s ", col[7], totbw, col[8]); /* display total */
|
|
for ( j = 0; j < i; ++j ) { /* display flow of each chain in color */
|
|
printf("%s%6.1fk%s ", col[j], bw[j].bw, col[8]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
sleep(SLEEPTIME); /* rest a little; you go too fast */
|
|
} /* give us enough time in order to let some bytes flow */
|
|
|
|
exit(0); /* bye, we have our measures!! */
|
|
|
|
} /* main */
|
|
</screen>
|
|
<para>
|
|
Write your program and compile as before:
|
|
</para>
|
|
<screen>
|
|
bash# <command>./ipt-cc bw</command>
|
|
</screen>
|
|
<para>
|
|
Before using the meter we need to set our environment.
|
|
</para>
|
|
<para>
|
|
First, we have to have at least 2 PCs connected in a network. This is our
|
|
diagram configuration:
|
|
</para>
|
|
<screen>
|
|
+--------+ eth0 eth0 +--------+
|
|
| PC #1 +-----------------+ PC #2 |
|
|
+--------+ +--------+
|
|
eth0=192.168.1.1 eth0=192.168.1.2
|
|
</screen>
|
|
<para>
|
|
Second, we need to install a very nice and useful package called
|
|
<emphasis>netcat</emphasis> written by Hobbit. This
|
|
<emphasis>excellent</emphasis> package will help us to inject and receive
|
|
a flow of bytes between 2 NICs. If you don't have the package in your
|
|
system, download it from <ulink url="http://rr.sans.org/audit/netcat.php">
|
|
http://rr.sans.org/audit/netcat.php</ulink>.
|
|
</para>
|
|
<para>
|
|
The version that I use is <emphasis>1.10-277</emphasis>. To install it follow
|
|
these instructions:
|
|
</para>
|
|
<screen>
|
|
bash# <command>cp netcat-1.10.tar.gz /usr/local/src</command>
|
|
bash# <command>tar xzvf netcat-1.10.tar.gz</command>
|
|
bash# <command>cd netcat-1.10</command>
|
|
</screen>
|
|
<para>
|
|
My version requires to make a patch first; check yours if you have a file
|
|
with a <emphasis>.dif</emphasis> extension and apply it too:
|
|
</para>
|
|
<screen>
|
|
bash# <command>patch -p0 -i netcat-1.10.dif</command>
|
|
</screen>
|
|
<para>
|
|
Next compile the package using <emphasis>make</emphasis>:
|
|
</para>
|
|
<screen>
|
|
bash# <command>make linux</command>
|
|
</screen>
|
|
<para>
|
|
Copy the binary <emphasis>nc</emphasis> to your user bin directory:
|
|
</para>
|
|
<screen>
|
|
bash# <command>cp nc /usr/bin</command>
|
|
</screen>
|
|
<para>
|
|
And also to the second PC in your network:
|
|
</para>
|
|
<screen>
|
|
bash# <command>scp nc 192.168.1.2:/usr/bin</command>
|
|
</screen>
|
|
<para>
|
|
We are going to use <emphasis>netcat</emphasis> to
|
|
<quote>listen</quote> to a flow of bytes from PC #2 and
|
|
to <quote>talk</quote> from PC #1. Using tty1 to tty4
|
|
consoles on PC #2 let's start <emphasis>netcat</emphasis> to
|
|
listen from this PC. Go to PC #2 and in tty1 type:
|
|
</para>
|
|
<screen>
|
|
bash# <command>nc -n -v -l -s 192.168.1.2 -p 1001 >/dev/null</command>
|
|
</screen>
|
|
<para>
|
|
<emphasis>netcat</emphasis> must respond with:
|
|
</para>
|
|
<screen>
|
|
listening on [192.168.1.2] 1001 ...
|
|
</screen>
|
|
<para>
|
|
This command started <emphasis>netcat</emphasis> to listen from address
|
|
<emphasis>192.168.1.2</emphasis> using port number <emphasis>1001</emphasis>.
|
|
Arguments are: <emphasis>-n</emphasis> = use numeric address identification;
|
|
<emphasis>-v</emphasis> = verbose; <emphasis>-l</emphasis> = listen. All the
|
|
flow that <emphasis>netcat</emphasis> receives in
|
|
<emphasis>192.168.1.2:1001</emphasis> will be redirected to the
|
|
<quote>black hole</quote> in <filename>/dev/null</filename>.
|
|
</para>
|
|
<para>
|
|
Repeat the command in tty2, tty3 and tty4; change to tty2 using
|
|
<keycap>ALT-F2</keycap> and after logging in write:
|
|
</para>
|
|
<screen>
|
|
bash# <command>nc -n -v -l -s 192.168.1.2 -p 1002 >/dev/null</command>
|
|
</screen>
|
|
<para>
|
|
Now we are <quote>listening</quote> to the same address but port
|
|
number <emphasis>1002</emphasis>.
|
|
</para>
|
|
<para>
|
|
Go on now with tty3:
|
|
</para>
|
|
<screen>
|
|
bash# <command>nc -n -v -l -s 192.168.1.2 -p 1003 >/dev/null</command>
|
|
</screen>
|
|
<para>
|
|
And tty4:
|
|
</para>
|
|
<screen>
|
|
bash# <command>nc -n -v -l -s 192.168.1.2 -p 1004 >/dev/null</command>
|
|
</screen>
|
|
<para>
|
|
Now we are listening in PC #2, address
|
|
<emphasis>192.168.1.2</emphasis> in ports <emphasis>1001</emphasis>,
|
|
<emphasis>1002</emphasis>, <emphasis>1003</emphasis> and
|
|
<emphasis>1004</emphasis>.
|
|
</para>
|
|
<para>
|
|
Come back to PC #1 and let's set the environment to allow
|
|
<emphasis>iptables</emphasis> to help us to complete our tests:
|
|
</para>
|
|
<para>
|
|
On PC #1, type the into tty1 as follows:
|
|
</para>
|
|
<screen>
|
|
bash# <command>iptables -F</command>
|
|
bash# <command>iptables -X</command>
|
|
bash# <command>iptables -N chn_1</command>
|
|
bash# <command>iptables -N chn_2</command>
|
|
bash# <command>iptables -N chn_3</command>
|
|
bash# <command>iptables -N chn_4</command>
|
|
bash# <command>iptables -A chn_1 -j ACCEPT</command>
|
|
bash# <command>iptables -A chn_2 -j ACCEPT</command>
|
|
bash# <command>iptables -A chn_3 -j ACCEPT</command>
|
|
bash# <command>iptables -A chn_4 -j ACCEPT</command>
|
|
bash# <command>iptables -A OUTPUT -o eth0 -p tcp --dport 1001 -j chn_1</command>
|
|
bash# <command>iptables -A OUTPUT -o eth0 -p tcp --dport 1002 -j chn_2</command>
|
|
bash# <command>iptables -A OUTPUT -o eth0 -p tcp --dport 1003 -j chn_3</command>
|
|
bash# <command>iptables -A OUTPUT -o eth0 -p tcp --dport 1004 -j chn_4</command>
|
|
</screen>
|
|
<para>
|
|
These commands will:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Flush all chains in table <emphasis>filter</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Delete all user chains in table <emphasis>filter</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Create user chains <emphasis>chn_1</emphasis>,
|
|
<emphasis>chn_2</emphasis>, <emphasis>chn_3</emphasis> and
|
|
<emphasis>chn_4</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Establish a target <emphasis>ACCEPT</emphasis> in each user chain.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Create 4 rules in chain <emphasis>OUTPUT</emphasis> that matches
|
|
port numbers <emphasis>1001</emphasis> to
|
|
<emphasis>1004</emphasis> and target it to user chains
|
|
<emphasis>chn_1</emphasis> to <emphasis>chn_4</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
Now start the <emphasis>bw</emphasis> meter using current values:
|
|
</para>
|
|
<screen>
|
|
bash# <command>./bw -c</command>
|
|
</screen>
|
|
<para>
|
|
It must respond with:
|
|
</para>
|
|
<screen>
|
|
Displaying current flow values ...
|
|
0.0k: 0.0k 0.0k 0.0k 0.0k
|
|
0.0k: 0.0k 0.0k 0.0k 0.0k
|
|
0.0k: 0.0k 0.0k 0.0k 0.0k
|
|
0.0k: 0.0k 0.0k 0.0k 0.0k
|
|
</screen>
|
|
<para>
|
|
It informs that measures are current flows. Every line is a measure
|
|
taken each <emphasis>SLEEPTIME</emphasis> lapse (1 second in our
|
|
program). First column (in black) are total flow, next columns (in red,
|
|
green, orange and blue) are flows in chains <emphasis>chn_1</emphasis>,
|
|
<emphasis>chn_2</emphasis>, <emphasis>chn_3</emphasis> and
|
|
<emphasis>chn_4</emphasis> respectively. Of course we do not have any
|
|
flow now. However let <emphasis>bw</emphasis> run and continue reading.
|
|
</para>
|
|
<para>
|
|
Let's start now one of our byte flows; go to tty2 in PC #1 with
|
|
<keycap>ALT-F2</keycap> and after logging in, type:
|
|
</para>
|
|
<screen>
|
|
bash# <command>yes 000000000000000000 | nc -n -v -s 192.168.1.1 -p 2001 192.168.1.2 1001</command>
|
|
</screen>
|
|
<para>
|
|
<emphasis>netcat</emphasis> responds with:
|
|
</para>
|
|
<screen>
|
|
(UNKNOWN) [192.168.1.2] 1000 (?) open
|
|
</screen>
|
|
<para>
|
|
Now we have a flow of bytes from PC #1 to PC #2. <emphasis>yes</emphasis>
|
|
generates a constant flow of zeroes; this flow is piped to
|
|
<emphasis>netcat</emphasis> through address <emphasis>192.168.1.1</emphasis>,
|
|
port <emphasis>2001</emphasis> and sends it to PC #2, address
|
|
<emphasis>192.168.1.2</emphasis>, port <emphasis>1001</emphasis>
|
|
(where PC #2 is listening).
|
|
</para>
|
|
<para>
|
|
Check now the display of <emphasis>bw</emphasis> in tty1:
|
|
</para>
|
|
<screen>
|
|
7653.2k: 7653.2k 0.0k 0.0k 0.0k
|
|
7829.5k: 7829.5k 0.0k 0.0k 0.0k
|
|
7786.7k: 7786.7k 0.0k 0.0k 0.0k
|
|
7892.1k: 7982.1k 0.0k 0.0k 0.0k
|
|
</screen>
|
|
<para>
|
|
Your mileage can vary depending of the physical characteristics of your
|
|
system. In mine I have a flow of aproximately 7700 kbits/sec in the first
|
|
chain <emphasis>chn_1</emphasis> which corresponds to port number
|
|
<emphasis>1001</emphasis> in PC #2.
|
|
</para>
|
|
<para>
|
|
Let's start now the second bytes flow; go to tty3 in PC #1 with
|
|
<keycap>ALT-F3</keycap> and after logging in, type:
|
|
</para>
|
|
<screen>
|
|
bash# <command>yes 000000000000000000 | nc -n -v -s 192.168.1.1 -p 2002 192.168.1.2 1002</command>
|
|
</screen>
|
|
<para>
|
|
<emphasis>netcat</emphasis> responds with:
|
|
</para>
|
|
<screen>
|
|
(UNKNOWN) [192.168.1.2] 1002 (?) open
|
|
</screen>
|
|
<para>
|
|
Now we have 2 flows of bytes from PC #1 to PC #2; one from
|
|
<emphasis>192.168.1.1:2001</emphasis> to
|
|
<emphasis>192.168.1.2:1001</emphasis> and another from
|
|
<emphasis>192.168.1.1:2002</emphasis> to
|
|
<emphasis>192.168.1.2:1002</emphasis>.
|
|
</para>
|
|
<para>
|
|
Now check the display of <emphasis>bw</emphasis> in tty1:
|
|
</para>
|
|
<screen>
|
|
7819.6k: 4144.2k 3675.4k 0.0k 0.0k
|
|
8090.5k: 3923.9k 4166.6k 0.0k 0.0k
|
|
7794.7k: 3920.8k 3873.9k 0.0k 0.0k
|
|
7988.3k: 3754.6k 4233.7k 0.0k 0.0k
|
|
</screen>
|
|
<para>
|
|
Now we have 2 flows; each of them is more or less 50% of the total flow
|
|
going out of the computer. The Linux kernel tries to balance the bandwidth
|
|
available between the 2 channels of output.
|
|
</para>
|
|
<para>
|
|
To continue, start the 2 aditional flows through channels
|
|
<emphasis>192.168.1.1:2003-192.168.1.2:1003</emphasis> and
|
|
<emphasis>192.168.1.1:2004-192.168.1.2:1004</emphasis>.
|
|
</para>
|
|
<para>
|
|
In tty4 type:
|
|
</para>
|
|
<screen>
|
|
bash# <command>yes 000000000000000000 | nc -n -v -s 192.168.1.1 -p 2003 192.168.1.2 1003</command>
|
|
</screen>
|
|
<para>
|
|
In tty5 type:
|
|
</para>
|
|
<screen>
|
|
bash# <command>yes 000000000000000000 | nc -n -v -s 192.168.1.1 -p 2004 192.168.1.2 1004</command>
|
|
</screen>
|
|
<para>
|
|
The display of <emphasis>bw</emphasis> in tty1 will be something like:
|
|
</para>
|
|
<screen>
|
|
8120.6k: 1705.3k 2354.9k 1898.6k 2161.8k
|
|
7765.3k: 1634.2k 2560.2k 2011.4k 1559.5k
|
|
7911.9k: 1699.8k 2090.3k 1768.0k 2353.8k
|
|
8309.4k: 1734.5k 1999.7k 1999.9k 2575.3k
|
|
</screen>
|
|
<para>
|
|
Total bandwidth is distributed between the 4 channels of flow.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="cflows" label="14">
|
|
<title>Controlling flows</title>
|
|
<para>
|
|
In this chapter we are going to try to control the flows using the Linux
|
|
kernel queue disciplines. Perhaps, depending on how you compiled your
|
|
kernel, you will again need to run <command>make menuconfig</command>,
|
|
re-configure your options, re-compile and re-install your kernel.
|
|
</para>
|
|
<para>
|
|
This chapter <emphasis>is not</emphasis> and
|
|
<emphasis>does not pretend to be</emphasis> a tutorial about the
|
|
implementation of <emphasis>QoS (Quality of Service)</emphasis> in Linux.
|
|
If you don't have previous experience with <emphasis>QoS</emphasis>
|
|
it's better to read some references at the end of this document to acquire
|
|
the concepts required for <emphasis>QoS</emphasis> implementation.
|
|
</para>
|
|
<para>
|
|
With this advice, I'm not going to explain in detail each of the
|
|
commands needed to control flows in Linux because it is not the goal of
|
|
this HOWTO. However, the implementation of some of these techniques will
|
|
serve us to show the bandwidth meter (based on <emphasis>libiptc</emphasis>)
|
|
behaviour.
|
|
</para>
|
|
<para>
|
|
First check if you have QoS implementation options implemented in your
|
|
kernel. Run <command>make menuconfig</command>, follow the menu to
|
|
<emphasis>Networking options</emphasis> and look for last menu of this
|
|
option <emphasis>QoS and/or fair queueing</emphasis>. Here use (or check
|
|
if they are active) these options:
|
|
</para>
|
|
<screen>
|
|
[*] QoS and/or fair queueing
|
|
<M> CBQ packet scheduler
|
|
<M> CSZ packet scheduler
|
|
[*] ATM pseudo-scheduler
|
|
<M> The simplest PRIO pseudoscheduler
|
|
<M> RED queue
|
|
<M> SFQ queue
|
|
<M> TEQL queue
|
|
<M> TBF queue
|
|
<M> GRED queue
|
|
<M> Diffserv field marker
|
|
<M> Ingress Qdisc
|
|
[*] QoS support
|
|
[*] Rate estimator
|
|
[*] Packet classifier API
|
|
<M> TC index classifier
|
|
<M> Routing table based classifier
|
|
<M> Firewall based classifier
|
|
<M> U32 classifier
|
|
<M> Special RSVP classifier
|
|
<M> Special RSVP classifier for IPv6
|
|
[*] Traffic policing (needed for in/egress)
|
|
</screen>
|
|
<para>
|
|
Save your configuration, recompile your kernel and modules, and
|
|
re-install it. We are going to use the
|
|
<emphasis>CBQ packet scheduler</emphasis> to implement some queues
|
|
to control bytes flow in our PC #1 NIC.
|
|
</para>
|
|
<para>
|
|
Personally I preferred the excellent <emphasis>HTB queueing
|
|
discipline implementation</emphasis> by Martin Devera but actually this
|
|
implementation is not in standard Linux (but it will be); for
|
|
implementing it you have to patch your kernel before recompiling and
|
|
it's better not to complicate things more. However I have to say that
|
|
this queue discipline is a lot more simple to use than
|
|
<emphasis>CBQ</emphasis> happens to be. More information on
|
|
<emphasis>HTB queueing discipline</emphasis> are linked at the end of
|
|
this document.
|
|
</para>
|
|
<para>
|
|
Having compiled and re-installed your kernel you have to install the
|
|
<emphasis>iproute2</emphasis> package that will be used to run the
|
|
commands needed to implement the queues. Download this package from
|
|
<ulink url="ftp://ftp.inr.ac.ru/ip-routing">ftp://ftp.inr.ac.ru/ip-routing</ulink>.
|
|
</para>
|
|
<para>
|
|
I'm working with version <emphasis>2.2.4-now-ss001007</emphasis>. To install
|
|
it follow these instructions:
|
|
</para>
|
|
<screen>
|
|
bash# <command>cp iproute2-2.2.4-now-ss001007.tar.gz /usr/local/src</command>
|
|
bash# <command>tar xzvf iproute2-2.2.4-now-ss001007.tar.gz</command>
|
|
bash# <command>cd iproute2</command>
|
|
bash# <command>make</command>
|
|
</screen>
|
|
<para>
|
|
After <emphasis>make</emphasis> compiles the <emphasis>iproute2</emphasis>
|
|
package successfully the <emphasis>ip</emphasis> utility will be in
|
|
<filename>iproute2/ip</filename> directory and the
|
|
<emphasis>tc</emphasis> utility in <filename>iproute2/tc</filename>
|
|
directory. Copy both of them to <filename>/usr/bin</filename> directory:
|
|
</para>
|
|
<screen>
|
|
bash# <command>cp ip/ip /usr/bin</command>
|
|
bash# <command>cp tc/tc /usr/bin</command>
|
|
</screen>
|
|
<para>
|
|
Now, using the <emphasis>tc</emphasis> utility, we are going to create a
|
|
<emphasis>CBQ</emphasis> queue in the interface <emphasis>eth0</emphasis> of
|
|
the PC #1 computer. This queue will have 4 classes as children and each of
|
|
these classes will be used to control the 4 flows from
|
|
<emphasis>192.168.1.1</emphasis> to <emphasis>192.168.1.2</emphasis>
|
|
through ports <emphasis>1001</emphasis> to <emphasis>1004</emphasis>.
|
|
</para>
|
|
<para>
|
|
Write and run the following commands:
|
|
</para>
|
|
<screen>
|
|
bash# <command>tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 10Mbit \
|
|
avpkt 1000 cell 8</command>
|
|
</screen>
|
|
<para>
|
|
This command creates the main (root) cbq queue 1:0 in the
|
|
<emphasis>eth0</emphasis> interface; the bandwidth of this queue is
|
|
10Mbit/sec corresponding to our Ethernet interface.
|
|
</para>
|
|
<para>
|
|
Now write and run:
|
|
</para>
|
|
<screen>
|
|
bash# <command>tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 10Mbit \
|
|
rate 1000kbit prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded</command>
|
|
</screen>
|
|
<para>
|
|
This command create the main cbq class 1:1. The rate of this class
|
|
will be 1000kbit/sec.
|
|
</para>
|
|
<para>
|
|
Now we are going to create 4 classes ownned by this class; the classes
|
|
will have rates of 100kbit, 200kbit, 300kbit and 400kbit respectively.
|
|
Write and run these commands:
|
|
</para>
|
|
<screen>
|
|
bash# <command>tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 10Mbit \
|
|
rate 100kbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000</command>
|
|
|
|
bash# <command>tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 10Mbit \
|
|
rate 200kbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000</command>
|
|
|
|
bash# <command>tc class add dev eth0 parent 1:1 classid 1:5 cbq bandwidth 10Mbit \
|
|
rate 300kbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000</command>
|
|
|
|
bash# <command>tc class add dev eth0 parent 1:1 classid 1:6 cbq bandwidth 10Mbit \
|
|
rate 400kbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000</command>
|
|
</screen>
|
|
<para>
|
|
Each of these classes will have a <emphasis>sfq</emphasis> queue discipline
|
|
attached to them to dispatch their packets. Write and run these commands:
|
|
</para>
|
|
<screen>
|
|
bash# <command>tc qdisc add dev eth0 parent 1:3 handle 30: sfq perturb 15</command>
|
|
bash# <command>tc qdisc add dev eth0 parent 1:4 handle 40: sfq perturb 15</command>
|
|
bash# <command>tc qdisc add dev eth0 parent 1:5 handle 50: sfq perturb 15</command>
|
|
bash# <command>tc qdisc add dev eth0 parent 1:6 handle 60: sfq perturb 15</command>
|
|
</screen>
|
|
<para>
|
|
These commands create 4 <emphasis>sfq</emphasis> queue disciplines, one
|
|
for each class. <emphasis>sfq</emphasis> queue discipline is some kind of
|
|
<emphasis>fair controlling queue</emphasis>. It tries to give to each connection
|
|
in an interface same oportunity to their packets to be dispatched to at all.
|
|
</para>
|
|
<para>
|
|
Finally we are going to create filters to assign flows to ports
|
|
<emphasis>1001</emphasis>, <emphasis>1002</emphasis>, <emphasis>1003</emphasis>
|
|
and <emphasis>1004</emphasis> to classes <emphasis>1:3</emphasis>,
|
|
<emphasis>1:4</emphasis>, <emphasis>1:5</emphasis> and
|
|
<emphasis>1:6</emphasis> respectively. Write and run as follows:
|
|
</para>
|
|
<screen>
|
|
bash# <command>tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
|
|
dport 1001 0xffff flowid 1:3</command>
|
|
|
|
bash# <command>tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
|
|
dport 1002 0xffff flowid 1:4</command>
|
|
|
|
bash# <command>tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
|
|
dport 1003 0xffff flowid 1:5</command>
|
|
|
|
bash# <command>tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
|
|
dport 1004 0xffff flowid 1:6</command>
|
|
</screen>
|
|
<para>
|
|
After running all these commands, now check your <emphasis>bw</emphasis>
|
|
meter (you must be running <emphasis>netcat</emphasis> listening at ports
|
|
<emphasis>1001</emphasis> to <emphasis>1004</emphasis> in PC #2 and
|
|
talking in PC #1 as was explained in previous chapter and <emphasis>bw</emphasis>
|
|
running in <emphasis>current -c</emphasis> mode). You will have something
|
|
like this:
|
|
</para>
|
|
<screen>
|
|
Current flow values ...
|
|
1099.9k: 108.8k 196.5k 337.9k 456.8k
|
|
1104.2k: 115.3k 184.9k 339.9k 464.1k
|
|
1102.1k: 117.3k 174.7k 339.7k 470.5k
|
|
1114.4k: 113.6k 191.7k 340.7k 468.4k
|
|
1118.4k: 113.7k 194.3k 340.5k 469.9k
|
|
</screen>
|
|
<para>
|
|
<emphasis>bw</emphasis> show us how flows are controlling using queue
|
|
disciplines of the Linux kernel. As you see,
|
|
<emphasis>CBQ queue discipline</emphasis> is not a very precise queue but
|
|
you more or less have a flow of approximately
|
|
<emphasis>1000=100+200+300+400</emphasis> on interface
|
|
<emphasis>eth0</emphasis>.
|
|
</para>
|
|
<para>
|
|
To step back, write and run as follows:
|
|
</para>
|
|
<screen>
|
|
bash# <command>tc qdisc del dev eth0 root handle 1:0 cbq</command>
|
|
</screen>
|
|
<para>
|
|
on PC #1, to delete the main (root) queue discipline and owned classes
|
|
and filters.
|
|
</para>
|
|
<screen>
|
|
bash# <command>killall nc</command>
|
|
</screen>
|
|
<para>
|
|
on PC #2 and PC #1, to stop <emphasis>netcat</emphasis>.
|
|
</para>
|
|
<screen>
|
|
bash# <command>iptables -F</command>
|
|
bash# <command>iptables -X</command>
|
|
</screen>
|
|
<para>
|
|
on PC #1, to clear <emphasis>iptables</emphasis> rules and chains.
|
|
</para>
|
|
<screen>
|
|
bash# <command>Ctrl-C</command>
|
|
</screen>
|
|
<para>
|
|
on PC #1, tty1 to stop <emphasis>bw</emphasis> bandwidth meter.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="somelinks" label="15">
|
|
<title>Some interesting links</title>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://netfilter.samba.org/">
|
|
iptables-1.2.6 by Paul Russell</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://netfilter.samba.org/documentation/HOWTO/">
|
|
Linux netfilter Hacking HOWTO by Paul Russell</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://www.linuxgrill.com/iproute2-toc.html">
|
|
iproute2 by Alexey Kuznetsov</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://www.tldp.org/HOWTO/Adv-Routing-HOWTO.html">
|
|
Advance routing Linux HOWTO</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://luxik.cdi.cz/~devik/qos/htb/htbtheory.htm">
|
|
HTB queueing discipline implementation by Martin Devera</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://qos.ittc.ukans.edu/howto/howto.html">
|
|
Linux-Advance Networking Overview by Saravanan Radhakrishnan</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://www.docum.org/">
|
|
monitor.pl by Stef Coene</ulink>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<ulink url="http://rr.sans.org/audit/netcat.php">
|
|
netcat by Hobbit</ulink>.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</sect1>
|
|
|
|
<sect1 id="author" label="16">
|
|
<title>About the author</title>
|
|
<para>
|
|
Leonardo Balliache is a power electrical engineer that left high voltage
|
|
lines, transformers and protection relays in 1983 to dedicated full of his
|
|
time to computer sciences.
|
|
</para>
|
|
<para>
|
|
He is the General Manager of OpalSoft, a venezuelan company dedicated to
|
|
business packages software development.
|
|
</para>
|
|
<para>
|
|
In 1989 he started learning Unix using Coherent operating system. After
|
|
this he was interested in Linux and specially in bandwidth bottleneck
|
|
problems, bandwidth controlling, packet filtering and hierarching, Linux
|
|
QoS (Quality of Service), advanced routing, network protection, firewalling,
|
|
private network connection through the Internet and solving line and server
|
|
load balancing problems.
|
|
</para>
|
|
<para>
|
|
His company will be opening a new area of business offering Linux
|
|
QoS solution implementations in Venezuela.
|
|
</para>
|
|
<para>
|
|
Married to Cielo, with 3 sons (Jose, Dario, Gustavo), he can be reached at
|
|
<ulink url="mailto:leonardo@opalsoft.net">leonardo@opalsoft.net</ulink>.
|
|
He is working now (please be patient) to open a QoS Linux information site
|
|
at <ulink url="http://opalsoft.net/qos/">
|
|
http://opalsoft.net/qos/</ulink> to interchange knowledge with people
|
|
interested and to make his works in the Linux <quote>best of all</quote>
|
|
operating system available to the public.
|
|
</para>
|
|
<para>
|
|
April 30, 2002
|
|
</para>
|
|
<para>
|
|
Caracas, Venezuela
|
|
</para>
|
|
</sect1>
|
|
|
|
</article>
|
|
|