<?xml version="1.0"?>
<article id="qlibiptc" lang="en"><articleinfo><title>Querying libiptc HOWTO</title><author><firstname>Leonardo</firstname><surname>Balliache</surname><affiliation><address format="linespecific"><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 label="1" id="legal"><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 label="2" id="translat"><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 inheritnum="ignore" continuation="restarts"><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 label="3" id="disclaim"><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 label="4" id="credits"><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 label="5" id="object"><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 moreinfo="none">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 label="6" id="whatis"><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 label="7" id="howdidi"><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 label="8" id="previous"><title>Previous knowledge and system requirements</title><para>You have to have some previous knowledge to follow this document:</para><orderedlist inheritnum="ignore" continuation="restarts"><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 moreinfo="none">/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 moreinfo="none">make menuconfig</command>, you
must compile and install the kernel as usual.</para></listitem><listitem><para>Reboot your new kernel using <command moreinfo="none">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 label="9" id="install"><title>Installing iptables + libiptc</title><para>To install <emphasis>libiptc</emphasis> follow these steps:</para><orderedlist inheritnum="ignore" continuation="restarts"><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 moreinfo="none">/usr/local/src</filename>:</para><screen format="linespecific">bash# <command moreinfo="none">cp iptables-1.2.6.tar.bz2 /usr/local/src</command></screen></listitem><listitem><para> Unpack:</para><screen format="linespecific">bash# <command moreinfo="none">tar xjvf iptables-1.2.6.tar.bz2</command></screen></listitem><listitem><para> Go into the iptables directory:</para><screen format="linespecific">bash# <command moreinfo="none">cd iptables-1.2.6</command></screen></listitem><listitem><para>Check to see if your kernel needs some aditional patches with:</para><screen format="linespecific">bash# <command moreinfo="none">make pending-patches</command> <emphasis>KERNEL_DIR=/usr/src/linux</emphasis></screen><para>If your kernel source is located somewhere other than in 
<filename moreinfo="none">/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 moreinfo="none">y</keycap> (apply the patch) or <keycap moreinfo="none">N</keycap> (skip this patch). 
In some cases answering <keycap moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">make</command> <emphasis>KERNEL_DIR=/usr/src/linux</emphasis></screen><para>Again, if your kernel source is not at <filename moreinfo="none">/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 format="linespecific">bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">rpm -e iptables</command></screen></listitem><listitem><para>Install the new created package:</para><screen format="linespecific">bash# <command moreinfo="none">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 moreinfo="none">/usr/local/sbin</filename>, the manuals 
in <filename moreinfo="none">/usr/local/man/man8</filename> and the modules in 
<filename moreinfo="none">/usr/local/lib/iptables</filename>.</para></listitem><listitem><para>Finally install the headers, development libraries and associated
development man pages, with:</para><screen format="linespecific">bash# <command moreinfo="none">make install-devel</command></screen><para>This command will install the <emphasis>libiptc</emphasis> library 
in <filename moreinfo="none">/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 format="linespecific">bash# <command moreinfo="none">cd /usr/local/src/iptables-1.2.6</command>
bash# <command moreinfo="none">cp include/iptables.h /usr/local/include</command>
bash# <command moreinfo="none">cp include/iptables_common.h /usr/local/include</command>
bash# <command moreinfo="none">mkdir /usr/local/include/libiptc</command>
bash# <command moreinfo="none">cp include/libiptc/libiptc.h /usr/local/include/libiptc</command>
bash# <command moreinfo="none">cp include/libiptc/ipt_kernel_headers.h /usr/local/include/libiptc</command>
bash# <command moreinfo="none">cp iptables.o /usr/local/lib</command></screen><para><filename moreinfo="none">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 label="10" id="howtoprg"><title>How to create your program(s)</title><para>Create your program(s) in <filename moreinfo="none">/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 format="linespecific">/* My program */

#include entgetopt.hent
#include entsys/errno.hent
#include entstdio.hent
#include entfcntl.hent
#include entstdlib.hent
#include entstring.hent
#include entdlfcn.hent
#include enttime.hent
#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 label="11" id="qfunction"><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 moreinfo="none">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 moreinfo="none">iptables-save.c</filename>
for how to invoke this function:</para><screen format="linespecific">  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 format="linespecific">/*
 * How to use libiptc- program #1
 * /usr/local/src/p1.c
 */

