Nicola,
attached is the sample code from the "Writing Netfilter modules"
tutorial. It builds and installs a filter module ipaddr for the running
kernel:
make all install
Hope this helps.
Regards,
Justin Kamerman
On 10-08-30 11:21 AM, Nicola Padovano wrote:
> ok justin thank you!
> for now I only need standalone package (to test my code, in future i
> will see how xtables-addons works).
> but (there is always a "but") the problem, justin, isn't the copy of
> libxt_foo.so in /lib/xtables, but it is the creation of this library.
> as i said before, when i compile the module i don't have no
> lixt_foo.so file. So, how i can create it?
>
> sorry for my ignorance, i've started with kernel programming only a few day ago.
>
> thanks!
>
> On Mon, Aug 30, 2010 at 3:57 PM, Justin Kamerman <justin@xxxxxxxxxx> wrote:
>
>> Nicola,
>> iptables is complaining because it can't locate the userspace companion
>> to your netfilter module. The userspace companion tells iptables which
>> kernel module to load and parses command line options before they are
>> passed to the kernel module. The module_install target takes care of the
>> kernel module but you also need a userspace helper installed to
>> /lib/xtables. If building standalone (as opposed to using the
>> Xtables-addons framework) you could use a maekfile rule like:
>>
>> libs_install:
>> cp -f libxt_ipaddr.so /lib/xtables
>>
>> Regards,
>> Justin Kamerman
>>
>> On 10-08-30 10:25 AM, Nicola Padovano wrote:
>>
>>> -s 127.0.0.1 -p icmp -j DROP
>>>
>>>> but i don't know how create this new target...
>>>> I've modified the netfilter makefile e Kbuild file (in net/netfilter)
>>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>>
>
>
>
/* Shared library add-on to iptables to add ipaddr support. */
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <arpa/inet.h>
#include <xtables.h>
#include "xt_ipaddr.h"
/**
* If we have a rule we want to save, iptables provides the tool
* iptables-save which dumps all your rules. It needs your extension's
* help to interpret struct xt_ipaddr_mtinfo's contents and and dump
* proper rules. The output that is produced must be options that can
* be passed to iptables
*/
static void ipaddr_mt4_save (const void *entry, const struct xt_entry_match *match)
{
const struct xt_ipaddr_mtinfo *info = (const void *) match->data;
/* Print the source address if it is part of the rule */
if (info->flags & XT_IPADDR_SRC)
{
if (info->flags & XT_IPADDR_SRC_INV)
printf ("! ");
printf ("--ipsrc %s ", xtables_ipaddr_to_numeric (&info->src.in));
}
/* Print the destination address if it is part of the rule */
if (info->flags & XT_IPADDR_DST)
{
if (info->flags & XT_IPADDR_DST_INV)
printf ("! ");
printf ("--ipdst %s ", xtables_ipaddr_to_numeric (&info->dst.in));
}
}
/**
* In the same philosophy as the save function, this function aims to
* print information about the rule. It is called by iptables -L, and
* you are free to output whatever you want and how you want.
*/
static void ipaddr_mt4_print (const void *entry,
const struct xt_entry_match *match,
int numeric)
{
const struct xt_ipaddr_mtinfo *info = (const void *) match->data;
/* Print the source address if it is part of the rule */
if (info->flags & XT_IPADDR_SRC)
{
printf ("src IP ");
if (info->flags & XT_IPADDR_SRC_INV)
printf ("! ");
printf ("%s ", numeric ?
xtables_ipaddr_to_numeric (&info->src.in) :
xtables_ipaddr_to_anyname (&info->src.in));
}
/* Print the destination address if it is part of the rule */
if (info->flags & XT_IPADDR_DST)
{
printf ("dst IP ");
if (info->flags & XT_IPADDR_DST_INV)
printf ("! ");
printf ("%s ", numeric ?
xtables_ipaddr_to_numeric (&info->dst.in) :
xtables_ipaddr_to_anyname (&info->dst.in));
}
}
/**
* This funciton verifies if arguments are used correctly and set
* information we will share with the kernel part. It is called each
* time an option is found, so if the user provides two options, it
* will be called twice with the argument code provided in the
* variable c. The argument code for a specific option is set in the
* option table.
*/
static int ipaddr_mt4_parse (int c,
char **argv,
int invert,
unsigned int *flags,
const void *entry,
struct xt_entry_match **match)
{
struct xt_ipaddr_mtinfo *info = (void *) (*match)->data;
struct in_addr *addrs, mask;
unsigned int naddr;
switch (c)
{
case '1': /* --ipsrc */
if (*flags & XT_IPADDR_SRC)
xtables_error (PARAMETER_PROBLEM,
"xt_ipaddr: Only use \"--ipsrc once!");
*flags |= XT_IPADDR_SRC;
info->flags |= XT_IPADDR_SRC;
if (invert)
info->flags |= XT_IPADDR_SRC_INV;
xtables_ipparse_any (optarg, &addrs, &mask, &naddr);
if (naddr != 1)
xtables_error (PARAMETER_PROBLEM,
"%s does not resolve to exactly one address",
optarg);
/* copy the single address */
memcpy (&info->src.in, addrs, sizeof (*addrs));
return true;
case '2': /* --ipdst */
if (*flags & XT_IPADDR_DST)
xtables_error (PARAMETER_PROBLEM,
"xt_ipaddr: Only use \"--ipdst once!");
*flags |= XT_IPADDR_DST;
info->flags |= XT_IPADDR_DST;
if (invert)
info->flags |= XT_IPADDR_DST_INV;
xtables_ipparse_any (optarg, &addrs, &mask, &naddr);
if (naddr != 1)
xtables_error (PARAMETER_PROBLEM,
"%s does not resolve to exactly one address",
optarg);
/* copy the single address */
memcpy (&info->dst.in, addrs, sizeof (*addrs));
return true;
}
return false;
}
/**
* This function is a last chance for a sanity check. It is called
* when the user enters a new rule, right after argument parsing is
* done and flags is filled with whatever values you chose to assign
* to it in your parse function.
*/
static void ipaddr_mt_check (unsigned int flags)
{
if ( flags == 0 )
xtables_error (PARAMETER_PROBLEM,
"xt_ipaddr: You need to specify at least "
"\"--ipsrc\" or \"--ipdst\".");
}
/**
* The init function can be used to populate our xt_ipaddr_mtinfo
* structure with defaults before parse is called
*/
static void ipaddr_mt_init (struct xt_entry_match *match)
{
struct xt_ipaddr_mtinfo *info = (void *) match->data;
/* This default destination address will never actually be used as
* the parser will not accept a --ipdst without an argument */
inet_pton (PF_INET, "192.0.2.137", &info->dst.in);
}
/**
* This funciton is called by iptables -m match_name -h. It shoudl
* give an overview of the available options and a very brief short
* description.
*/
static void ipaddr_mt_help (void)
{
printf ("ipaddr match options:\n"
"[!] --ipsrc addr Match source address of packet\n"
"[!] --ipdst addr Match destination address of packet\n");
}
static const struct option ipaddr_mt_opts[] =
{
{ .name = "ipsrc", .has_arg = true, .val = '1' },
{ .name = "ipdst", .has_arg = true, .val = '2' },
{ NULL },
};
static struct xtables_match ipaddr_mt4_reg =
{
.version = XTABLES_VERSION,
.name = "ipaddr",
.revision = 0,
.family = NFPROTO_IPV4,
.size = XT_ALIGN (sizeof (struct xt_ipaddr_mtinfo)),
.userspacesize = XT_ALIGN (sizeof (struct xt_ipaddr_mtinfo)),
.help = ipaddr_mt_help,
.init = ipaddr_mt_init,
.parse = ipaddr_mt4_parse,
.final_check = ipaddr_mt_check,
.print = ipaddr_mt4_print,
.save = ipaddr_mt4_save,
.extra_opts = ipaddr_mt_opts,
};
void _init (void)
{
xtables_register_match (&ipaddr_mt4_reg);
}
# If KERNEL_RELEASE is defined then we have been called from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := xt_ipaddr.o
# Otherwise we were called directly from the command line; invoke the
# kernel build system.
else
MODULES_DIR := /lib/modules/$(shell uname -r)
KERNELDIR := $(MODULES_DIR)/build
CFLAGS = -O2 -Wall
.PHONY: all modules install modules_install libs_install clean
all: modules libxt_ipaddr.so
modules:
$(MAKE) -C $(KERNELDIR) M=$$PWD $@
install: modules_install libs_install
modules_install:
$(MAKE) -C $(KERNELDIR) M=$$PWD $@
libs_install:
cp -f libxt_ipaddr.so /lib/xtables
clean:
$(RM) *.so
$(MAKE) -C $(KERNELDIR) M=$$PWD $@
# Pattern rules
lib%.so: lib%.o
gcc -shared -o $@ $^;
lib%.o: lib%.c
gcc ${CFLAGS} -D_INIT=lib$*_init -c -o $@ $<;
endif
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter/x_tables.h>
#include <linux/skbuff.h>
#include "xt_ipaddr.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Justin Kamerman <justin@xxxxxxxxxx>");
MODULE_DESCRIPTION("Xtables: match source/destination address");
MODULE_ALIAS("ipt_ipaddr");
/**
* the match function
*/
static bool ipaddr_mt (const struct sk_buff *skb,
const struct xt_match_param *par)
{
struct tcphdr _tcph;
const struct tcphdr *th;
const struct xt_ipaddr_mtinfo *info;
const struct iphdr *iph;
/* Sanity check: if we don't have the whole header, drop packet. */
th = skb_header_pointer (skb, par->thoff, sizeof (_tcph), &_tcph);
if (th == NULL)
{
*par->hotdrop = true;
return false;
}
/* Get a handle to data block copied from userspace i.e. match parameters */
info = par->matchinfo;
/* Get handle to IPv4 header from packet - can use ip_hdr()
* because this match family is NFPROTO_IPV4; lower level
* extension families must use skb_header_pointer() */
iph = ip_hdr (skb);
printk (KERN_INFO
"xt_ipaddr: IN=%s OUT=%s "
"SRC=" NIPQUAD_FMT " DST=" NIPQUAD_FMT " "
"IPSRC=" NIPQUAD_FMT " IPDST=" NIPQUAD_FMT "\n",
(par->in != NULL) ? par->in->name : "",
(par->out != NULL) ? par->out->name : "",
NIPQUAD (iph->saddr),
NIPQUAD (iph->daddr),
NIPQUAD (info->src),
NIPQUAD (info->dst));
/* If the XT_IPADDR_SRC flag has been set, we check whether the
* source address matches the one specified in the rule. If it
* does not match, the whole rule will not match so we can already
* return false here. */
if (info->flags & XT_IPADDR_SRC)
{
if ((iph->saddr != info->src.ip) ^ !!(info->flags & XT_IPADDR_SRC_INV))
{
printk (KERN_NOTICE "src IP - no match\n");
return false;
}
}
/* Here we do the same except we look for the destination address
* if XT_IPADDR_DST has been set */
if (info->flags & XT_IPADDR_DST)
{
if ((iph->daddr != info->dst.ip) ^ !!(info->flags & XT_IPADDR_DST_INV))
{
printk (KERN_NOTICE "dst IP - no match\n");
return false;
}
}
return true;
}
/**
* function to check for validity of parameters in our struct and load
* additional modules required to perform the match.
*/
static bool ipaddr_mt_check (const struct xt_mtchk_param *par)
{
const struct xt_ipaddr_mtinfo *info = par->matchinfo;
printk (KERN_INFO "xt_ipaddr: Added a rule with -m ipaddr in "
"the %s table; this rule is reachable through "
"hooks 0x%x\n",
par->table,
par->hook_mask);
/* No flags set */
if (!(info->flags & (XT_IPADDR_SRC | XT_IPADDR_DST)))
{
printk (KERN_INFO "xt_ipaddr: testing for nothing\n");
return false;
}
/* Special test just because we can */
if (ntohl (info->src.ip) == 0xDEADBEEF)
{
printk (KERN_INFO "xt_ipaddr: I just thought I do not "
"want to let you match on 222.173.190.239\n");
return false;
}
return true;
}
/**
* function to call when rule is deleted to free any reserved space
* and/or drop additional modules reference counts so they can be
* unloaded if desired.
*/
static void ipaddr_mt_destroy (const struct xt_mtdtor_param *par)
{
const struct xt_ipaddr_mtinfo *info = par->matchinfo;
printk (KERN_INFO "Test for address %08X removed\n" , info->src.ip);
}
/**
* structure containing all match metadata such as name and function pointer table.
*/
static struct xt_match ipaddr_mt4_reg __read_mostly =
{
.name = "ipaddr",
.revision = 0,
.family = NFPROTO_IPV4,
.match = ipaddr_mt,
.checkentry = ipaddr_mt_check,
.destroy = ipaddr_mt_destroy,
.matchsize = XT_ALIGN (sizeof (struct xt_ipaddr_mtinfo)),
.me = THIS_MODULE,
};
/**
* function called on module loading
*/
static int __init ipaddr_mt_init (void)
{
return xt_register_match (&ipaddr_mt4_reg);
}
/**
* function called on module unloading
*/
static void __exit ipaddr_mt_exit (void)
{
xt_unregister_match (&ipaddr_mt4_reg);
}
module_init (ipaddr_mt_init);
module_exit (ipaddr_mt_exit);
#ifndef _LINUX_NETFILTER_XT_IPADDR_H
#define _LINUX_NETFILTER_XT_IPADDR_H 1
enum
{
XT_IPADDR_SRC = 1 << 0,
XT_IPADDR_DST = 1 << 1,
XT_IPADDR_SRC_INV = 1 << 2,
XT_IPADDR_DST_INV = 1 << 3,
};
struct xt_ipaddr_mtinfo
{
union nf_inet_addr src, dst;
__u8 flags;
};
#endif /* _LINUX_NETFILTER_XT_IPADDR_H */