Write the netfilter ID by yourself.

Source: Internet
Author: User
Overview

Write an iptables/Netfilter
The general steps of the matching module are as follows:

  • Find the specific situation you want to match.
  • Write part of the user space program used to accept parameters.
  • Write the kernel space program used to analyze the package information and determine whether the program matches the result.

 

1.0 iptables Module

The iptables library is basically used to interact with users. It captures the parameters that the user wants to send to the core State program.

1.1 available data structures and functions

The first is some basic data structures.
<Iptables/include/iptables. h>
The purpose of these structures will be displayed later.

/* Include file for additions: new matches and targets. */
struct iptables_match
{
struct iptables_match *next;

ipt_chainlabel name;

const char *version;

/* Size of match data. */
size_t size;

/* Size of match data relevent for userspace comparison purposes */
size_t userspacesize;

/* Function which prints out usage message. */
void (*help)(void);

/* Initialize the match. */
void (*init)(struct ipt_entry_match *m, unsigned int *nfcache);

/* Function which parses command options; returns true if it
ate an option */
int (*parse)(int c, char **argv, int invert, unsigned int *flags,
const struct ipt_entry *entry,
unsigned int *nfcache,
struct ipt_entry_match **match);

/* Final check; exit if not ok. */
void (*final_check)(unsigned int flags);

/* Prints out the match iff non-NULL: put space at end */
void (*print)(const struct ipt_ip *ip,
const struct ipt_entry_match *match, int numeric);

/* Saves the match info in parsable form to stdout. */
void (*save)(const struct ipt_ip *ip,
const struct ipt_entry_match *match);

/* Pointer to list of extra command-line options */
const struct option *extra_opts;

/* Ignore these men behind the curtain: */
unsigned int option_offset;
struct ipt_entry_match *m;
unsigned int mflags;
#ifdef NO_SHARED_LIBS
unsigned int loaded; /* simulate loading so options are merged properly */
#endif
};

 

1.2 deep skeleton Program

 

1.2.1 Initialization

We first initialize common fields in the 'iptables _ Match' structure:

static struct iptables_match ipaddr
= {

'Name'
Is the file name of your function library (that is, libipt_ipaddr ).
You cannot place other things in this location. This is used to automatically load your library.

    .name            = "ipaddr",

The next field 'version' is
The version of iptables. The following two fields are used to maintain the size consistency between the user State Program and the core State sharing structure.

    .version         = IPTABLES_VERSION,
.size = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)),
.userspacesize = IPT_ALIGN(sizeof(struct ipt_ipaddr_info)),

'Help'
Is the function to be called when you enter 'iptables-M module-H. 'Parse'
It is called when you enter a new rule to verify the validity of the parameter. 'Print 'indicates that the Rules added earlier are displayed when 'iptables-L' is used.

    .help            = &help,
.init = &init,
.parse = &parse,
.final_check = &final_check,
.print = &print,
.save = &save,
.extra_opts = opts
};

Iptables
The architecture supports multiple shared libraries. Each shared library must use <Iptables/iptables. c> 'Register _ match () 'defined in ()'
Register with iptables. This function will be called when the module is loaded by iptables. For more information, see 'man dlopen '.

void _init(void)
{
register_match(&ipaddr);
}

 

1.2.2 SAVE Function

If we have a rule set to save, we can use the tool provided by iptables.
'Iptables-save', which can save all the rules. Obviously, you need to extend this tool to save these rules. This extension is completed through the Save function.

static void 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;

If the source address is part of the rule, print it.

   if (info->flags & IPADDR_SRC) {
if (info->flags & IPADDR_SRC_INV)
printf("! ");
printf("--ipsrc ");
print_ipaddr((u_int32_t *)&info->ipaddr.src);
}

If the destination address is part of the rule, print the destination address.

   if (info->flags & IPADDR_DST) {
if (info->flags & IPADDR_DST_INV)
printf("! ");
printf("--ipdst ");
print_ipaddr((u_int32_t *)&info->ipaddr.dst);
}
}

 

1.2.3 print function