#include entgetopt.hent
#include entsys/errno.hent
#include entstdio.hent
#include entfcntl.hent
#include entstdlib.hent
#include entstring.hent
#include entdlfcn.hent
#include enttime.hent
#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(enth); chain; chain = iptc_next_chain(enth))  {
    printf("%s\n", chain);
  }

  exit(0);

} /* main */</screen><para>Write this program and save it as <filename moreinfo="none">p1.c</filename>
in <filename moreinfo="none">/usr/local/src</filename>.</para><para>Now write this <quote>bash</quote> script to simplify the compiling process:</para><screen format="linespecific">#!/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 moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">./ipt-cc p1</command></screen><para>And run it:</para><screen format="linespecific">bash# <command moreinfo="none">./p1</command></screen><para>You will get:</para><screen format="linespecific">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 format="linespecific">bash# <command moreinfo="none">iptables -N chain_1</command>
bash# <command moreinfo="none">iptables -N chain_2</command>
bash# <command moreinfo="none">./p1</command></screen><para>You will get:</para><screen format="linespecific">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 format="linespecific"><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 format="linespecific">/* 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 moreinfo="none">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 format="linespecific">/* 
 * How to use libiptc- program #2
 * /usr/local/src/p1.c
 */

#include entgetopt.hent
#include entsys/errno.hent
#include entstdio.hent
#include entfcntl.hent
#include entstdlib.hent
#include entstring.hent
#include entdlfcn.hent
#include enttime.hent
#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)entent24)ent0xFF,   \
(unsigned int)((n)entent16)ent0xFF,   \
(unsigned int)((n)entent8)ent0xFF,    \
(unsigned int)((n)ent0xFF)

