<HTML ><HEAD ><TITLE >Functions to query libiptc</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+ "><LINK REL="HOME" TITLE="Querying libiptc HOWTO" HREF="index.html"><LINK REL="PREVIOUS" TITLE="How to create your program(s)" HREF="howtoprg.html"><LINK REL="NEXT" TITLE="Functions to modify firewalling rules and statistics" HREF="mfunction.html"></HEAD ><BODY CLASS="SECT1" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="NAVHEADER" ><TABLE SUMMARY="Header navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TH COLSPAN="3" ALIGN="center" >Querying libiptc HOWTO</TH ></TR ><TR ><TD WIDTH="10%" ALIGN="left" VALIGN="bottom" ><A HREF="howtoprg.html" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" ></TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="mfunction.html" ACCESSKEY="N" >Next</A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="SECT1" ><H1 CLASS="SECT1" ><A NAME="QFUNCTION">11. Functions to query libiptc</H1 ><P >This section explains which functions allow you to query libiptc. We will use the header file of <EM >libiptc</EM >, file <TT CLASS="FILENAME" >usr/local/include/libiptc/libiptc.h</TT >, containing prototypes of each function as a reference to develop our explanation. </P ><P >I have also included a brief description (when available) taken from <A HREF="http://netfilter.samba.org/documentation/HOWTO/" TARGET="_top" >Linux netfilter Hacking HOWTO</A > within each function explanation.</P ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN233">11.1. iptc_init</H2 ><P ><B >Name: </B >iptc_init</P ><P ><B >Usage: </B >Takes a snapshot of the rules.</P ><P ><B >Prototype: </B >iptc_handle_t iptc_init(const char *tablename)</P ><P ><B >Description: </B >This function must be called as initiator before any other function can be called.</P ><P ><B >Parameters: </B ><EM >tablename</EM > is the name of the table we need to query and/or modify; this could be <EM >filter</EM >, <EM >mangle</EM >, <EM >nat</EM >, etc.</P ><P ><B >Returns: </B >Pointer to a structure of type <EM >iptc_handle_t</EM > that must be used as main parameter for the rest of functions we will call from <EM >libiptc</EM >. <EM >iptc_init</EM > returns the pointer to the structure or NULL if it fails. If this happens you can invoke <EM >iptc_strerror</EM > to get information about the error. See below.</P ><P >Have a look at this section of code in file <TT CLASS="FILENAME" >iptables-save.c</TT > for how to invoke this function:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" > h = iptc_init(tablename); if (!h) exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",iptc_strerror(errno));</PRE ></FONT ></TD ></TR ></TABLE ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN260">11.2. iptc_strerror</H2 ><P ><B >Name: </B >iptc_strerror</P ><P ><B >Usage: </B >Translates error numbers into more human-readable form.</P ><P ><B >Prototype: </B >const char *iptc_strerror(int err)</P ><P ><B >Description: </B >This function returns a more meaningful explanation of a failure code in the iptc library. If a function fails, it will always set <EM >errno</EM >. This value can be passed to <EM >iptc_strerror()</EM > to yield an error message.</P ><P ><B >Parameters: </B ><EM >err</EM > is an integer indicating the error number.</P ><P ><B >Returns: </B >Char pointer containing the error description.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN279">11.3. iptc_first_chain</H2 ><P ><B >Name: </B >iptc_first_chain</P ><P ><B >Usage: </B >Iterator functions to run through the chains.</P ><P ><B >Prototype: </B >const char *iptc_first_chain(iptc_handle_t *handle)</P ><P ><B >Description: </B >This function returns the first chain name in the table.</P ><P ><B >Parameters: </B >Pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Char pointer to the name of the chain.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN297">11.4. iptc_next_chain</H2 ><P ><B >Name: </B >iptc_next_chain</P ><P ><B >Usage: </B >Iterator functions to run through the chains.</P ><P ><B >Prototype: </B >const char *iptc_next_chain(iptc_handle_t *handle)</P ><P ><B >Description: </B >This function returns the next chain name in the table; NULL means no more chains.</P ><P ><B >Parameters: </B >Pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Char pointer to the name of the chain.</P ><P >These two previous functions allow to us to iterate through the chains of the table getting the name of each of the chains; <EM >iptc_first_chain</EM > returns the name of the first chain of the table; <EM >iptc_next_chain</EM > returns the name of next chains and NULL when the function reaches the end.</P ><P >We can create <EM >Program #1</EM > to exercise our understanding of these previous four functions:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >/* * How to use libiptc- program #1 * /usr/local/src/p1.c */ #include <getopt.h> #include <sys/errno.h> #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> #include <time.h> #include "libiptc/libiptc.h" #include "iptables.h" int main(void) { iptc_handle_t h; const char *chain = NULL; const char *tablename = "filter"; program_name = "p1"; program_version = NETFILTER_VERSION; h = iptc_init(tablename); if ( !h ) { printf("Error initializing: %s\n", iptc_strerror(errno)); exit(errno); } for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) { printf("%s\n", chain); } exit(0); } /* main */</PRE ></FONT ></TD ></TR ></TABLE ><P >Write this program and save it as <TT CLASS="FILENAME" >p1.c</TT > in <TT CLASS="FILENAME" >/usr/local/src</TT >.</P ><P >Now write this <SPAN CLASS="QUOTE" >"bash"</SPAN > script to simplify the compiling process:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >#!/bin/bash gcc -Wall -Wunused -DNETFILTER_VERSION=\"1.2.6\" -rdynamic -o $1 $1.c \ /usr/local/lib/iptables.o /usr/local/lib/libiptc.a -ldl</PRE ></FONT ></TD ></TR ></TABLE ><P >Save it as <TT CLASS="FILENAME" >ipt-cc</TT > and do not forget to <EM >chmod 0700 ipt-cc</EM >.</P ><P >Now compile your <EM >p1</EM > program:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >bash# <B CLASS="COMMAND" >./ipt-cc p1</B ></PRE ></FONT ></TD ></TR ></TABLE ><P >And run it:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >bash# <B CLASS="COMMAND" >./p1</B ></PRE ></FONT ></TD ></TR ></TABLE ><P >You will get:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >INPUT FORWARD OUTPUT</PRE ></FONT ></TD ></TR ></TABLE ><P >These are the three built-in iptables chains.</P ><P >Now create some new chains using iptables and run your program again:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >bash# <B CLASS="COMMAND" >iptables -N chain_1</B > bash# <B CLASS="COMMAND" >iptables -N chain_2</B > bash# <B CLASS="COMMAND" >./p1</B ></PRE ></FONT ></TD ></TR ></TABLE ><P >You will get:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >INPUT FORWARD OUTPUT chain_1 chain_2</PRE ></FONT ></TD ></TR ></TABLE ><P >Try to generate an error initializing tablename to <EM >myfilter</EM > instead of <EM >filter</EM >. When you compile and execute your program again, you will get:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" ><EM >Error initializing: Table does not exist (do you need to insmod?)</EM ></PRE ></FONT ></TD ></TR ></TABLE ><P ><EM >iptables</EM > informs you that <EM >myfilter</EM > does not exist as a table.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN355">11.5. iptc_is_chain</H2 ><P ><B >Name: </B >iptc_is_chain</P ><P ><B >Usage: </B >Check if a chain exists.</P ><P ><B >Prototype: </B >int iptc_is_chain(const char *chain, const iptc_handle_t handle)</P ><P ><B >Description: </B >This function checks to see if the chain described in the parameter <EM >chain</EM > exists in the table.</P ><P ><B >Parameters: </B ><EM >chain</EM > is a char pointer containing the name of the chain we want to check to. <EM >handle</EM > is a pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >integer value 1 (true) if the chain exists; integer value 0 (false) if the chain does not exist.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN376">11.6. iptc_builtin</H2 ><P ><B >Name: </B >iptc_builtin</P ><P ><B >Usage: </B >Is this a built-in chain?</P ><P ><B >Prototype: </B >int iptc_builtin(const char *chain, const iptc_handle_t handle)</P ><P ><B >Description: </B >This function is used to check if a given chain name is a built-in chain or not.</P ><P ><B >Parameters: </B ><EM >chain</EM > is a char pointer containing the name of the chain we want to check to. <EM >handle</EM > is a pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Returns integer value 1 (true) if the given chain name is the name of a builtin chain; returns integer value 0 (false) is not.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN396">11.7. iptc_first_rule</H2 ><P ><B >Name: </B >iptc_first_rule</P ><P ><B >Usage: </B >Get first rule in the given chain.</P ><P ><B >Prototype: </B >const struct ipt_entry *iptc_first_rule(const char *chain, iptc_handle_t *handle)</P ><P ><B >Description: </B >This function returns a pointer to the first rule in the given chain name; NULL for an empty chain.</P ><P ><B >Parameters: </B ><EM >chain</EM > is a char pointer containing the name of the chain we want to get the rules to. <EM >handle</EM > is a pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Returns a pointer to an <EM >ipt_entry</EM > structure containing information about the first rule of the chain. See below for an explanation of this structure.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN417">11.8. iptc_next_rule</H2 ><P ><B >Name: </B >iptc_next_rule</P ><P ><B >Usage: </B >Get the next rule in the given chain.</P ><P ><B >Prototype: </B >const struct ipt_entry *iptc_next_rule(const struct ipt_entry *prev, iptc_handle_t *handle)</P ><P ><B >Description: </B >This function returns a pointer to the next rule in the given chain name; NULL means the end of the chain.</P ><P ><B >Parameters: </B ><EM >prev</EM > is a pointer to a structure of type <EM >ipt_entry</EM > that must be obtained first by a previous call to the function <EM >iptc_first_rule</EM >. 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. <EM >handle</EM > is a pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Returns a pointer to an <EM >ipt_entry</EM > structure containing information about the next rule of the chain. See below for an explanation of this structure.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN440">11.9. iptc_get_target</H2 ><P ><B >Name: </B >iptc_get_target</P ><P ><B >Usage: </B >Get a pointer to the target name of this entry.</P ><P ><B >Prototype: </B >const char *iptc_get_target(const struct ipt_entry *e, iptc_handle_t *handle)</P ><P ><B >Description: </B >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 <EM >verdict</EM > field of the <EM >ipt_entry</EM > structure directly, as it offers the above further interpretations of the standard verdict.</P ><P ><B >Parameters: </B ><EM >e</EM > is a pointer to a structure of type <EM >ipt_entry</EM > that must be obtained first by a previous call to the function <EM >iptc_first_rule</EM > or the function <EM >iptc_next_rule</EM >. <EM >handle</EM > is a pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Returns a char pointer to the target name. See <EM >Description</EM > above for more information.</P ><P >Now it is time to explain the <EM >ipt_entry</EM > structure; these pieces of code are taken from <EM >iptables</EM > package sources:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >/* Internet address. */ struct in_addr { __u32 s_addr; }; /* Yes, Virginia, you have to zero the padding. */ struct ipt_ip { /* Source and destination IP addr */ struct in_addr src, dst; /* Mask for src and dest IP addr */ struct in_addr smsk, dmsk; char iniface[IFNAMSIZ], outiface[IFNAMSIZ]; unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ]; /* Protocol, 0 = ANY */ u_int16_t proto; /* Flags word */ u_int8_t flags; /* Inverse flags */ u_int8_t invflags; }; struct ipt_counters { u_int64_t pcnt, bcnt; /* Packet and byte counters */ }; /* This structure defines each of the firewall rules. Consists of 3 parts which are 1) general IP header stuff 2) match specific stuff 3) the target to perform if the rule matches */ struct ipt_entry { struct ipt_ip ip; /* Mark with fields that we care about. */ unsigned int nfcache; /* Size of ipt_entry + matches */ u_int16_t target_offset; /* Size of ipt_entry + matches + target */ u_int16_t next_offset; /* Back pointer */ unsigned int comefrom; /* Packet and byte counters. */ struct ipt_counters counters; /* The matches (if any), then the target. */ unsigned char elems[0]; };</PRE ></FONT ></TD ></TR ></TABLE ><P >An <EM >ipt_entry</EM > structure contains:</P ><P ></P ><UL ><LI ><P >An <EM >ipt_ip</EM > structure containing (for the rule) the source address and netmask <EM >(ip.src.s_addr, ip.smsk.s_addr)</EM >, the destination address and netmask <EM >(ip.dst.s_addr, ip.dmsk.s_addr)</EM >, the protocol <EM >(ip.proto)</EM >, a flags field <EM >(invflags)</EM > to check for inverse <EM >(!)</EM > selections <EM >(eg. ! 192.168.2.0/24, ! eth0, ! tcp, etc)</EM >, the input interface <EM >(iniface)</EM >, the output interface <EM >(outiface)</EM >, the input <EM >(iniface_mask)</EM > and output <EM >(outiface_mask)</EM > interface masks and the <EM >flags</EM > field to check for fragmented packets.</P ></LI ><LI ><P >An <EM >ipt_counters</EM > structure containing the packet <EM >(pcnt)</EM > and byte <EM >(bcnt)</EM > counter of the rule. This information is important for bandwidth measurement.</P ></LI ><LI ><P ><EM >target_offset</EM > that is used to get the target information of the rule.</P ></LI ><LI ><P >Unknown fields: <EM >nfcache, comefrom, elems, next_offset</EM >. If someone can give me a feedback about these fields I would be grateful.</P ></LI ></UL ><P >A simple way to work with all this information is to borrow some functions from <TT CLASS="FILENAME" >iptables-save.c</TT > by Paul Russell and Harald Welte.</P ><P >Here is another sample program <EM >Program #2</EM > written with a lot of help from Russell-Welte:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >/* * How to use libiptc- program #2 * /usr/local/src/p1.c */ #include <getopt.h> #include <sys/errno.h> #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> #include <time.h> #include "libiptc/libiptc.h" #include "iptables.h" <EM >/* Here begins some of the code taken from iptables-save.c **************** */</EM > #define IP_PARTS_NATIVE(n) \ (unsigned int)((n)>>24)&0xFF, \ (unsigned int)((n)>>16)&0xFF, \ (unsigned int)((n)>>8)&0xFF, \ (unsigned int)((n)&0xFF) #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) /* This assumes that mask is contiguous, and byte-bounded. */ static void print_iface(char letter, const char *iface, const unsigned char *mask, int invert) { unsigned int i; if (mask[0] == 0) return; printf("-%c %s", letter, invert ? "! " : ""); for (i = 0; i < IFNAMSIZ; i++) { if (mask[i] != 0) { if (iface[i] != '\0') printf("%c", iface[i]); } else { /* we can access iface[i-1] here, because * a few lines above we make sure that mask[0] != 0 */ if (iface[i-1] != '\0') printf("+"); break; } } printf(" "); } /* These are hardcoded backups in iptables.c, so they are safe */ struct pprot { char *name; u_int8_t num; }; /* FIXME: why don't we use /etc/protocols ? */ static const struct pprot chain_protos[] = { { "tcp", IPPROTO_TCP }, { "udp", IPPROTO_UDP }, { "icmp", IPPROTO_ICMP }, { "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, }; static void print_proto(u_int16_t proto, int invert) { if (proto) { unsigned int i; const char *invertstr = invert ? "! " : ""; for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++) if (chain_protos[i].num == proto) { printf("-p %s%s ", invertstr, chain_protos[i].name); return; } printf("-p %s%u ", invertstr, proto); } } static int print_match(const struct ipt_entry_match *e, const struct ipt_ip *ip) { struct iptables_match *match = find_match(e->u.user.name, TRY_LOAD); if (match) { printf("-m %s ", e->u.user.name); /* some matches don't provide a save function */ if (match->save) match->save(ip, e); } else { if (e->u.match_size) { fprintf(stderr, "Can't find library for match `%s'\n", e->u.user.name); exit(1); } } return 0; } /* print a given ip including mask if neccessary */ static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert) { if (!mask && !ip) return; printf("%s %s%u.%u.%u.%u", prefix, invert ? "! " : "", IP_PARTS(ip)); if (mask != 0xffffffff) printf("/%u.%u.%u.%u ", IP_PARTS(mask)); else printf(" "); } /* We want this to be readable, so only print out neccessary fields. * Because that's the kind of world I want to live in. */ static void print_rule(const struct ipt_entry *e, iptc_handle_t *h, const char *chain, int counters) { struct ipt_entry_target *t; const char *target_name; /* print counters */ if (counters) printf("[%llu:%llu] ", e->counters.pcnt, e->counters.bcnt); /* print chain name */ printf("-A %s ", chain); /* Print IP part. */ print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr, e->ip.invflags & IPT_INV_SRCIP); print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, e->ip.invflags & IPT_INV_DSTIP); print_iface('i', e->ip.iniface, e->ip.iniface_mask, e->ip.invflags & IPT_INV_VIA_IN); print_iface('o', e->ip.outiface, e->ip.outiface_mask, e->ip.invflags & IPT_INV_VIA_OUT); print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO); if (e->ip.flags & IPT_F_FRAG) printf("%s-f ", e->ip.invflags & IPT_INV_FRAG ? "! " : ""); /* Print matchinfo part */ if (e->target_offset) { IPT_MATCH_ITERATE(e, print_match, &e->ip); } /* Print target name */ target_name = iptc_get_target(e, h); if (target_name && (*target_name != '\0')) printf("-j %s ", target_name); /* Print targinfo part */ t = ipt_get_target((struct ipt_entry *)e); if (t->u.user.name[0]) { struct iptables_target *target = find_target(t->u.user.name, TRY_LOAD); if (!target) { fprintf(stderr, "Can't find library for target `%s'\n", t->u.user.name); exit(1); } if (target->save) target->save(&e->ip, t); else { /* If the target size is greater than ipt_entry_target * there is something to be saved, we just don't know * how to print it */ if (t->u.target_size != sizeof(struct ipt_entry_target)) { fprintf(stderr, "Target `%s' is missing " "save function\n", t->u.user.name); exit(1); } } } printf("\n"); } <EM >/* Here ends some of the code taken from iptables-save.c ****************** */</EM > int main(void) { iptc_handle_t h; const struct ipt_entry *e; const char *chain = NULL; const char *tablename = "filter"; const int counters = 1; program_name = "p2"; program_version = NETFILTER_VERSION; /* initialize */ h = iptc_init(tablename); if ( !h ) { printf("Error initializing: %s\n", iptc_strerror(errno)); exit(errno); } /* print chains and their rules */ for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) { printf("%s\n", chain); for (e = iptc_first_rule(chain, &h); e; e = iptc_next_rule(e, &h)) { print_rule(e, &h, chain, counters); } } exit(0); } /* main */</PRE ></FONT ></TD ></TR ></TABLE ><P >The function <EM >print_rule</EM > borrowed from <TT CLASS="FILENAME" >iptables-save.c</TT > prints the information about a rule into a readable form using:</P ><P ></P ><UL ><LI ><P ><EM >print_ip</EM > to print the addresses, </P ></LI ><LI ><P ><EM >print_iface</EM > to print the interfaces, </P ></LI ><LI ><P ><EM >print_proto</EM > to print the protocols, </P ></LI ><LI ><P ><EM >iptc_get_target</EM > to get and print the targets (using <EM >save</EM >).</P ></LI ></UL ><P >In <EM >main</EM > we iterate through each chain and for each one we iterate through each rule printing it.</P ><P >The arguments of <EM >print_rule</EM > are:</P ><P ></P ><UL ><LI ><P >e = pointer to an <EM >ipt_entry</EM > structure containing information about the rule.</P ></LI ><LI ><P >h = pointer to an <EM >iptc_handle_t</EM > structure returned by <EM >iptc_init</EM >.</P ></LI ><LI ><P >chain = name of the chain.</P ></LI ><LI ><P >counters = 0: do not print counters; 1: print them.</P ></LI ></UL ><P >OK, compile and run program <EM >p2</EM >:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >bash# <B CLASS="COMMAND" >./ipt-cc p2</B > bash# <B CLASS="COMMAND" >./p2</B ></PRE ></FONT ></TD ></TR ></TABLE ><P >You will get:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >INPUT FORWARD OUTPUT chain_1 chain_2</PRE ></FONT ></TD ></TR ></TABLE ><P >Now modify the environment using <EM >iptables</EM > to add some rules:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >bash# <B CLASS="COMMAND" >iptables -A INPUT -p tcp -i eth0 -s ! 192.168.1.1 --dport 20 -j ACCEPT</B > bash# <B CLASS="COMMAND" >iptables -A chain_1 -p udp -o eth1 -s 192.168.2.0/24 --sport 33 -j DROP</B ></PRE ></FONT ></TD ></TR ></TABLE ><P >Now if you run again <EM >p2</EM > you will get:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >INPUT [0:0] -A INPUT -s ! 192.168.1.1 -i eth0 -p tcp -m tcp --dport 20 -j ACCEPT FORWARD OUTPUT chain_1 [0:0] -A chain_1 -s 192.168.2.0/255.255.255.0 -o eth1 -p udp -m udp --sport 33 -j DROP chain_2</PRE ></FONT ></TD ></TR ></TABLE ><P >We have now rules printed for <EM >INPUT</EM > and <EM >chain_1</EM > chains. The numbers in the brackets at left are packet and byte counters respectively.</P ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN556">11.10. iptc_get_policy</H2 ><P ><B >Name: </B >iptc_get_policy</P ><P ><B >Usage: </B >Get the policy of a given built-in chain.</P ><P ><B >Prototype: </B >const char *iptc_get_policy(const char *chain, struct ipt_counters *counter, iptc_handle_t *handle)</P ><P ><B >Description: </B >This function gets the policy of a built-in chain, and fills in the <EM >counters</EM > argument with the hit statistics on that policy.</P ><P ><B >Parameters: </B >You have to pass as arguments the name of the built-in chain you want to get the policy to, a pointer to an <EM >ipt_counters</EM > structure to be filled by the function and the <EM >iptc_handle_t</EM > structure identifying the table we are working to. The <EM >ipt_counters</EM > structure was explained in previous section; do not forget that <EM >iptc_handle_t</EM > must be obtained by a previous call to the function <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Returns a char pointer to the policy name.</P ><P >Using pieces of programs 1 and 2 we can write <EM >program #3</EM >:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >/* * How to use libiptc- program #3 * /usr/local/src/p3.c */ #include <getopt.h> #include <sys/errno.h> #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <dlfcn.h> #include <time.h> #include "libiptc/libiptc.h" #include "iptables.h" int main(void) { iptc_handle_t h; const char *chain = NULL; const char *policy = NULL; const char *tablename = "filter"; struct ipt_counters counters; program_name = "p3"; program_version = NETFILTER_VERSION; /* initialize */ h = iptc_init(tablename); if ( !h ) { printf("Error initializing: %s\n", iptc_strerror(errno)); exit(errno); } /* print built-in chains, their policies and counters */ printf("BUILT-IN POLICY PKTS-BYTES\n"); printf("-----------------------------\n"); for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h)) { if ( !iptc_builtin(chain, h) ) continue; if ( (policy = iptc_get_policy(chain, &counters, &h)) ) printf("%-10s %-10s [%llu:%llu]\n", chain, policy, counters.pcnt, counters.bcnt); } exit(0); } /* main */</PRE ></FONT ></TD ></TR ></TABLE ><P >OK, compile and run program <EM >p3</EM >:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >bash# <B CLASS="COMMAND" >./ipt-cc p3</B > bash# <B CLASS="COMMAND" >./p3</B ></PRE ></FONT ></TD ></TR ></TABLE ><P >You will get something like this:</P ><TABLE BORDER="1" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><FONT COLOR="#000000" ><PRE CLASS="SCREEN" >BUILT-IN POLICY PKTS-BYTES ---------------------------- INPUT ACCEPT [0:0] FORWARD ACCEPT [0:0] OUTPUT ACCEPT [0:0]</PRE ></FONT ></TD ></TR ></TABLE ></DIV ><DIV CLASS="SECT2" ><H2 CLASS="SECT2" ><A NAME="AEN588">11.11. iptc_read_counter</H2 ><P ><B >Name: </B >iptc_read_counter</P ><P ><B >Usage: </B >Read counters of a rule in a chain.</P ><P ><B >Prototype: </B >struct ipt_counters *iptc_read_counter(const ipt_chainlabel chain, unsigned int rulenum, iptc_handle_t *handle);</P ><P ><B >Description: </B >This function read and returns packet and byte counters of the entry rule in chain <EM >chain</EM > positioned at <EM >rulenum</EM >. Counters are returned in a pointer to a type structure <EM >ipt_counters</EM >. Rule numbers start at 1 for the first rule.</P ><P ><B >Parameters: </B ><EM >chain</EM > is a char pointer to the name of the chain to be readed; <EM >rulenum</EM > is an integer value defined the position in the chain of rules of the rule which counters will be read. <EM >handle</EM > is a pointer to a structure of type <EM >iptc_handle_t</EM > that was obtained by a previous call to <EM >iptc_init</EM >.</P ><P ><B >Returns: </B >Returns a pointer to an <EM >ipt_counters</EM > structure containing the byte and packet counters readed. </P ></DIV ></DIV ><DIV CLASS="NAVFOOTER" ><HR ALIGN="LEFT" WIDTH="100%"><TABLE SUMMARY="Footer navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" ><A HREF="howtoprg.html" ACCESSKEY="P" >Prev</A ></TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="index.html" ACCESSKEY="H" >Home</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" ><A HREF="mfunction.html" ACCESSKEY="N" >Next</A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >How to create your program(s)</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" > </TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >Functions to modify firewalling rules and statistics</TD ></TR ></TABLE ></DIV ></BODY ></HTML >