Like the philosophy of SAVE, there is also a print function for printing rules. It is in 'iptables-l'
Is called. We will see the purpose of the parameter 'ipt_entry_match * Match' in the following section, but we already have a concept for it, right?

static void 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;

if (info->flags & IPADDR_SRC) {
printf("src IP ");
if (info->flags & IPADDR_SRC_INV)
printf("! ");
print_ipaddr((u_int32_t *)&info->ipaddr.src);
}

if (info->flags & IPADDR_DST) {
printf("dst IP ");
if (info->flags & IPADDR_DST_INV)
printf("! ");
print_ipaddr((u_int32_t *)&info->ipaddr.dst);
}
}

 

1.2.4 final check function

This function is the last chance to check the correctness. It is called after the user enters the rule and the parameter resolution is just completed.

static void final_check(unsigned int flags)
{
if (!flags)
exit_error(PARAMETER_PROBLEM, "ipt_ipaddr: Invalid parameters.");
}

 

1.2.5 parse function

Parse
Is the most important function, because we need to check the correctness of the parameters and write the information we will share with the core State program. It is called every time a parameter is found. That is to say, if you enter two parameters, this function will be called with different parameter codes.
C is called twice.

static int parse(int c, char **argv, int invert, unsigned int *flags,
const struct ipt_entry *entry,
unsigned int *nfcache,
struct ipt_entry_match **match)
{

We use a special structure to save the information we want to pass to the core State program. 'Match'
Pointers are passed to multiple functions. We can use the same data structure each time. Once the rule is loaded, the pointer is copied to the core State program. In this way, the kernel module can know what users want to analyze (this is the key to the problem, isn't it ?).

   struct ipt_ipaddr_info *info = (struct ipt_ipaddr_info *)(*match)->data;

Each parameter corresponds to a separate value, so we can decide what action to take based on the entered parameter. Next we will see how we convert the parameter to a value.

   switch(c) {

First, check whether the parameter is used multiple times. If multiple times are used
<Iptables/iptables. c> The 'exit _ error () 'function defined in.
<Iptables/include/iptables_common.h> 'Parameter _ problem' defined in'
. Otherwise, set 'flags 'and
'Info-> flags '. We will introduce this header file later.

Although the two logos look similar, they are completely different. 'Flag'
The scope is this function, and 'info-> flags 'is part of the structure we use to share information with core State programs.

      case '1':
if (*flags & IPADDR_SRC)
exit_error(PARAMETER_PROBLEM, "ipt_ipaddr: Only use --ipsrc once!");
*flags |= IPADDR_SRC;
info->flags |= IPADDR_SRC;

Check if the anti-flag is used
'! 'Exist or not. If yes, write the corresponding value in 'info-> flags.
Call the internal function 'parse _ ipaddr 'written for this skeleton program'
To convert an IP address from a string to a 32-bit value.

         if (invert)
info->flags |= IPADDR_SRC_INV;

parse_ipaddr(argv[optind-1], &info->ipaddr.src);
break;

Similarly, we check whether there are multiple settings and set the appropriate flag.

      case '2':
if (*flags & IPADDR_DST)
exit_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;
}

 

1.2.6 options Structure

Previously, we have discussed how to map each parameter to a value. 'Struct option'
Is a good way to achieve this goal. For more information about this structure, we strongly recommend that you read 'man 3 getopt '.

static struct option opts[] = {
{ .name = "ipsrc", .has_arg = 1, .flag = 0, .val = '1' },
{ .name = "ipdst", .has_arg = 1, .flag = 0, .val = '2' },
{ .name = 0 }
};

 

1.2.7 init Function

The init function is used to initialize some specific things, such as the netfilter cache.
System. You don't have to worry too much about the specific use of this function.

static void init(struct ipt_entry_match *m, unsigned int *nfcache)
{
/* Can't cache this */
*nfcache |= NFC_UNKNOWN;
}

 

1.2.7 help functions

This function is called through 'iptables-M match_name-H' to display available parameters.

static void help(void)
{
printf (
"IPADDR v%s options:/n"
"[!] --ipsrc /t/t The incoming ip addr matches./n"
"[!] --ipdst /t/t The outgoing ip addr matches./n"
"/n", IPTABLES_VERSION
);
}

 

1.2.8 header file 'ipaddr. H'

This file defines what we need.

#ifndef _IPT_IPADDR_H
#define _IPT_IPADDR_H

We have used these specific values above.

#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 */

Structure
'Ipaddr_info 'is the data structure to be copied to the core State program.

struct ipt_ipaddr {
u_int32_t src, dst;
};

struct ipt_ipaddr_info {

struct ipt_ipaddr ipaddr;

/* Flags from above */
u_int8_t flags;

};

#endif

 

1.3 Chapter 1 Summary

In the first part, we discuss the role of the iptables library. The content of each function is described as follows'
This is an important structure for storing information that will be copied to the core State Program for further processing. We also see iptables
Structure and how to register a new library.
It should be noted that this is only a skeleton program used to demonstrate how the framework works. Besides, 'ipaddr_info 'and other similar things are not
Iptables/netfilter is part of this example.

2.0 netfilter Module

The task of a matching module is to check each received package and determine whether it complies with a certain decision criterion. This module should do the following:

  • Receive each package and View tables related to the matching Module
  • Tell netfilter whether our module matches this package

 

2.1 available functions and data structures

First, some basic data structures are defined in
<Linux/netfilter_ipv4/ip_tables.h>.
For this structure and the previous iptables
If you are still interested, you can refer to the netfilter hacking howto written by Rusty Russell and Harald welte.

struct ipt_match
{
struct list_head list;

const char name[IPT_FUNCTION_MAXNAMELEN];

/* Return true or false: return FALSE and set *hotdrop = 1 to
force immediate packet drop. */
/* Arguments changed since 2.4, as this must now handle
non-linear skbs, using skb_copy_bits and
skb_ip_make_writable. */
int (*match)(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
int *hotdrop);

/* Called when user tries to insert an entry of this type. */
/* Should return true or false. */
int (*checkentry)(const char *tablename,
const struct ipt_ip *ip,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask);

/* Called when entry of this type deleted. */
void (*destroy)(void *matchinfo, unsigned int matchinfosize);

/* Set this to THIS_MODULE. */
struct module *me;
};

 

2.2 deep skeleton Program

 

2.2.1 Initialization

First, we initialize common fields in the 'ipt_match 'data structure.

static struct ipt_match ipaddr_match
= {

'Name'
Is the file name string of your module (that is, ipt_ipaddr ).

.name       = "ipaddr",

The following field is the callback function to be used by the Framework. 'match' is the function to be called when a package is sent to your module.

.match      = match,
.checkentry = checkentry,
.me = THIS_MODULE,
};

Your kernel module's
The init function needs to call 'ipt _ register_match () 'by pointing to a pointer of 'struct ipt_match'
Framework registration. This function is called when the module is loaded.

static int __init init(void)
{
printk(KERN_INFO "ipt_ipaddr: init!/n");
return ipt_register_match(&ipaddr_match);
}

When the module is removed from the kernel, this function will be called. Here, we want to cancel the check.

static void __exit fini(void)
{
printk(KERN_INFO "ipt_ipaddr: exit!/n");
ipt_unregister_match(&ipaddr_match);
}

These two functions are called when the module is loaded and removed.

module_init(init);
module_exit(fini);

 

2.2.2 match Function

Linux TCP/IP protocol stack includes five netfilters
Hook. In this way, after a package arrives, the protocol stack sends the package to the corresponding hook, enters each table in sequence, and then stacks each rule in sequence. When your module gets a package, your module can work on it.

static int match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
int *hotdrop)
{

I hope you still remember what we did in the user State program!
:). Now we can map the data structure copied by the user State program to us.

const struct ipt_skeleton_info *info = matchinfo;

'Skb'
Contains the packages we want to process. For more information about the powerful data structure that is everywhere in the Linux TCP/IP protocol stack, See Harald welte.
An excellent article written article (ftp://ftp.gnumonks.org/pub/doc/skb-doc.html ).

   struct iphdr *iph = skb->nh.iph;

Here, we just print some interesting things to see what they look like. Macro
'Ipquad' is used to display an IP address in a readable manner.Linux/include/Linux/kernel. h>
.

   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
The '-- ipsrc' parameter indicates whether the source address matches the address specified by the rule. Don't forget to consider the anti-flag '! '. If no match exists, 0 is returned.

   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;
}
}