#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 ent 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 ent 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-entu.user.name, TRY_LOAD);

  if (match) {
    printf("-m %s ", e-entu.user.name);

    /* some matches don't provide a save function */
    if (match-entsave)
      match-entsave(ip, e);
  } else {
    if (e-entu.match_size) {
      fprintf(stderr,
        "Can't find library for match `%s'\n",
        e-entu.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 entent !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-entcounters.pcnt, e-entcounters.bcnt);

  /* print chain name */
  printf("-A %s ", chain);

  /* Print IP part. */
  print_ip("-s", e-entip.src.s_addr,e-entip.smsk.s_addr,
      e-entip.invflags ent IPT_INV_SRCIP);  

  print_ip("-d", e-entip.dst.s_addr, e-entip.dmsk.s_addr,
      e-entip.invflags ent IPT_INV_DSTIP);

  print_iface('i', e-entip.iniface, e-entip.iniface_mask,
        e-entip.invflags ent IPT_INV_VIA_IN);

  print_iface('o', e-entip.outiface, e-entip.outiface_mask,
        e-entip.invflags ent IPT_INV_VIA_OUT);

  print_proto(e-entip.proto, e-entip.invflags ent IPT_INV_PROTO);

  if (e-entip.flags ent IPT_F_FRAG)
    printf("%s-f ",
           e-entip.invflags ent IPT_INV_FRAG ? "! " : "");

  /* Print matchinfo part */
  if (e-enttarget_offset) {
    IPT_MATCH_ITERATE(e, print_match, ente-entip);
  }

  /* Print target name */  
  target_name = iptc_get_target(e, h);
  if (target_name entent (*target_name != '\0'))
    printf("-j %s ", target_name);

  /* Print targinfo part */
  t = ipt_get_target((struct ipt_entry *)e);
  if (t-entu.user.name[0]) {
    struct iptables_target *target
      = find_target(t-entu.user.name, TRY_LOAD);

    if (!target) {
      fprintf(stderr, "Can't find library for target `%s'\n",
        t-entu.user.name);
      exit(1);
    }

    if (target-entsave)
      target-entsave(ente-entip, 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-entu.target_size != 
          sizeof(struct ipt_entry_target)) {
        fprintf(stderr, "Target `%s' is missing "
            "save function\n",
          t-entu.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(enth); chain; chain = iptc_next_chain(enth))  {
    printf("%s\n", chain);
    for (e = iptc_first_rule(chain, enth); e; e = iptc_next_rule(e, enth))  {
      print_rule(e, enth, chain, counters);
    }
  }

  exit(0);

} /* main */</screen><para>The function <emphasis>print_rule</emphasis> borrowed from 
<filename moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">./ipt-cc p2</command>
bash# <command moreinfo="none">./p2</command></screen><para>You will get:</para><screen format="linespecific">INPUT
FORWARD
OUTPUT
chain_1
chain_2</screen><para>Now modify the environment using <emphasis>iptables</emphasis> to add some rules:</para><screen format="linespecific">bash# <command moreinfo="none">iptables -A INPUT -p tcp -i eth0 -s ! 192.168.1.1 --dport 20 -j ACCEPT</command>
bash# <command moreinfo="none">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 format="linespecific">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 format="linespecific">/* 
 * How to use libiptc- program #3
 * /usr/local/src/p3.c
 */

#include entgetopt.hent
#include entsys/errno.hent
#include entstdio.hent
#include entfcntl.hent
#include entstdlib.hent
#include entstring.hent
#include entdlfcn.hent
#include enttime.hent
#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(enth); chain; chain = iptc_next_chain(enth))  {
    if ( !iptc_builtin(chain, h) )
      continue;
    if ( (policy = iptc_get_policy(chain, entcounters, enth)) )
      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 format="linespecific">bash# <command moreinfo="none">./ipt-cc p3</command>
bash# <command moreinfo="none">./p3</command></screen><para>You will get something like this:</para><screen format="linespecific">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 label="12" id="mfunction"><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 moreinfo="none">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 label="13" id="bmeter"><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 moreinfo="none">bw.c</filename>. 
It's well commented to be easy followed by everyone:</para><screen format="linespecific">/* 
 * 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 entgetopt.hent
#include entsys/errno.hent
#include entsys/time.hent
#include entstdio.hent
#include entfcntl.hent
#include entstdlib.hent
#include entstring.hent
#include entdlfcn.hent
#include enttime.hent
#include entunistd.hent
#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 ent 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(entbw, 0, MAXUSERCHAINS * sizeof(struct bwcnt));

  /* get time to start meter on variable ti */
  gettimeofday(entti, 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(entto, NULL);  /* have a time shoot */

    /* iterate through each chain of the table */
    for (chain = iptc_first_chain(enth), i = 0; 
         chain; 
         chain = iptc_next_chain(enth))  {
      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, enth)) )  {
         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 ent= 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-entbcnt;
        bw[i].start = 1;
      }

      /* this chain has a previous measure; take the current one */
      else  {
        bw[i].ocnt = counters-entbcnt;
        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 ent 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 ent 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 format="linespecific">bash# <command moreinfo="none">./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 format="linespecific">+--------+ 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 format="linespecific">bash# <command moreinfo="none">cp netcat-1.10.tar.gz /usr/local/src</command>
bash# <command moreinfo="none">tar xzvf netcat-1.10.tar.gz</command>
bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">patch -p0 -i netcat-1.10.dif</command></screen><para>Next compile the package using <emphasis>make</emphasis>:</para><screen format="linespecific">bash# <command moreinfo="none">make linux</command></screen><para>Copy the binary <emphasis>nc</emphasis> to your user bin directory:</para><screen format="linespecific">bash# <command moreinfo="none">cp nc /usr/bin</command></screen><para>And also to the second PC in your network:</para><screen format="linespecific">bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">nc -n -v -l -s 192.168.1.2 -p 1001 ent/dev/null</command></screen><para><emphasis>netcat</emphasis> must respond with:</para><screen format="linespecific">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 moreinfo="none">/dev/null</filename>.</para><para>Repeat the command in tty2, tty3 and tty4; change to tty2 using 
<keycap moreinfo="none">ALT-F2</keycap> and after logging in write:</para><screen format="linespecific">bash# <command moreinfo="none">nc -n -v -l -s 192.168.1.2 -p 1002 ent/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 format="linespecific">bash# <command moreinfo="none">nc -n -v -l -s 192.168.1.2 -p 1003 ent/dev/null</command></screen><para>And tty4:</para><screen format="linespecific">bash# <command moreinfo="none">nc -n -v -l -s 192.168.1.2 -p 1004 ent/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 format="linespecific">bash# <command moreinfo="none">iptables -F</command>
bash# <command moreinfo="none">iptables -X</command>
bash# <command moreinfo="none">iptables -N chn_1</command>
bash# <command moreinfo="none">iptables -N chn_2</command>
bash# <command moreinfo="none">iptables -N chn_3</command>
bash# <command moreinfo="none">iptables -N chn_4</command>
bash# <command moreinfo="none">iptables -A chn_1 -j ACCEPT</command>
bash# <command moreinfo="none">iptables -A chn_2 -j ACCEPT</command>
bash# <command moreinfo="none">iptables -A chn_3 -j ACCEPT</command>
bash# <command moreinfo="none">iptables -A chn_4 -j ACCEPT</command>
bash# <command moreinfo="none">iptables -A OUTPUT -o eth0 -p tcp --dport 1001 -j chn_1</command>
bash# <command moreinfo="none">iptables -A OUTPUT -o eth0 -p tcp --dport 1002 -j chn_2</command>
bash# <command moreinfo="none">iptables -A OUTPUT -o eth0 -p tcp --dport 1003 -j chn_3</command>
bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">./bw -c</command></screen><para>It must respond with:</para><screen format="linespecific">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 moreinfo="none">ALT-F2</keycap> and after logging in, type:</para><screen format="linespecific">bash# <command moreinfo="none">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 format="linespecific">(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 format="linespecific">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 moreinfo="none">ALT-F3</keycap> and after logging in, type:</para><screen format="linespecific">bash# <command moreinfo="none">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 format="linespecific">(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 format="linespecific">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 format="linespecific">bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">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 format="linespecific">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 label="14" id="cflows"><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 moreinfo="none">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 moreinfo="none">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 format="linespecific">       [*] QoS and/or fair queueing
       entMent CBQ packet scheduler
       entMent CSZ packet scheduler
       [*] ATM pseudo-scheduler
       entMent The simplest PRIO pseudoscheduler
       entMent RED queue
       entMent SFQ queue
       entMent TEQL queue
       entMent TBF queue
       entMent GRED queue
       entMent Diffserv field marker
       entMent Ingress Qdisc
       [*] QoS support
       [*]   Rate estimator
       [*] Packet classifier API
       entMent   TC index classifier
       entMent   Routing table based classifier
       entMent   Firewall based classifier
       entMent   U32 classifier
       entMent   Special RSVP classifier
       entMent   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 format="linespecific">bash# <command moreinfo="none">cp iproute2-2.2.4-now-ss001007.tar.gz /usr/local/src</command>
bash# <command moreinfo="none">tar xzvf iproute2-2.2.4-now-ss001007.tar.gz</command>
bash# <command moreinfo="none">cd iproute2</command>
bash# <command moreinfo="none">make</command></screen><para>After <emphasis>make</emphasis> compiles the <emphasis>iproute2</emphasis>
package successfully the <emphasis>ip</emphasis> utility will be in 
<filename moreinfo="none">iproute2/ip</filename> directory and the 
<emphasis>tc</emphasis> utility in <filename moreinfo="none">iproute2/tc</filename>
directory. Copy both of them to <filename moreinfo="none">/usr/bin</filename> directory:</para><screen format="linespecific">bash# <command moreinfo="none">cp ip/ip /usr/bin</command>
bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">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 moreinfo="none">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 moreinfo="none">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 moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">tc qdisc add dev eth0 parent 1:3 handle 30: sfq perturb 15</command>
bash# <command moreinfo="none">tc qdisc add dev eth0 parent 1:4 handle 40: sfq perturb 15</command>
bash# <command moreinfo="none">tc qdisc add dev eth0 parent 1:5 handle 50: sfq perturb 15</command>
bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
dport 1001 0xffff flowid 1:3</command>

bash# <command moreinfo="none">tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
dport 1002 0xffff flowid 1:4</command>

bash# <command moreinfo="none">tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
dport 1003 0xffff flowid 1:5</command>

bash# <command moreinfo="none">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 format="linespecific">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 format="linespecific">bash# <command moreinfo="none">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 format="linespecific">bash# <command moreinfo="none">killall nc</command></screen><para>on PC #2 and PC #1, to stop <emphasis>netcat</emphasis>.</para><screen format="linespecific">bash# <command moreinfo="none">iptables -F</command>
bash# <command moreinfo="none">iptables -X</command></screen><para>on PC #1, to clear <emphasis>iptables</emphasis> rules and chains.</para><screen format="linespecific">bash# <command moreinfo="none">Ctrl-C</command></screen><para>on PC #1, tty1 to stop <emphasis>bw</emphasis> bandwidth meter.</para></sect1><sect1 label="15" id="somelinks"><title>Some interesting links</title><orderedlist inheritnum="ignore" continuation="restarts"><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 label="16" id="author"><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>

