📄 netfilter-hacking-howto.txt
字号:
One warning about doing tricky things (such as providing counters) in
the extra space in your new match or target. On SMP machines, the
entire table is duplicated using memcpy for each CPU: if you really
want to keep central information, you should see the method used in
the `limit' match.
[1m4.2.1.1. New Match Functions[0m
New match functions are usually written as a standalone module. It's
possible to have these modules extensible in turn, although it's
usually not necessary. One way would be to use the netfilter
framework's `nf_register_sockopt' function to allows users to talk to
your module directly. Another way would be to export symbols for
other modules to register themselves, the same way netfilter and
ip_tables do.
The core of your new match function is the struct ipt_match which it
passes to `ipt_register_match()'. This structure has the following
fields:
[1mlist[0m
This field is set to any junk, say `{ NULL, NULL }'.
[1mname[0m
This field is the name of the match function, as referred to by
userspace. The name should match the name of the module (i.e.,
if the name is "mac", the module must be "ipt_mac.o") for auto-
loading to work.
[1mmatch[0m
This field is a pointer to a match function, which takes the
skb, the in and out device pointers (one of which may be NULL,
depending on the hook), a pointer to the match data in the rule
that is worked on (the structure that was prepared in
userspace), the IP offset (non-zero means a non-head fragment),
a pointer to the protocol header (i.e., just past the IP
header), the length of the data (ie. the packet length minus the
IP header length) and finally a pointer to a `hotdrop' variable.
It should return non-zero if the packet matches, and can set
`hotdrop' to 1 if it returns 0, to indicate that the packet must
be dropped immediately.
[1mcheckentry[0m
This field is a pointer to a function which checks the
specifications for a rule; if this returns 0, then the rule will
not be accepted from the user. For example, the "tcp" match
type will only accept tcp packets, and so if the `struct ipt_ip'
part of the rule does not specify that the protocol must be tcp,
a zero is returned. The tablename argument allows your match to
control what tables it can be used in, and the `hook_mask' is a
bitmask of hooks this rule may be called from: if your match
does not make sense from some netfilter hooks, you can avoid
that here.
[1mdestroy[0m
This field is a pointer to a function which is called when an
entry using this match is deleted. This allows you to
dynamically allocate resources in checkentry and clean them up
here.
[1mme [22mThis field is set to `THIS_MODULE', which gives a pointer to
your module. It causes the usage-count to go up and down as
rules of that type are created and destroyed. This prevents a
user removing the module (and hence cleanup_module() being
called) if a rule refers to it.
[1m4.2.1.2. New Targets[0m
If your target alters the packet (ie. the headers or the body), it
must call skb_unshare() to copy the packet in case it is cloned:
otherwise any raw sockets which have a clone of the skbuff will see
the alterations (ie. people will see wierd stuff happening in
tcpdump).
New targets are also usually written as a standalone module. The
discussions under the above section on `New Match Functions' apply
equally here.
The core of your new target is the struct ipt_target that it passes to
ipt_register_target(). This structure has the following fields:
[1mlist[0m
This field is set to any junk, say `{ NULL, NULL }'.
[1mname[0m
This field is the name of the target function, as referred to by
userspace. The name should match the name of the module (i.e.,
if the name is "REJECT", the module must be "ipt_REJECT.o") for
auto-loading to work.
[1mtarget[0m
This is a pointer to the target function, which takes the
skbuff, the hook number, the input and output device pointers
(either of which may be NULL), a pointer to the target data, and
the position of the rule in the table. The target function may
return either IPT_CONTINUE (-1) if traversing should continue,
or a netfilter verdict (NF_DROP, NF_ACCEPT, NF_STOLEN etc.).
[1mcheckentry[0m
This field is a pointer to a function which checks the
specifications for a rule; if this returns 0, then the rule will
not be accepted from the user.
[1mdestroy[0m
This field is a pointer to a function which is called when an
entry using this target is deleted. This allows you to
dynamically allocate resources in checkentry and clean them up
here.
[1mme [22mThis field is set to `THIS_MODULE', which gives a pointer to
your module. It causes the usage-count to go up and down as
rules with this as a target are created and destroyed. This
prevents a user removing the module (and hence cleanup_module()
being called) if a rule refers to it.
[1m4.2.1.3. New Tables[0m
You can create a new table for your specific purpose if you wish. To
do this, you call `ipt_register_table()', with a `struct ipt_table',
which has the following fields:
[1mlist[0m
This field is set to any junk, say `{ NULL, NULL }'.
[1mname[0m
This field is the name of the table function, as referred to by
userspace. The name should match the name of the module (i.e.,
if the name is "nat", the module must be "iptable_nat.o") for
auto-loading to work.
[1mtable[0m
This is a fully-populated `struct ipt_replace', as used by
userspace to replace a table. The `counters' pointer should be
set to NULL. This data structure can be declared `__initdata'
so it is discarded after boot.
[1mvalid_hooks[0m
This is a bitmask of the IPv4 netfilter hooks you will enter the
table with: this is used to check that those entry points are
valid, and to calculate the possible hooks for ipt_match and
ipt_target `checkentry()' functions.
[1mlock[0m
This is the read-write spinlock for the entire table; initialize
it to RW_LOCK_UNLOCKED.
[1mprivate[0m
This is used internally by the ip_tables code.
[1m4.2.2. Userspace Tool[0m
Now you've written your nice shiny kernel module, you may want to
control the options on it from userspace. Rather than have a branched
version of iptables for each extension, I use the very latest 90's
technology: furbies. Sorry, I mean shared libraries.
New tables generally don't require any extension to iptables: the user
just uses the `-t' option to make it use the new table.
The shared library should have an `_init()' function, which will
automatically be called upon loading: the moral equivalent of the
kernel module's `init_module()' function. This should call
`register_match()' or `register_target()', depending on whether your
shared library provides a new match or a new target.
You need to provide a shared library: this can be used to initialize
part of the structure, or provide additional options. I now insist on
a shared library even if it doesn't do anything, to reduce problem
reports where the shares libraries are missing.
There are useful functions described in the `iptables.h' header,
especially:
[1mcheck_inverse()[0m
checks if an argument is actually a `!', and if so, sets the
`invert' flag if not already set. If it returns true, you
should increment optind, as done in the examples.
[1mstring_to_number()[0m
converts a string into a number in the given range, returning -1
if it is malformed or out of range. `string_to_number' rely on
`strtol' (see the manpage), meaning that a leading "0x" would
make the number be in Hexadecimal base, a leading "0" would make
it be in Octal base.
[1mexit_error()[0m
should be called if an error is found. Usually the first
argument is `PARAMETER_PROBLEM', meaning the user didn't use the
command line correctly.
[1m4.2.2.1. New Match Functions[0m
Your shared library's _init() function hands `register_match()' a
pointer to a static `struct iptables_match', which has the following
fields:
[1mnext[0m
This pointer is used to make a linked list of matches (such as
used for listing rules). It should be set to NULL initially.
[1mname[0m
The name of the match function. This should match the library
name (eg "tcp" for `libipt_tcp.so').
[1mversion[0m
Usually set to the IPTABLES_VERSION macro: this is used to
ensure that the iptables binary doesn't pick up the wrong shared
libraries by mistake.
[1msize[0m
The size of the match data for this match; you should use the
IPT_ALIGN() macro to ensure it is correctly aligned.
[1muserspacesize[0m
For some matches, the kernel changes some fields internally (the
`limit' target is a case of this). This means that a simple
`memcmp()' is insufficient to compare two rules (required for
delete-matching-rule functionality). If this is the case, place
all the fields which do not change at the start of the
structure, and put the size of the unchanging fields here.
Usually, however, this will be identical to the `size' field.
[1mhelp[0m
A function which prints out the option synopsis.
[1minit[0m
This can be used to initialize the extra space (if any) in the
ipt_entry_match structure, and set any nfcache bits; if you are
examining something not expressible using the contents of
`linux/include/netfilter_ipv4.h', then simply OR in the
NFC_UNKNOWN bit. It will be called before `parse()'.
[1mparse[0m
This is called when an unrecognized option is seen on the
command line: it should return non-zero if the option was indeed
for your library. `invert' is true if a `!' has already been
seen. The `flags' pointer is for the exclusive use of your
match library, and is usually used to store a bitmask of options
which have been specified. Make sure you adjust the nfcache
field. You may extend the size of the `ipt_entry_match'
structure by reallocating if necessary, but then you must ensure
that the size is passed through the IPT_ALIGN macro.
[1mfinal_check[0m
This is called after the command line has been parsed, and is
handed the `flags' integer reserved for your library. This
gives you a chance to check that any compulsory options have
been specified, for example: call `exit_error()' if this is the
case.
[1mprint[0m
This is used by the chain listing code to print (to standard
output) the extra match information (if any) for a rule. The
numeric flag is set if the user specified the `-n' flag.
[1msave[0m
This is the reverse of parse: it is used by `iptables-save' to
reproduce the options which created the rule.
[1mextra_opts[0m
This is a NULL-terminated list of extra options which your
library offers. This is merged with the current options and
handed to getopt_long; see the man page for details. The return
code for getopt_long becomes the first argument (`c') to your
`parse()' function.
There are extra elements at the end of this structure for use
internally by iptables: you don't need to set them.
[1m4.2.2.2. New Targets[0m
Your shared library's _init() function hands `register_target()' it a
pointer to a static `struct iptables_target', which has similar fields
to the iptables_match structure detailed above.
[1m4.2.3. Using `libiptc'[0m
libiptc is the iptables control library, designed for listing and
manipulating rules in the iptables kernel module. While its current
use is for the iptables program, it makes writing other tools fairly
easy. You need to be root to use these functions.
The kernel tables themselves are simply a table of rules, and a set of
numbers representing entry points. Chain names ("INPUT", etc) are
provided as an abstraction by the library. User defined chains are
labelled by inserting an error node before the head of the user-
defined chain, which contains the chain name in the extra data section
of the target (the builtin chain positions are defined by the three
table entry points).
The following standard targets are supported: ACCEPT, DROP, QUEUE
(which are translated to NF_ACCEPT, NF_DROP, and NF_QUEUE,
respectively), RETURN (which is translated to a special IPT_RETURN
value handled by ip_tables), and JUMP (which is translated from the
chain name to an actual offset within the table).
When `iptc_init()' is called, the table, including the counters, is
read. This table is manipulated by the `iptc_insert_entry()',
`iptc_replace_entry()', `iptc_append_entry()', `iptc_delete_entry()',
`iptc_delete_num_entry()', `iptc_flush_entries()',
`iptc_zero_entries()', `iptc_create_chain()' `iptc_delete_chain()',
and `iptc_set_policy()' functions.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -