看了Nicolas写的netfilter写匹配器,自己尝试编译测试,发现iptables 以及内核版本升级很多数据结构和函数接口都改变了,需要做大量的修改才能运行。
运行 iptables/netfilter
1)iptables
从 ftp://ftp.netfilter.org/pub/iptables/ 下载iptables 的源码然后拷贝libipt_ipaddr.c 到 iptables-1.4.10/extensions.
拷贝ipt_ipaddr.h 到 ./include/linux/netfilter_ipv4/
然后
$./configure
$make && make install
编译这个内核模块需用到3个文件:
ipt_ipaddr.h ipt_ipaddr.c Makefile
编译完内核模块之后用
$ sudo modprobe x_tables
$ sudo insmod ipaddr.ko
加载内核模块,然后iptables命令:
sudo iptables -I OUTPUT -m ipaddr --ipsrc ipaddr --ipdst ipaddr
设置规则。
修改后的源码:
ipt_ipaddr.c :
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ipt_ipaddr.h"
#define NIPQUAD(addr) \
((unsigned char *)&addr)[0], \
((unsigned char *)&addr)[1], \
((unsigned char *)&addr)[2], \
((unsigned char *)&addr)[3]
#define NF_IP_LOCAL_IN 1
#define NF_IP_LOCAL_OUT 3
static int ipt_match(const struct sk_buff *skb,struct xt_action_param *param)
{
const struct net_device *in = param->in;
const struct net_device *out = param->out;
const struct ipt_ipaddr_info *info = param->matchinfo;
struct iphdr *iph = ip_hdr(skb);
printk("entered ipt_match !\n");
printk(KERN_INFO "ipt_ipaddr: IN=%s OUT=%s TOS=0x%02X "
"TTL=%x SRC=%u.%u.%u.%u DST=%u.%u.%u.%u "
"ID=%u IPSRC=%u.%u.%u.%u IPDST=%u.%u.%u.%u\n",
in ? (char *)in : "", out ? (char *)out : "", iph->tos,
iph->ttl, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr),
ntohs(iph->id), NIPQUAD(info->ipaddr.src), NIPQUAD(info->ipaddr.dst)
);
if (info->flags & IPADDR_SRC) {
if ( (ntohl(iph->saddr) != ntohl(info->ipaddr.src)) ^ !!(info->flags & IPADDR_SRC_INV) ) {
printk(KERN_NOTICE "src IP %u.%u.%u.%u is not matching %s.\n",
NIPQUAD(info->ipaddr.src),
info->flags & IPADDR_SRC_INV ? " (INV)" : "");
return 0;
}
}
if (info->flags & IPADDR_DST) {
if ( (ntohl(iph->daddr) != ntohl(info->ipaddr.dst)) ^ !!(info->flags & IPADDR_DST_INV) ) {
printk(KERN_NOTICE "dst IP %u.%u.%u.%u is not matching%s.\n",
NIPQUAD(info->ipaddr.dst),
info->flags & IPADDR_DST_INV ? " (INV)" : "");
return 0;
}
}
return 1;
}
static int ipaddr_checkentry(const struct xt_mtchk_param *param)
{
printk("entered ipaddr_checkentry\n");
const struct ipt_ipaddr_info *info = param->matchinfo;
unsigned int hook_mask = param->hook_mask;
unsigned int matchsize = param->match->matchsize;
char tablename[XT_TABLE_MAXNAMELEN];
const struct ipt_ip *ip = (struct ipt_ip *)param->entryinfo; // this is specified by param->family.
if (hook_mask & ~((1 << NF_IP_LOCAL_IN) | (1 << NF_IP_LOCAL_OUT))) {
printk(KERN_WARNING "ipt_ipaddr: only valid with the FILTER table.\n");
return 0;
}
if (matchsize != XT_ALIGN(sizeof(struct ipt_ipaddr_info))) {
printk(KERN_ERR "ipt_ipaddr: matchsize differ, you may have forgotten to recompile me.\n");
return 0;
}
strcpy(tablename,param->match->table);
printk(KERN_INFO "ipt_ipaddr: Registered in the %s table, hook=%x, proto=%u\n",
tablename, hook_mask, ip->proto);
return 1;
}
static struct xt_match ipaddr_match = {
.match = ipt_match,
.matchsize = XT_ALIGN(sizeof(struct ipt_ipaddr_info)), /// without this may cause invalid size 0 != 12
.name = "ipaddr",
.checkentry = ipaddr_checkentry,
.me = THIS_MODULE
};
static int __init init(void)
{
printk(KERN_INFO "ipt_ipaddr: init!\n");
return xt_register_match(&ipaddr_match);
}
static void __exit fini(void)
{
printk(KERN_INFO "ipt_ipaddr: exit!\n");
xt_unregister_match(&ipaddr_match);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nicolas Bouliane && Samuel Jean");
MODULE_DESCRIPTION("netfilter module skeleton");
ipt_ipaddr.h
#ifndef _IPT_IPADDR_H
#define _IPT_IPADDR_H
#include <linux/types.h>
#define IPADDR_SRC 0x01 /* Match source IP addr */
#define IPADDR_DST 0x02 /* Match destination IP addr */
#define IPADDR_SRC_INV 0x10 /* Negate the condition */
#define IPADDR_DST_INV 0x20 /* Negate the condition */
struct ipt_ipaddr {
__u32 src, dst;
};
struct ipt_ipaddr_info {
struct ipt_ipaddr ipaddr;
/* Flags from above */
__u8 flags;
};
#endif
libipt_ipaddr.c:
#include <stdbool.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <iptables.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_ipaddr.h>
//./configure --prefix= ./install
/*
* ./install/sbin/iptables -m ipaddr -h
*/
static void ipaddr_help(void)
{
printf (
"IPADDR options:\n"
"[!] --ipsrc <ip>\t\t The incoming ip addr matches.\n"
"[!] --ipdst <ip>\t\t The outgoing ip addr matches.\n"
"\n"
);
}
static struct option ipaddr_opts[] = {
{ .name = "ipsrc", .has_arg = 1, .flag = 0, .val = '1' },
{ .name = "ipdst", .has_arg = 1, .flag = 0, .val = '2' },
{ .name = 0 }
};
static void ipaddr_init(struct xt_entry_match *m)
{
/* Can't cache this
*nfcache |= NFC_UNKNOWN;*/
}
__be32 in_aton(const char *str)
{
unsigned long l;
unsigned int val;
int i;
l = 0;
for (i = 0; i < 4; i++)
{
l <<= 8;
if (*str != '\0')
{
val = 0;
while (*str != '\0' && *str != '.' && *str != '\n')
{
val *= 10;
val += *str - '0';
str++;
}
l |= val;
if (*str != '\0')
str++;
}
}
return htonl(l);
}
struct in_addr* dotted_to_addr(const char *arg)
{
struct in_addr * p;
p = malloc(sizeof(struct in_addr));
printf("%x\n",p);
p->s_addr = in_aton(arg);
return p;
}
static void parse_ipaddr(const char *arg, __u32 *ipaddr)
{
struct in_addr *ip;
printf("in parse_ipaddr arg is %s",arg);
ip = dotted_to_addr(arg);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Bad IP address `%s'\n", arg);
*ipaddr = ip->s_addr;
}
static int ipaddr_parse(int c, char **argv, int invert, unsigned int *flags,
const struct ipt_entry *entry,
struct ipt_entry_match **match)
{
struct ipt_ipaddr_info *info = (struct ipt_ipaddr_info *)(*match)->data /*NULL*/;
printf("entered ipaddr_parse\n");
switch(c) {
case '1':
if (*flags & IPADDR_SRC)
xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipsrc once!");
*flags |= IPADDR_SRC;
info->flags |= IPADDR_SRC;
if (invert)
info->flags |= IPADDR_SRC_INV;
parse_ipaddr(argv[optind-1], &info->ipaddr.src);
break;
case '2':
if (*flags & IPADDR_DST)
xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipdst once!");
*flags |= IPADDR_DST;
info->flags |= IPADDR_DST;
if (invert)
info->flags |= IPADDR_DST_INV;
parse_ipaddr(argv[optind-1], &info->ipaddr.dst);
break;
default:
return 0;
}
return 1;
}
static void ipaddr_final_check(unsigned int flags)
{
if (!flags)
xtables_error(PARAMETER_PROBLEM, "ipt_ipaddr: Invalid parameters.");
}
/*
* Can't call it ipaddr, because
* the main structure is already
* called like that.
*/
static void print_ipaddr(__u32 *ip_addr)
{
printf( "%u.%u.%u.%u ",
((unsigned char *)ip_addr)[0],
((unsigned char *)ip_addr)[1],
((unsigned char *)ip_addr)[2],
((unsigned char *)ip_addr)[3]
);
}
static void ipaddr_print(const struct ipt_ip *ip,
const struct ipt_entry_match *match,
int numeric)
{
const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;
printf("entered ipaddr_print\n");
if (info->flags & IPADDR_SRC) {
printf("src IP ");
if (info->flags & IPADDR_SRC_INV)
printf("! ");
print_ipaddr((__u32 *)&info->ipaddr.src);
}
if (info->flags & IPADDR_DST) {
printf("dst IP ");
if (info->flags & IPADDR_DST_INV)
printf("! ");
print_ipaddr((__u32 *)&info->ipaddr.dst);
}
}
/*
* iptables-saves
*/
static void ipaddr_save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
const struct ipt_ipaddr_info *info = (const struct ipt_ipaddr_info *)match->data;
printf("entered ipaddr_save\n");
if (info->flags & IPADDR_SRC) {
if (info->flags & IPADDR_SRC_INV)
printf("! ");
printf("--ipsrc ");
print_ipaddr((__u32 *)&info->ipaddr.src);
}
if (info->flags & IPADDR_DST) {
if (info->flags & IPADDR_DST_INV)
printf("! ");
printf("--ipdst ");
print_ipaddr((__u32 *)&info->ipaddr.dst);
}
}
static struct xtables_match ipaddr = {
.family = NFPROTO_UNSPEC,
.name = "ipaddr",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct ipt_ipaddr_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_ipaddr_info)),
.help = ipaddr_help,
/// .init = ipaddr_init,
.parse = ipaddr_parse,
.final_check = ipaddr_final_check,
.print = ipaddr_print,
.save = ipaddr_save,
.extra_opts = ipaddr_opts
};
void _init(void)
{
xtables_register_match(&ipaddr);
}
Makefile文件:
EXTRA_CFLAGS := -g -O2 ##Debug info .
KVERS = $(shell uname -r)
ifneq ($(KERNELRELEASE),)
obj-m = ipaddr.o
ipaddr-objs := ipt_ipaddr.o
else
KDIR := /lib/modules/$(KVERS)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.order *~ *.symvers
endif
原文链接:
http://www.linuxfocus.org/ChineseGB/February2005/article367.shtml