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 article describes how to write custom target modules. A target is the result of a firewall rule policy. It defines how data packets are processed, such as accept, discard, modify, and continue. The implementation is divided into two parts: the kernel
Part and user space part: the kernel is implemented by the extension module of Netfilter. After defining the module and attaching it to the target linked list of Netfilter, the module is automatically detected when the Kernel performs the target detection.
Find the module based on the target name and call the corresponding target function to complete the real target function. In the user space, the target module is implemented as an extended dynamic library of iptables, just by a user
Interface, does not complete the actual target function, complete the function of receiving user input and passing the target data structure to the kernel, the Library name is limited, must be libipt_xxx.so, where "XXX" is
The target name is different from the matching name. Generally, the target name is in uppercase. 2. the function parameters of the kernel module in the kernel 2.4 are slightly different from those in the kernel 2.6. 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 how to modify the ID field in the IP header. In actual use, this function has no practical significance, for example. The net/IPv4/Netfilter/ipt_id.c module is provided in the kernel to modify the ID field in the IP header. We can modify the field based on this module. First, define the target data structure to describe the target condition. modify it to/* include/Linux/netfilter_ipv4/ipt_id.h */Based on the ipt_id.h header file */
# Ifndef _ ipt_id_h_target
# DEFINE _ ipt_id_h_targetstruct ipt_id_target_info {
/* Network order .*/
U_int16_t ID; // ID is the number of 16 bits
}; # Endif/* _ ipt_id_h_target */then defines kernel module processing. The most important thing is to define an ipt_target target structure, which is defined in include/Linux/netfilter_ipv4/ip_tables.h: /* Registration hooks for targets. */
Struct ipt_target
{
Struct list_head list; const char name [ipt_function_maxnamelen];/* called when user tries to insert an entry of this type:
Hook_mask is a bitmask of hooks from which it can be
Called .*/
/* Shoshould return true or false .*/
INT (* checkentry) (const char * tablename,
Const struct ipt_entry * E,
Void * targinfo,
Unsigned int targinfosize,
Unsigned int hook_mask);/* called when entry of this type deleted .*/
Void (* destroy) (void * targinfo, unsigned int targinfosize);/* returns verdict. Argument order sinchanged 2.4, as this
Must Now handle non-linear skbs, using skb_copy_bits and
Skb_ip_make_writable .*/
Unsigned int (* Target) (struct sk_buff ** pskb,
Const struct net_device * In,
Const struct net_device * Out,
Unsigned int hooknum,
Const void * targinfo,
Void * userdata);/* set this to this_module .*/
Struct module * Me;
}; The structure has the following parameters:
Struct list_head list: Used to link to the target linked list. It must be initialized to {null, null };
Name: name of the target name, which must be unique;
The checkentry function is used to check the validity of the data passed in at the user layer, for example, whether the target data length is correct or whether it is used in the correct table;
Destroy: This function is used to release resources dynamically allocated to the target. It is called when the rule is deleted;
Target
Function: this function is the main function that completes the rule processing of data packets, including modifying the data in the package. The returned result of the function may be nf_accept (accepted)/nf_drop (discarded)
/Nf_stolen (Theft indicates that the packet processing is taken over by the target and is no longer processed by the system network stack)/ipt_continue (continue, continue to check the packet according to the following rules;
Struct module * Me: points to the module itself. The target structure in this example is defined as follows:
Static struct ipt_target ipt_id_reg = {
. Name = "ID ",
. Target = target,
. Checkentry = checkentry,
. Me = this_module,
}; The target function is the core function of the target. If 1 is returned, the data meets the target condition. If 0 is returned, the function is defined as follows:
Unsigned int (* Target) (struct sk_buff ** pskb,
Const struct net_device * In,
Const struct net_device * Out,
Unsigned int hooknum,
Const void * targinfo,
Void * userdata );
The parameter of the target function is:
SKB: Data Packet
In: The network card that the data enters
Out: The NIC from which the data is sent
Hooknum: hook number. Value: NF_IP_PRE_ROUTING/nf_ip_local_in/nf_ip_forward/nf_ip_local_out/nf_ip_post_routing
Targetinfo: pointer to the target condition information
Offset: the shard data offset.
Userdata: special dedicated data. Currently, it is basically useless in the kernel and is usually null. The check function checks the data. If the return value is 1, the data is valid, and 0 indicates that the data is invalid. The function is defined:
INT (* checkentry) (const char * tablename,
Const struct ipt_entry * E,
Void * targinfo,
Unsigned int targinfosize,
Unsigned int hook_mask); tablename: Table name, such as "filter", "Nat", and "mangle", which can be used to limit that the target can only be processed in the specified table;
Struct ipt_entry * E: pointer to rule;
Targetinfo: pointer to the target condition information passed in by the user space;
Targetinfosize: the length of the target 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 restrict the target to be processed only in the specified mount point; the macro ipt_align is used to obtain the actual size of the target structure. In this example, you need to check whether the target data length is correct and whether the table name is "mangle". Because you need to modify the data, you must process the data in the mangle table; the destroy function releases the resources dynamically allocated to the target. No return value is returned. The function is defined:
Void (* destroy) (void * targetinfo, unsigned int targetinfosize );
Function parameters are the same as the description of the check () function. In this example, related resources are not allocated, so this function is not defined. Finally, call the ipt_register_target () function in the module initialization function to link an ipt_target target structure to the system target linked list. Call ipt_unregister_target () in the module end function () the function removes the target structure from the target linked list. Modify the net/IPv4/Netfilter/makefile and kconfig files, add ipt_id-related content to automatically compile in the compiling kernel, or directly compile it as a module and insert it into the kernel. The ipt_id.c code is as follows:/* This is a module which is used for setting the ID field of a packet.
* Based on ipt_id.c
* In fact, it's useless.
*/# Include <Linux/module. h>
# Include <Linux/skbuff. h>
# Include <Linux/IP. h>
# Include <net/checksum. h> # include <Linux/netfilter_ipv4/ip_tables.h>
# Include <Linux/netfilter_ipv4/ipt_id.h> module_license ("GPL ");
Module_author ("yfydz <yfydz_no1@hotmail.com
> ");
Module_description ("iptables ID mangling module"); static unsigned int
Target (struct sk_buff ** pskb,
Const struct net_device * In,
Const struct net_device * Out,
Unsigned int hooknum,
Const void * targinfo,
Void * userinfo)
{
Const struct ipt_id_target_info * idinfo = targinfo; // If the id value of the current package is different from the specified value, assign the specified value to the ID field in the IP header.
If (* pskb)-> NH. iph-> ID! = Idinfo-> ID ){
U_int16_t diffs [2]; If (! Skb_ip_make_writable (pskb, sizeof (struct iphdr )))
Return nf_drop; diffs [0] = htons (* pskb)-> NH. iph-> ID) ^ 0 xFFFF;
(* Pskb)-> NH. iph-> ID
= Idinfo-> ID;
Diffs [1] = htons (* pskb)-> NH. iph-> ID );
// Because the IP packet data has been modified, you need to re-calculate the checksum in the IP Header
(* Pskb)-> NH. iph-> check
= Csum_fold (csum_partial (char *) diffs,
Sizeof (diffs ),
(* Pskb)-> NH. iph-> check
^ 0 xFFFF ));
(* Pskb)-> nfcache | = nfc_altered;
}
// Return ipt_continue, indicating to continue processing data packets according to the next rule
Return ipt_continue;
} Static int
Checkentry (const char * tablename,
Const struct ipt_entry * E,
Void * targinfo,
Unsigned int targinfosize,
Unsigned int hook_mask)
{
Const u_int8_t id = (struct ipt_id_target_info *) targinfo)-> ID;
// Check whether the length of user input data is correct
If (targinfosize! = Ipt_align (sizeof (struct ipt_id_target_info ))){
Printk (kern_warning "ID: targinfosize % u! = % Zu/N ",
Targinfosize,
Ipt_align (sizeof (struct ipt_id_target_info )));
Return 0;
}
// Determine whether the table is in the mangle table
If (strcmp (tablename, "mangle ")! = 0 ){
Printk (kern_warning "ID: can only be called from/" mangle/"table, not/" % S/"/N", tablename );
Return 0;
} Return 1;
} Static struct ipt_target ipt_id_reg = {
. Name = "ID ",
. Target = target,
. Checkentry = checkentry,
. Me = this_module,
}; Static int _ init Init (void)
{
Return ipt_register_target (& ipt_id_reg );
} Static void _ exit Fini (void)
{
Ipt_unregister_target (& ipt_id_reg );
} Module_init (init );
Module_exit (fini); If you modify the data in the package, you need to modify the corresponding checksum of the Data header, such as IP header checksum and TCP/UDP header checksum, so you may need to call
Csum_partial (), tcp_v4_check (), csum_tcpudp_magic (), ip_send_check (IPH), etc.
Calculate the checksum. For how to use these functions, refer to the Code instances in the kernel. Some targets have complicated operations on packages, such as reject and mirror. Therefore, a response packet must be constructed, which is generally more complex than matching. 3. The extension target module in iptables, the target module of the iptables user layer, is processed as a dynamic library.
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 the Target Dynamic library is used to parse the target information entered by the user and display the target 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. The most important data structure for the target is the struct iptables_target structure. The extended target program defines this structure and attaches it to the iptables target linked list. The structure is defined as follows: struct iptables_target
{
Struct iptables_target * Next; ipt_chainlabel name; const char * version;/* size of target data .*/
Size_t size;/* size of target data relevent for userspace comparison purposes */
Size_t userspacesize;/* function which prints out usage message .*/
Void (* Help) (void);/* initialize the target .*/
Void (* init) (struct ipt_entry_target * t, 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,
Struct ipt_entry_target ** target);/* Final check; exit if not OK .*/
Void (* final_check) (unsigned int flags);/* prints out the target IFF non-null: put space at end */
Void (* print) (const struct ipt_ip * IP,
Const struct ipt_entry_target * target, int numeric);/* saves the targinfo in parsable form to stdout .*/
Void (* save) (const struct ipt_ip * IP,
Const struct ipt_entry_target * target);/* pointer to list of extra command-line options */
Struct option * extra_opts;/* ignore these men behind the curtain :*/
Unsigned int option_offset;
Struct ipt_entry_target * t;
Unsigned int tflags;
Unsigned int used;
# Ifdef no_shared_libs
Unsigned int loaded;/* simulate loading so options are merged properly */
# Endif
}; Struct iptables_target structure parameters are described as follows:
Next: next to the target linked list. The target linked list is a one-way linked list;
Name: the name of the target, which must be unique;
Version: version of iptables;
Size: The Data Length of the target structure;
Userspacesize: The Data Length of the target part. This value is usually equal to size, but may be smaller than size in some cases;
Help function: Print help information, called when "-j xxx-h;
Init function: initialization function. You can assign an initial value to the target 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 the target information, which is called when iptables-L is used.
Save function: prints the target format when saving the current iptables rule, which is called by the 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;
T: pointing to iptables rules;
Tflags: Rule-related flag
Used: module count. In this example, the user input parameter is a new ID value in the format:
"-J id -- Set-ID
Id_value "
Id_value Is the actual value of ID. The libipt_id.c function is to fill in the struct iptables_target structure, and then define the dynamic library initialization function _ Init () to link the structure to the option linked list of iptables. The program is modified on the basis of libipt_id.c. The program is relatively simple and the code is listed directly. The relevant instructions are in the Notes:/* libipt_id.c */
/* Shared library add-on to iptables to add ID target support .*/
# Include <stdio. h>
# Include <string. h>
# Include <stdlib. h>
# Include <getopt. h> # include <iptables. h>
# Include <Linux/netfilter_ipv4/ip_tables.h>
# Include <Linux/netfilter_ipv4/ipt_id.h> struct idinfo {
Struct ipt_entry_target T;
Struct ipt_id_target_info ID;
};/* Function which prints out usage message .*/
Static void
Help (void)
{
Unsigned int I; printf (
"Id target v % s options:/N"
"-- Set-id value set ID of IP headere/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 [] = {
{"Set-ID", 1, 0, '1 '},
{0}
};/* Initialize the target .*/
Static void
Init (struct ipt_entry_target * t, unsigned int * nfcache)
{
// Empty function, no preprocessing required
} Static void
Parse_id (const unsigned char * s, struct ipt_id_target_info * info)
{
Unsigned int I, ID; If (string_to_number (S, 0,255, & ID )! =-1 ){
// Switch host sequence data to network Sequence
Info-> id = htons (u_int16_t) ID );
Return;
}
Exit_error (parameter_problem, "Bad id value '% S'", S );
}/* 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,
Struct ipt_entry_target ** target)
{
Struct ipt_id_target_info * idinfo
= (Struct ipt_id_target_info *) (* Target)-> data; Switch (c ){
Case '1 ':
If (* flags)
Exit_error (parameter_problem,
"Id target: cant specify -- Set-ID twice ");
Parse_id (optarg, idinfo );
* Flags = 1;
Break; default:
Return 0;
} Return 1;
} Static void
Final_check (unsigned int flags)
{
If (! Flags)
Exit_error (parameter_problem,
"Id target: parameter -- Set-ID is required ");
} Static void
Print_id (u_int8_t ID, int numeric)
{
Unsigned int I; printf ("0x % x", ntohs (ID ));
}/* Prints out the targinfo .*/
Static void
Print (const struct ipt_ip * IP,
Const struct ipt_entry_target * target,
Int numeric)
{
Const struct ipt_id_target_info * idinfo =
(Const struct ipt_id_target_info *) Target-> data;
Printf ("ID set ");
Print_id (idinfo-> ID, numeric );
}/* Saves the Union ipt_targinfo in parsable form to stdout .*/
Static void
Save (const struct ipt_ip * IP, const struct ipt_entry_target * target)
{
Const struct ipt_id_target_info * idinfo =
(Const struct ipt_id_target_info *) Target-> data; printf ("-- Set-ID 0x % x", ntohs (idinfo-> ID ));
} Static
Struct iptables_target ID
= {Null,
"ID ",
Iptables_version,
Ipt_align (sizeof (struct ipt_id_target_info )),
Ipt_align (sizeof (struct ipt_id_target_info )),
& Help,
& Init,
& Parse,
& Final_check,
& Print,
& Save,
Opts
}; Void _ Init (void)
{
Register_target (& ID );
} 4. Conclusion: Netfilter/iptables can easily expand the new target 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. You can modify the code based on the ready-made target module during implementation, 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.
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.