Here, we do the same job, just look
'-- Ipdst' parameter.

   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;
}
}

If none of them are successful, return
1. It indicates that we matched the package.

   return 1;
}

 

2.2.3 checkentry Function

Checkentry is usually the last chance to check validity. It is difficult to understand when it is called. View post
Http://www.mail-archive.com/netfilter-devel@lists.samba.org/msg00625.html)
As an explanation. This article is also an article about netfilter hacking howto.

static int checkentry(const char *tablename,
const struct ipt_ip *ip,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
const struct ipt_skeleton_info *info = matchinfo;

if (matchsize != IPT_ALIGN(sizeof(struct ipt_skeleton_info))) {
printk(KERN_ERR "ipt_skeleton: matchsize differ, you may have forgotten to recompile me./n");
return 0;
}

printk(KERN_INFO "ipt_skeleton: Registered in the %s table, hook=%x, proto=%u/n",
tablename, hook_mask, ip->proto);

return 1;
}

 

2.3 Chapter II Summary

In the second part, we talk about netfilter.
Module and how to register it with a specific structure. In addition, we also discussed how to match specific conditions based on the criteria given in the user space section.

3.0 run iptables/Netfilter

We have seen how to write a new iptables/Netfilter
Matching module. Now we will add it to the kernel to run it. Here, I suppose you know how to compile the kernel. First, download the skeleton matching file from the download page of this article.

