Define the matching module of iptables/Netfilter

Source: Internet
Author: User
Copyleft of this document belongs to yfydz and can be freely copied and reproduced when published using GPL. It is strictly prohibited to be used for any commercial purposes.
MSN: yfydz_no1@hotmail.com

In Linux, netfilter provides a firewall framework with good scalability. In addition to the built-in modules, users can define new firewall modules according to their own needs.
The programming process is not very complex, as long as it can be modified based on modules with similar functions, or even how each function is called, some internal structures are not defined.
This document describes how to compile a custom matching module. Match is the condition part in the firewall rule policy. The matching result returns 0 (matching failed) or 1 (matching successful) to determine whether the data packet meets the policy. At specific implementation time
The kernel part and the user space part are implemented using the netfilter extension module in the kernel. After defining the module and attaching it to the netfilter matching linked list
During row matching detection, the corresponding matching function is automatically called Based on the matching name to complete the real matching function. In the user space, the matching module is implemented as an extended dynamic library of iptables.
Currently, it is only a user interface that does not complete the actual matching function. It receives user input and passes the matching data structure to the kernel. The Library name must be libipt_xxx.so,
"XXX" indicates the name of the matching, which is usually in lower case. 2. kernel module matching function parameters in kernel 2.4 and kernel 2.6 are slightly different. The two are incompatible, but they can be transplanted to each other after simple modification. The main part does not need to be changed, this article takes the 2.6 kernel module as an example. For convenience, we can use examples to illustrate that the object to be matched is an IP address segment, but some IP addresses in this segment may not meet the matching conditions to form an address "hole ", in this case, it is often used in practical applications to handle several IP addresses in a CIDR block. The net/IPv4/Netfilter/ipt_iprange.c module is provided in the kernel to match the address segment. We can modify the module and add the address "hole. First, you must define the data structure to be matched to describe the matching conditions. modify it to/* include/Linux/netfilter_ipv4/ipt_iprangehole.h */# ifndef _ ipt_iprangehole_h Based on the ipt_iprange.h header file
# DEFINE _ ipt_iprangehole_h # define iprange_src 0x01/* match source IP address */
# Define iprange_dst 0x02/* match destination IP address */
# Define iprange_src_inv 0x10/* negate the condition */
# Define iprange_dst_inv 0x20/* negate the condition */
# Define max_holes_num 10/* defines the maximum number of IP "holes" in a match */struct ipt_iprangehole {
/* Random sive: Network order .*/
U_int32_t min_ip, max_ip;
U_int32_t holes [max_holes_num];/* IP hole address */
}; Struct ipt_iprangehole_info
{
Struct ipt_iprangehole SRC;
Struct ipt_iprangehole DST;/* flags from above */
U_int8_t flags;
}; # Endif/* _ ipt_iprangehole_h */then defines kernel module processing. The most important thing is to define an ipt_match matching structure, which is defined in include/Linux/netfilter_ipv4/ip_tables.h: struct ipt_match
{
Struct list_head list; const char name [ipt_function_maxnamelen];/* return true or false: Return false and Set * hotdrop = 1
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 .*/
/* Shoshould 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;
}; The structure has the following parameters:
Struct list_head list: Used to link to a matched linked list. It must be initialized to {null, null };
Name: name of the matched name, which must be unique;
Match function: This function is the main function. After the packet matching condition check is completed, 1 indicates that the matching is successful, and 0 indicates that the matching fails;
The checkentry function is used to check the validity of the data passed in at the user layer, for example, whether the matching data length is correct or whether it is used in the correct table;
Destroy: This function is used to release resources dynamically allocated in the match and is called when the rule is deleted;
Struct module * Me: points to the module itself. The matching structure in this example is defined as follows:
Static struct ipt_match iprangehole_match =
{
. List = {null, null },
. Name = "iprangehole ",
. Match = & match,
. Checkentry = & check,
. Destroy = NULL,
. Me = this_module
}; The match function is the core function for matching. If the return value is 1, the data meets the matching condition. If the return value is 0, the data does not match. The function is defined as follows:
INT (* match) (const struct sk_buff * SKB,
Const struct net_device * In,
Const struct net_device * Out,
Const void * matchinfo,
Int offset,
Int * hotdrop );
In the match function, the parameters are:
SKB: Data Packet
In: The network card that the data enters
Out: The NIC from which the data is sent
Matchinfo: pointer to match condition information
Offset: the shard data offset.
Hotdrop: discard data immediately. This function is used to match the content of the SKB data packet according to the matchinfo matching condition. It checks whether the content of the data packet meets the matching condition and supports reverse processing.
If (1/0) is different from whether to obtain the inverse (1/0), the final result is obtained. In this example, you can add an IP address "hole" Check In ipt_iprange.c. Note the hotdrop parameter. Generally, matching does not determine the data processing policy. However, this parameter can cause the kernel to discard the data packet immediately. The check function checks the data. If the return value is 1, the data is valid. If the return value is 0, the data is invalid. The function is defined:
INT (* checkentry) (const char * tablename,
Const struct ipt_ip * IP,
Void * matchinfo,
Unsigned int matchinfosize,
Unsigned int hook_mask );
Tablename: The table name, such as "filter", "Nat", and "mangle". It can be used to restrict matching to a specified table;
Struct ipt_ip * IP: contains the relevant information in the corresponding IP header;
Matchinfo: pointer to the matching condition information passed in by the user space;
Matchinfosize: the length of the matching condition information passed in to the user space;
Hook_mask: indicates the mask of the mount point (prerouting/input/forward/output/postrouting). It can be used to limit matching to be processed only in the specified mount point; the macro ipt_align is used to obtain the actual size of the actually matched structure. In this example, you only need to check whether the length of the matching data is correct. The processing is the same as ipt_iprange, and no modification is required. The destroy function releases the resources dynamically allocated in the matching. No return value is returned. The function is defined:
Void (* destroy) (void * matchinfo, unsigned int matchinfosize );
Function parameters are the same as the description of the check () function. In this example, no related resources are allocated. This function is null ). Finally, call the ipt_register_match () function in the module initialization function to link an ipt_match matching structure to the system matching linked list. Call ipt_unregister_match () in the module end function () the function removes the matching structure from the matched linked list. Modify the net/IPv4/Netfilter/makefile and kconfig files, add relevant content about ipt_iprangehole to automatically compile in the compiling kernel, or directly compile it as a module and insert it into the kernel. The ipt_iprangehole.c code is as follows :/*
* Net/IPv4/Netfilter/ipt_iprangehole.c
* Iptables module to Match ip address ranges with Holes
* Based on ipt_iprange.c
*
* This program is free software; you can redistribute it and/or modify
* It under the terms of the GNU General Public License version 2
* Published by the Free Software Foundation.
*/
# Include <Linux/module. h>
# Include <Linux/skbuff. h>
# Include <Linux/IP. h>
# Include <Linux/netfilter_ipv4/ip_tables.h>
# Include <Linux/netfilter_ipv4/ipt_iprangehole.h> module_license ("GPL ");
Module_author ("yfydz <yfydz_no1@hotmial.com
> ");
Module_description ("iptables arbitrary IP range with holes match module"); # If 0
# Define debugp printk
# Else
# Define debugp (format, argS ...)
# Endif // This is a new addition function. Check whether the address belongs to an IP hole.
Static int in_holes (u_int32_t ADDR, u_int32_t * holes)
{
Int I;
For (I = 0; I <max_holes_num; I ++)
If (ADDR = holes [I]) return 1;
Return 0;
} Static int
Match (const struct sk_buff * SKB,
Const struct net_device * In,
Const struct net_device * Out,
Const void * matchinfo,
Int offset, int * hotdrop)
{
Const struct ipt_iprangehole_info * info = matchinfo;
Const struct iphdr * IPH = SKB-> NH. iph; If (Info-> flags & iprange_src ){
If (ntohl (IPH-> saddr) <ntohl (Info-> SRC. min_ip ))
| (Ntohl (IPH-> saddr)> ntohl (Info-> SRC. max_ip ))
| (In_holes (IPH-> saddr, info-> SRC. holes )))
^ !! (Info-> flags & iprange_src_inv )){
Debugp ("src IP % u. % u not in range % s"
"% U. % u-% u. % u/N ",
Nipquad (IPH-> saddr ),
Info-> flags & iprange_src_inv? "(INV )":"",
Nipquad (Info-> SRC. min_ip ),
Nipquad (Info-> SRC. max_ip ));
Return 0;
}
}
If (Info-> flags & iprange_dst ){
If (ntohl (IPH-> daddr) <ntohl (Info-> DST. min_ip ))
| (Ntohl (IPH-> daddr)> ntohl (Info-> DST. max_ip ))
| (In_holes (IPH-> daddr, info-> DST. holes )))
^ !! (Info-> flags & iprange_dst_inv )){
Debugp ("dst ip % u. % u not in range % s"
"% U. % u-% u. % u/N ",
Nipquad (IPH-> daddr ),
Info-> flags & iprange_dst_inv? "(INV )":"",
Nipquad (Info-> DST. min_ip ),
Nipquad (Info-> DST. max_ip ));
Return 0;
}
}
Return 1;
} Static int check (const char * tablename,
Const struct ipt_ip * IP,
Void * matchinfo,
Unsigned int matchsize,
Unsigned int hook_mask)
{
/* Verify size */
If (matchsize! = Ipt_align (sizeof (struct ipt_iprangehole_info )))
Return 0; return 1;
} Static struct ipt_match iprangehole_match =
{
. List = {null, null },
. Name = "iprangehole ",
. Match = & match,
. Checkentry = & check,
. Destroy = NULL,
. Me = this_module
}; Static int _ init Init (void)
{
Return ipt_register_match (& iprangehole_match );
} Static void _ exit Fini (void)
{
Ipt_unregister_match (& iprangehole_match );
} Module_init (init );
Module_exit (fini); 3. The extension matching module in the iptables user-layer matching module is processed as a dynamic library, and "-M" is used in the command line
Xxx "to enable iptables to call the corresponding libipt_xxx.so dynamic library.
In the iptables-<version>/extension directory, the compiled dynamic library is stored in/usr/local/lib/iptables by default.
Directory. The function of dynamic library matching is used to parse the matching information entered by the user and display matching information. Write the libipt_xxx.c program and put it in the iptables-<version>/extension directory. Modify the MAKEFILE file in the directory and add XXX to the extension table, make can automatically compile it into a dynamic library. For matching, the most important data structure is the struct iptables_match structure. The extended matching program defines this structure and mounts it to the iptables matching linked list. The structure is defined as follows: 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;
Unsigned int used;
# Ifdef no_shared_libs
Unsigned int loaded;/* simulate loading so options are merged properly */
# Endif
}; Struct iptables_match structure parameters are described as follows:
Next: match the next of the linked list. The matched linked list is a one-way linked list;
Name: The matched name, which must be unique;
Version: version of iptables;
Size: The Data Length of the matching structure;
Userspacesize: Used to match the data length of a part. Generally, this value is equal to size, but may be smaller than size in some cases, such as limit matching. There are some changed parameters in the limit matching structure, these parameters do not need to be matched for matching, but only the fixed data part is matched;
Help function: Print help information, called when "-m xxx-h;
Init function: initialization function. You can assign an initial value to the matching structure;
Parse function: parses user input parameters. This is the most important processing function;
Final_check function: performs the final check on user data;
Print function: Print matching information, called when iptables-l
Save function: print the matching format when saving the current iptables rule, called by iptables-Save program;
Extra_opts: Option information. The option format is standard UNIX option format, which is identified by the getopt function;
Option_offset: Option offset;
M: pointing to iptables rules;
Used: module usage count. In this example, the user is required to enter the IP address segment and the corresponding IP address "hole". The required data format is:
IP-IP/IP [, IP...]
IP addresses are IP addresses in the format of point data, such as 1.1.1.1;
"-" Connection IP start and end values;
"/" Separate the CIDR blocks and the address "holes"
IP addresses in the "holes" section are separated by "," with no spaces in the middle. For example, the address range is 10.10.10.1 to 10.10.10.100, and the address "hole" is 10.10.10.10, 10.10.10.20, and 10.10.10.30. The format is as follows:
10.10.10.1-10.10.10.100/10.10.10.10, 10.10.10.20, 10.10.10.30 libipt_iprangehole.c function is to fill in struct iptables_match
Iprangehole structure, and then define the dynamic library initialization function _ Init () to link the structure to the option linked list of iptables. Program in
Libipt_iprange.c. The program is relatively simple and the code is directly listed. The relevant instructions are in the Notes:/* libipt_iprangehole.c */
/* Shared library add-on to iptables to add IP Range matching support. */# include <stdio. h>
# Include <netdb. h>
# Include <string. h>
# Include <stdlib. h>
# Include <getopt. h> # include <iptables. h>
# Include <Linux/netfilter_ipv4/ipt_iprangehole.h>/* function which prints out usage message .*/
Static void
Help (void)
{
Printf (
"Iprange match v % s options:/N"
"[!] -- Src-range IP-IP/ip_holes match source IP in the specified range/N"
"[!] -- DST-range IP-IP/ip_holes match Destination IP in the specified range/N"
"/N ",
Iptables_version );
} // The first parameter in the OPTs structure is the option name,
// If the second parameter is 1, the option name is followed by a parameter. If the parameter is 0, the option name is not followed by a parameter.
// The third parameter is a flag, indicating the format of the returned data, which is generally set to 0.
// 4th parameters indicate the index value of this option
Static struct option opts [] = {
{"Src-range", 1, 0, '1 '},
{"DST-range", 1, 0, '2 '},
{0}
};/* Initialize the match .*/
Static void
Init (struct ipt_entry_match * m, unsigned int * nfcache)
{
Struct ipt_iprangehole_info * info = (struct ipt_iprangehole_info *) m-> data;
/* Can't cache this .*/
* Nfcache | = nfc_unknown;
// Initialize the structure data to 0
Bzero (Info, sizeof (struct ipt_iprangehole_info ));
} Static void
Parse_iprange (char * Arg, struct ipt_iprangehole * range)
{
Char * dash, * slash;
Struct in_addr * IP; slash = strchr (ARG ,'/');
If (slash)
* Slash = '/0 ';
Dash = strchr (ARG ,'-');
If (DASH)
* Dash = '/0'; // parse the address segment
IP = dotted_to_addr (ARG );
If (! IP)
Exit_error (parameter_problem, "iprange match: Bad IP address '% s'/N ",
Arg );
Range-> min_ip = IP-> s_addr; If (DASH ){
IP = dotted_to_addr (Dash + 1 );
If (! IP)
Exit_error (parameter_problem, "iprange match: Bad IP address '% s'/N ",
Dash + 1 );
Range-> max_ip = IP-> s_addr;
} Else
Range-> max_ip = range-> min_ip; // resolve the address Holes
If (range-> max_ip! = Range-> min_ip) & Slash ){
Char * PTR;
Int I = 0;
Do {
PTR = strchr (slash + 1 ,',');
If (PTR)
PTR = '/0 ';
IP = dotted_to_addr (slash + 1 );
If (! IP)
Exit_error (parameter_problem, "iprange match: Bad IP address '% s'/N ",
Slash + 1 );
If (IP-> s_addr ){
Range-> holes [I] = IP-> s_addr;
I ++;
}
Slash = PTR;
} While (slash! = NULL );
}
}/* Function which parses command options; returns true if it
Ate an option */
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)
{
Struct ipt_iprangehole_info * info = (struct ipt_iprangehole_info *) (* match)-> data; Switch (c ){
Case '1 ':
If (* flags & iprange_src)
Exit_error (parameter_problem,
"Iprange match: only use -- Src-range once! ");
* Flags | = iprange_src; Info-> flags | = iprange_src;
// Check whether "!" is included To reverse the matching
Check_inverse (optarg, & invert, & optind, 0 );
If (invert ){
Info-> flags | = iprange_src_inv;
Printf ("Hoho/N ");
}
Parse_iprange (optarg, & info-> SRC); break; Case '2 ':
If (* flags & iprange_dst)
Exit_error (parameter_problem,
"Iprange match: only use -- DST-range once! ");
* Flags | = iprange_dst; Info-> flags | = iprange_dst;
Check_inverse (optarg, & invert, & optind, 0 );
If (invert)
Info-> flags | = iprange_dst_inv; parse_iprange (optarg, & info-> DST );
* Flags = 1;
Break; default:
Return 0;
}
Return 1;
}/* Final check; must have specified -- Src-range or -- DST-range .*/
Static void
Final_check (unsigned int flags)
{
If (! Flags)
Exit_error (parameter_problem,
"Iprange match: You must specify '-- Src-range' or' -- DST-range '");
} Static void
Print_iprange (const struct ipt_iprangehole * range)
{
Const unsigned char * byte_min, * byte_max;
Int I; byte_min = (const unsigned char *) & (range-> min_ip );
Byte_max = (const unsigned char *) & (range-> max_ip );
Printf ("% d. % d-% d. % d ",
Byte_min [0], byte_min [1], byte_min [2], byte_min [3],
Byte_max [0], byte_max [1], byte_max [2], byte_max [3]);
If (range-> holes [0]) {
For (I = 0; I <max_holes_num; I ++)
If (! Range-> holes [I]) break;
Byte_min = (const unsigned char *) & (range-> holes [I]);
Printf ("% C % d. % d", I = 0? '/':',',
Byte_min [0], byte_min [1], byte_min [2], byte_min [3]);
}
Else
Printf ("");
}/* Prints out the info .*/
Static void
Print (const struct ipt_ip * IP,
Const struct ipt_entry_match * match,
Int numeric)
{
Struct ipt_iprangehole_info * info = (struct ipt_iprangehole_info *) Match-> data; If (Info-> flags & iprange_src ){
Printf ("Source IP Range ");
If (Info-> flags & iprange_src_inv)
Printf ("! ");
Print_iprange (& info-> SRC );
}
If (Info-> flags & iprange_dst ){
Printf ("Destination IP Range ");
If (Info-> flags & iprange_dst_inv)
Printf ("! ");
Print_iprange (& info-> DST );
}
}/* Saves the Union ipt_info in parsable form to stdout .*/
Static void
Save (const struct ipt_ip * IP, const struct ipt_entry_match * match)
{
Struct ipt_iprangehole_info * info = (struct ipt_iprangehole_info *) Match-> data; If (Info-> flags & iprange_src ){
If (Info-> flags & iprange_src_inv)
Printf ("! ");
Printf ("-- Src-range ");
Print_iprange (& info-> SRC );
If (Info-> flags & iprange_dst)
Fputc ('', stdout );
}
If (Info-> flags & iprange_dst ){
If (Info-> flags & iprange_dst_inv)
Printf ("! ");
Printf ("-- DST-range ");
Print_iprange (& info-> DST );
}
} Static
Struct iptables_match iprangehole
= {Null,
"Iprangehole ",
Iptables_version,
Ipt_align (sizeof (struct ipt_iprangehole_info )),
Ipt_align (sizeof (struct ipt_iprangehole_info )),
& Help,
& Init,
& Parse,
& Final_check,
& Print,
& Save,
Opts
}; Void _ Init (void)
{
Register_match (& iprangehole );
} 4. Conclusion: Netfilter/iptables can easily expand the new matching module. You only need to write the code in the specified method, so that developers can focus on the specific functions.
Now, you don't have to consider other factors. In actual implementation, you can modify the code based on the ready-made matching module, or even complete the coding without having to have a closer understanding of the definition of the internal structure, is a program module
An excellent example of implementation. On the netfilter official website (www.netfilter.org
The patch-o-matic package is provided, which contains matching and target modules not incorporated into the official Linux kernel by many enthusiasts.

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.