3.1 iptables

Now, if you don't have source code for iptables, you can download it from the ftp://ftp.netfilter.org/pub/iptables. Then copy
'Libipt _ ipaddr. c' to <Iptables/extensions/>.

This is
<Iptables/extensions/makefile> You should add 'ipaddr 'to a row in '.

PF_EXT_SLIB:=ah addrtype comment connlimit connmark conntrack dscp ecn
esp hashlimit helper icmp iprange length limit ipaddr mac mark
multiport owner physdev pkttype realm rpc sctp standard state tcp tcpmss
tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE
MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE
TTL ULOG

 

3.2 Kernel

First, you should copy 'ipaddr. c'
<Linux/NET/IPv4/Netfilter/>, Copy 'ipt_ipaddr.h'
<Linux/NET/IPv4/Netfilter/>. Some readers may still use the 2.4 kernel, So I provide both 2.4 and 2.6
.

Edit the 2.4 kernel <Linux/NET/IPv4/Netfilter/config. In>
, Add the following aggravated rows.

# The simple matches.
dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
dep_tristate ' ipaddr match support' CONFIG_IP_NF_MATCH_IPADDR $CONFIG_IP_NF_IPTABLES

Then, edit <Linux/documentation/configure. Help>
Add aggravated rows. I copied some text to help you find the content you want to add.

limit match support
CONFIG_IP_NF_MATCH_LIMIT
limit matching allows you to control the rate at which a rule can be
...
ipaddr match support
CONFIG_IP_NF_MATCH_IPADDR
ipaddr matching. etc etc.

Finally, you must add the aggravated rows to <Linux/NET/IPv4/Netfilter/makefile>.

# matches
obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
obj-$(CONFIG_IP_NF_MATCH_IPADDR) += ipt_ipaddr.o

Now for 2.6, files to edit are
<Linux/NET/IPv4/Netfilter/kconfig> And
<Linux/NET/IPv4/Netfilter/makefile>. For the 2.6 kernel, the edited file should be
<Linux/NET/IPv4/Netfilter/kconfig> And
<Linux/NET/IPv4/Netfilter/makefile>.

Summary

The rest of the following is the re-compilation and I forgot to talk about it.
Happy hacking !!
Thanks to Samuel Jean.

 

  Original article addressHttp://www.tldp.org/linuxfocus/ChineseGB/February2005/article367.shtml

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.