summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorBart De Schuymer <bdschuym@pandora.be>2002-09-06 19:10:33 +0000
committerBart De Schuymer <bdschuym@pandora.be>2002-09-06 19:10:33 +0000
commit68bdce38b3794bd91b89c7e2e3cb0c0dfa0163bf (patch)
tree9f2b1e7a32aec65eafea28e2dcd0bc555fc4bc92 /docs
parent89cc15e186d810ee281466bac734edaf6d60b28b (diff)
*** empty log message ***
Diffstat (limited to 'docs')
-rw-r--r--docs/ebtables-hacking/ebtables-hacking-HOWTO-1.html72
-rw-r--r--docs/ebtables-hacking/ebtables-hacking-HOWTO-2.html43
-rw-r--r--docs/ebtables-hacking/ebtables-hacking-HOWTO-3.html468
-rw-r--r--docs/ebtables-hacking/ebtables-hacking-HOWTO-4.html597
-rw-r--r--docs/ebtables-hacking/ebtables-hacking-HOWTO.html66
5 files changed, 1246 insertions, 0 deletions
diff --git a/docs/ebtables-hacking/ebtables-hacking-HOWTO-1.html b/docs/ebtables-hacking/ebtables-hacking-HOWTO-1.html
new file mode 100644
index 0000000..b4cf2d1
--- /dev/null
+++ b/docs/ebtables-hacking/ebtables-hacking-HOWTO-1.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Ebtables Hacking HOWTO: Introduction</title>
+
+<link HREF="ebtables-hacking-HOWTO.html#toc1" REL=contents>
+</head>
+<body>
+<a HREF="ebtables-hacking-HOWTO-2.html">Next</a>
+Previous
+<a HREF="ebtables-hacking-HOWTO.html#toc1">Contents</a>
+<hr>
+<h2><a NAME="intro"></a> <a NAME="s1">1.</a> <a HREF="ebtables-hacking-HOWTO.html#toc1">Introduction</a></h2>
+
+<p>Hi guys (famous opening sentence).</p>
+
+<p>This document wants to tell the interested how to implement extensions
+on top of the ebtables architecture.</p>
+
+<p>For more understanding of netfilter and a broader look I recommend
+reading the HOWTO's on the netfilter homepage. The "netfilter hacking HOWTO"
+is certainly worth your time. Also very recommended is the
+"ebtables/iptables interaction on a Linux-based bridge" document (call name br_fw_ia) which
+you can find on the ebtables homepage.
+</p>
+<p>
+This document discusses ebtables version 2.0, later versions might have subtle changes.
+</p>
+
+<p>(C) 2002 Bart De Schuymer. Licenced under the GNU GPL.</p>
+
+<h2><a NAME="ss1.1">1.1</a> <a HREF="ebtables-hacking-HOWTO.html#toc1.1">What is ebtables?</a>
+</h2>
+
+<p>Ebtables is a filter/nat facility for the Linux Ethernet bridge. Its
+implementation and usage is very similar to that of iptables. However,
+ebtables works mostly on the Link Layer, while iptables mostly works on the
+Network Layer.
+<h2><a NAME="ss1.2">1.2</a> <a HREF="netfilter-hacking-HOWTO.html#toc1.2">Why do I need ebtables?</a>
+</h2>
+
+<p>
+Ebtables enables you to get a transparent bridging firewall, it also provides
+the functionality of a brouter and lets you make things like transparent proxys.
+What's cooler than playing around with a firewall? Playing around with a transparent
+firewall (stealth firewall), ofcourse! OK, a really cool stealth firewall would allow
+great stuff like IP NAT; that can be obtained with the bridge-nf stuff, which links
+iptables to the bridging world. For more information about bridge-nf, the br_fw_ia document
+is recommended.
+</p>
+<p>
+Concentrating on ebtables, it enables us, for example, to filter out ugly stuff
+like NetBEUI traffic coming from another side of the bridge into our sweet
+IP-only side. Basically, it gives us complete access to the Ethernet header of all frames
+the bridge can get its hands on, along with some elementary access to the protocols on top
+of Ethernet (like IP and ARP).
+</p>
+
+
+<h2><a NAME="ss1.3">1.3</a> <a HREF="netfilter-hacking-HOWTO.html#toc1.3">Who are you?</a>
+</h2>
+
+<p>I'm just someone who was foolish enough to start reading Rusty's code and, consequently,
+got hooked on kernel hacking. So all blame Rusty!
+</p>
+<hr>
+<a HREF="ebtables-hacking-HOWTO-2.html">Next</a>
+Previous
+<a HREF="ebtables-hacking-HOWTO.html#toc1">Contents</a>
+</body>
+</html>
+
diff --git a/docs/ebtables-hacking/ebtables-hacking-HOWTO-2.html b/docs/ebtables-hacking/ebtables-hacking-HOWTO-2.html
new file mode 100644
index 0000000..5a44731
--- /dev/null
+++ b/docs/ebtables-hacking/ebtables-hacking-HOWTO-2.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Ebtables Hacking HOWTO: Where Can I Get The Latest?</title>
+</head>
+<body>
+<a HREF="ebtables-hacking-HOWTO-3.html">Next</a>
+<a HREF="ebtables-hacking-HOWTO-1.html">Previous</a>
+<a HREF="ebtables-hacking-HOWTO.html#toc2">Contents</a>
+<hr>
+<h2><a NAME="s2">2.</a> <a HREF="netfilter-hacking-HOWTO.html#toc2">Where Can I Get The Latest?</a></h2>
+
+<p>Ebtables has a sourceforge account and uses its CVS services. This CVS contains the latest
+userspace and kernel code along with other documents.
+
+For casual browsing, you can use the
+<a HREF="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/ebtables/">Web Interface</a>. </p>
+<p>To grab the latest sources, you can do the following:
+<ol>
+<li> Log in to the CVS server anonymously, when prompted for a password simply press the ENTER key:
+<blockquote><code>
+<pre>
+cvs -d:pserver:anonymous@cvs.ebtables.sourceforge.net:/cvsroot/ebtables login
+</pre>
+</code></blockquote>
+</li>
+<li> Check out the ebtables repository:
+<blockquote><code>
+<pre>
+cvs -z3 -d:pserver:anonymous@cvs.ebtables.sourceforge.net:/cvsroot/ebtables co ebtables2
+</pre>
+</code></blockquote>
+</li>
+</ol>
+</p>
+
+<hr>
+<a HREF="ebtables-hacking-HOWTO-3.html">Next</a>
+<a HREF="ebtables-hacking-HOWTO-1.html">Previous</a>
+<a HREF="ebtables-hacking-HOWTO.html#toc2">Contents</a>
+</body>
+</html>
+
diff --git a/docs/ebtables-hacking/ebtables-hacking-HOWTO-3.html b/docs/ebtables-hacking/ebtables-hacking-HOWTO-3.html
new file mode 100644
index 0000000..4b53955
--- /dev/null
+++ b/docs/ebtables-hacking/ebtables-hacking-HOWTO-3.html
@@ -0,0 +1,468 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Ebtables Hacking HOWTO: Reference manual</title>
+</head>
+<body>
+<a HREF="ebtables-hacking-HOWTO-4.html">Next</a>
+<a HREF="ebtables-hacking-HOWTO-2.html">Previous</a>
+<a HREF="ebtables-hacking-HOWTO.html#toc3">Contents</a>
+<hr>
+<h2><a NAME="s3">3.</a> <a HREF="netfilter-hacking-HOWTO.html#toc3">Reference manual</a></h2>
+<p>
+This section (claims that it) contains the knowledge necessary to write an extension. For a first time reader
+it's probably less boring to first read the examples section and come back here when necessary.
+</p>
+<h2><a NAME="ss3.1">3.1</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.1">Userspace</a>
+</h2>
+<p>
+The userspace modules are responsible for putting the user's input into the right form to be given to
+the kernel.
+</p>
+<h3><a NAME="ss3.1.1">3.1.1</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.1.1">Matches</a>
+</h3>
+<p>
+A match module is a piece of code that looks at frames passing by and decides whether that frame
+matches certain conditions or not. The userspace match is contained in a
+<CODE>struct ebt_u_match</CODE>, of which the fields important to the match implementor will be
+described now:
+<ol>
+<li><CODE>char name[EBT_FUNCTION_MAXNAMELEN]<CODE>
+<p>The name of the match, for example <CODE>ip</CODE>. Try to keep yourself from using capitals.</p>
+</li>
+<li><CODE>unsigned int size</CODE>
+<p>The size of the match data</p>
+</li>
+<li><CODE>void (*help)(void)</CODE>
+<p>This function should print out the help information for the match, when the user asks for it
+with the <CODE>-h &#60match&#62</CODE> command. The function can expect a '\n' to have been
+printed right before it is executed and should end with at least one '\n'. The output should
+explain the usage of the module, with its look similar to that of the standard help.
+</p>
+</li>
+<li><CODE>void (*init)(struct ebt_entry_match *m)</CODE>
+<p>This function is executed when the ebtables program starts execution, before any user commands
+are processed. Initializing any private data should be done at this time. The data inside the
+match struct can be initialized too, using the function's argument <CODE>m</CODE>.
+</p>
+</li>
+<li><CODE>int (*parse)(int c, char **argv, int argc,<BR>
+ const struct ebt_u_entry *entry, unsigned int *flags,<BR>
+ struct ebt_entry_match **match)<CODE>
+<p>This function parses a user option given on the command line. The function can abort execution
+of the program using ebtables' <CODE>print_error()</CODE> function when appropriate. The return
+value for success is 1, in case of failure it is 0.<br>
+<CODE>c</CODE> contains the option the user used on the command line, <CODE>argv</CODE> and <CODE>argc</CODE>
+are the same two parameters given to the <CODE>main</CODE> function. <CODE>entry</CODE> points to the
+complete new rule that is being constructed. <CODE>flags</CODE> points to an unsigned int private to the
+module that can have any value the module wants. In practice it is used to contain flags for which options
+are already processed. <CODE>match</CODE> points to the data of the match, as you can see it's a double pointer,
+meaning you are allowed to change the address of the match's data.
+</p>
+</li>
+<li><CODE>void (*final_check)(const struct ebt_u_entry *entry,<BR>
+ const struct ebt_entry_match *match,<BR>
+ const char *name, unsigned int hookmask, unsigned int time)</CODE>
+<p>This function is executed after the new rule has been completely parsed without errors. Here you can see
+if there is no invalid use of different options. For example, if the match only works for protocol XyZ, then
+you should check that the user specified <CODE>-p XyZ</CODE>. The <CODE>name</CODE> argument contains the name
+of the table the rule will be put in, <CODE>hookmask</CODE> contains the mask that describes from which base
+chains the rule can be accessed. Because this function can be called twice during the execution of the
+program, the value <CODE>time</CODE> equals 0 for the first execution and 1 for the second. In some situations
+it is necessary to have this knowledge.
+</p>
+</li>
+<li><CODE>void (*print)(const struct ebt_u_entry *entry,<BR>
+ const struct ebt_entry_match *match)</CODE>
+<p>
+This function is executed when the user wants to list the rules and if a rule contains this match. The output should
+be in a format the user could have used to make the rule.
+</p>
+</li>
+<li><CODE>int (*compare)(const struct ebt_entry_match *m1,<BR>
+ const struct ebt_entry_match *m2)</CODE>
+<p>
+This function is executed when 2 rules have to be compared with eachother and both contain this match. A return value
+of 1 means the matches in both rules are the same, otherwise the return value must be 0.
+</p>
+</li>
+<li><CODE>const struct option *extra_ops</CODE>
+<p>
+This points to a <CODE>struct option</CODE>, recognized by the library function <CODE>getopt_long</CODE>. This contains
+the options the user can use for the match module. Options specific to a match should start with a specific prefix, then
+a minus, then the option specifying name. For example, the IP match has an option "ip-source" for matching the IP source address.
+</p>
+</li>
+</ol>
+</p>
+<h3><a NAME="ss3.1.2">3.1.2</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.1.2">Watchers</a>
+</h3>
+<p>
+A watcher module is a piece of code that looks at frames passing by, after they have passed all matches of the rule in which the
+watcher is contained. A watcher only looks at a frame and will probably log something or keep statistics. Watchers are in ebtables
+because it allows to have a watcher and a target in the same rule. Therefore you can log stuff with the log watcher, while still
+being able to give a target. Without watchers, you would need two rules for this, which is slower and ugly.<br><br>
+The userspace watcher is contained in a <CODE>struct ebt_u_watcher</CODE> that has the same relevant fields as the match, so we refer
+to the previous section (mentally replace match by watcher where necessary).
+</p>
+<h3><a NAME="ss3.1.3">3.1.3</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.1.3">Targets</a>
+</h3>
+<p>
+A target module is a piece of code that does a certain action when a all matches of a rule are passed and after the watchers in
+the rule (if any) are executed.<br><br>
+The userspace target is contained in a <CODE>struct ebt_u_target</CODE> that has the same relevant fields as the match, so we refer
+to the first section (mentally replace match by target where necessary).
+</p>
+<h3><a NAME="ss3.1.4">3.1.4</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.1.4">Miscellaneous</a>
+</h3>
+<p>
+This section contains more general information that you could need.
+</p>
+<p>
+<em>Macro's:</em>
+</p>
+<p>
+The following macro's are defined in <CODE>include/ebtables_u.h</CODE>
+<ol>
+<li>
+<CODE>print_bug()</CODE>
+<p>
+The arguments should look like arguments to <CODE>printf</CODE>, use this macro if you want to do sanity checks on your code.
+</p>
+</li>
+<li>
+<CODE>print_error()</CODE>
+<p>
+The arguments should look like arguments to <CODE>printf</CODE>, use this macro to tell the user she did something wrong.
+A trailing '.' is added by the macro.
+</p>
+</li>
+<li>
+<CODE>print_memory()</CODE>
+<p>
+Use this macro when <CODE>malloc</CODE> and friends fail. No arguments allowed.
+</p>
+</li>
+<li>
+<CODE>FILL_TARGET(string, pos)</CODE>
+<p>
+This macro fills the integer <CODE>pos</CODE> with the value representing the target <CODE>string</CODE>. So, if you want <CODE>pos</CODE> to contain the value for RETURN,
+use <CODE>FILL_TARGET("RETURN", pos);</CODE>
+</p>
+</li>
+<li>
+<CODE>TARGET_NAME(value)</CODE>
+<p>
+This macro produces the target string coreesponding to the given target <CODE>value</CODE>. Use this to convert a stored numeric value to a string that can be printed for
+the user to read.
+</p>
+</li>
+<li>
+<CODE>BASE_CHAIN</CODE>
+<p>
+This macro produces a boolean with value true if the rule is in a base chain. This is used for example to prevent a RETURN target on a base chain.
+</p>
+</li>
+<li>
+<CODE>CLEAR_BASE_CHAIN_BIT</CODE>
+<p>
+This macro should be used (only once) before using the <CODE>hookmask</CODE> in the <CODE>final_check()</CODE> function.
+If you want to use <CODE>BASE_CHAIN</CODE> you must use it earlier in the function.
+</p>
+</li>
+</ol>
+</p>
+<p>
+<em>The <CODE>time</CODE> argument to <CODE>final_check()</CODE>:</em>
+</p>
+<p>
+Some extra explanation about the <CODE>time</CODE> argument of the <CODE>final_check()</CODE> function is perhaps needed. When a rule is added, this rule can have as
+target a user defined chain. It can be, for example, that introducing this new rule makes a certain target accessible from a base chain that is not allowed for that target.
+Before this rule was added, this was not so, but after the rule is added this is so. Therefore, after an add or insert, all the <CODE>final_check()</CODE> functions of all
+the modules used in all chains are called, the value of <CODE>time</CODE> will be set to 1. We could ofcourse be lazy and let this checking up to the kernel, but it's the
+policy of ebtables that any rejected table from the kernel is caused by an ebtables userspace bug. Userspace should make sure no invalid data can go to the kernel. This does
+not mean that the kernel no longer has to check for validity, ofcourse.
+</p>
+<p>
+<em>A complete rule:</em>
+</p>
+<p>
+The <CODE>struct ebt_u_entry</CODE> contains the information of a rule. Most module functions that are called by the base ebtables code have this struct as an argument.
+However, I feel there is only one field that can be needed by the userspace module:
+<ol>
+<li><CODE>uint16_t ethproto</CODE>
+<p>
+This contains the Ethernet protocol specified by the user, its value is zero if the user did not specify a specific protocol. The value is in host endian, so there is no need
+for <CODE>ntohs()</CODE>. The <CODE>final_check()</CODE> can need this value to be sure the module is used with the right specified Ethernet protocol.
+</p>
+</li>
+</ol>
+</p>
+<p>
+<em>Adding a new table:</em>
+</p>
+<p>
+A module for a new table can be added too, the table's information is stored in a <CODE>struct ebt_u_table</CODE> and has following relevant members:
+<ol>
+<li><CODE>char name[EBT_TABLE_MAXNAMELEN]</CODE>
+<p>
+The name of the table. Try to keep yourself from using capital letters.
+</p>
+</li>
+<li><CODE>void (*check)(struct ebt_u_replace *repl)</CODE>
+<p>
+This function gets the complete table as an argument and can do all the checks it likes. It should use <CODE>print_error()</CODE> if the table is invalid. However, there
+is probably no need to make this function.
+</p>
+</li>
+<li><CODE>void (*help)(char **)</CODE>
+<p>
+This function gets executed when the user gives the '-h' command, it should at least print out the supported chains for the table. You can assume a '\n' has been printed
+prior to the function's execution, it should also end with at least one '\n'.
+</p>
+</li>
+</ol>
+</p>
+<p>
+<em>Useful functions:</em>
+</p>
+<p>
+Now follows a description of other functions that are useful for a module.
+<ol>
+<li><CODE>void register_table(struct ebt_u_table *)</CODE>
+<p>
+Is needed in the initialization function of a table module, to register the table's data, namely the <CODE>name</CODE> and the <CODE>check</CODE> and <CODE>help</CODE> functions.
+</p>
+</li>
+<li><CODE>void register_match(struct ebt_u_match *)</CODE>
+<p>
+Is needed in the initialization function of a match module, to register its data.
+</p>
+</li>
+<li><CODE>void register_watcher(struct ebt_u_watcher *)</CODE>
+<p>
+Is needed in the initialization function of a watcher module, to register its data.
+</p>
+</li>
+<li><CODE>void register_target(struct ebt_u_target *t)</CODE>
+<p>
+Is needed in the initialization function of a target module, to register its data.
+</p>
+</li>
+<li><CODE>int name_to_number(char *name, uint16_t *proto)</CODE>
+<p>
+Translate a name of an Ethernet protocol to the corresponding protocol number, which is put inside the variable pointed to by <CODE>proto</CODE>. The
+translation is done using /etc/ethertypes. The return value is as follows: 0 = success, 1 = success but the name equals "LENGTH", -1 = no translation possible.
+</p>
+</li>
+<li><CODE>int number_to_name(unsigned short proto, char *name)</CODE>
+<p>
+Translate a protocol number to a protocol name, using /etc/ethertypes. Returns 0 on success and puts the protocol name at the address pointed to
+by <CODE>name</CODE>. This demands the <CODE>name</CODE> buffer to be of size at least 21.
+</p>
+</li>
+<li><CODE>void check_option(unsigned int *flags, unsigned int mask)</CODE>
+<p>
+Checks the boolean <CODE>(*flags & mask)</CODE>. Normally, <CODE>mask</CODE> should be a power of 2 and <CODE>flags</CODE> points to an integer containing
+all the options already processed for the specific module. If the boolean is true then an error message is printed to the screen about double usage
+of the same option and the program exits. If the boolean is false, the bit in <CODE>*flags</CODE> for the specific option is put to 1.
+</p>
+</li>
+<li><CODE>int check_inverse(const char option[])</CODE>
+<p>
+Checks if the string argument equals "!". If it does, <CODE>optind</CODE> is increased and 1 is returned, else 0 is returned. As this function can increase <CODE>optind</CODE>,
+the code that comes behind the call to this function has to use <CODE>argv[optind - 1]</CODE>, not <CODE>optarg</CODE> because <CODE>optarg</CODE> can point to the "!".
+</p>
+</li>
+</ol>
+</p>
+<p>
+<em>The <CODE>hookmask</CODE> argument to <CODE>final_check()</CODE>:</em>
+</p>
+<p>
+The usage of the <CODE>hookmask</CODE> argument for the <CODE>final_check()</CODE> function could use some extra explaining. This mask contains the information from which
+base chain the rule in question (so the module's data in question) can be reached. If your module is only viable for certain base chains, you should check it isn't used
+in an invalid chain. If the rule can be reached through the PREROUTING chain, then the NF_BR_PRE_ROUTING'th least significant bit will be set for <CODE>hookmask</CODE>. Here
+is a list of all constants: NF_BR_PRE_ROUTING = 0, NF_BR_LOCAL_IN = 1, NF_BR_FORWARD = 2, NF_BR_LOCAL_OUT = 3, NF_BR_POST_ROUTING = 4, NF_BR_BROUTING = 5. See the already
+implemented modules for examples.
+</p>
+<h2><a NAME="ss3.2">3.2</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.2">Kernel</a>
+</h2>
+<p>
+The kernel modules are responsible for checking the data received by userspace and its main task is doing whatever the
+data tells the module to do, with a frame.
+</p>
+<h3><a NAME="ss3.2.1">3.2.1</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.2.1">Matches</a>
+</h3>
+<p>
+The kernel match module is contained in a <CODE>struct ebt_match</CODE> of which its relevant fields will be discussed now:
+<ol>
+<li><CODE>struct list_head list</CODE>
+<p>
+Set this to <CODE>{NULL, NULL}</CODE>.
+</p></li>
+<li><CODE>char name[EBT_FUNCTION_MAXNAMELEN]</CODE>
+<p>
+The name of the match, should be the same as the name of the corresponding userspace match.
+</p></li>
+<li><CODE>int (*match)(const struct sk_buff *skb, const struct net_device *in,<BR>
+ const struct net_device *out, const void *matchdata,<BR>
+ unsigned int datalen)</CODE>
+<p>
+Checks if the frame (<CODE>skb</CODE>) matches the data from the match (<CODE>matchdata</CODE>) contained in the rule. If it matches,
+EBT_MATCH (=0) is returned, else EBT_NOMATCH (=1) is returned. This function is executed for every frame that
+comes into contact with a rule utilizing the match in question.
+</p></li>
+<li><CODE>int (*check)(const char *tablename, unsigned int hookmask,<BR>
+ const struct ebt_entry *e, void *matchdata, unsigned int datalen)</CODE>
+<p>
+Checks the data of the match (<CODE>matchdata</CODE>) contained in the rule (<CODE>e</CODE>) to see if it is valid. This function is executed
+when the user gives new table data to the kernel. Returns 0 on success, a negative value (e.g. <CODE>-EINVAL</CODE>) on failure.
+</p></li>
+<li><CODE>void (*destroy)(void *matchdata, unsigned int datalen)</CODE>
+<p>
+Contains the code executed when a rule utilizing the match is removed. Set to <CODE>NULL</CODE> if not used.
+</p></li>
+<li><CODE>struct module *me</CODE>
+<p>
+Always set to <CODE>THIS_MODULE</CODE>.
+</p>
+</li>
+</ol>
+</p>
+<h3><a NAME="ss3.2.2">3.2.2</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.2.2">Watchers</a>
+</h3>
+<p>
+The watchers are contained in a <CODE>struct ebt_watcher</CODE>, its members are basically the same as
+for the <CODE>struct ebt_match</CODE>, except that the <CODE>watcher()</CODE> function
+(the analogue of the <CODE>match()</CODE> function) has no return value.
+</p>
+<h3><a NAME="ss3.2.3">3.2.3</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.2.3">Targets</a>
+</h3>
+<p>
+The targets are contained in a <CODE>struct ebt_target</CODE>, its members are basically the same as
+for the <CODE>struct ebt_match</CODE>, except that it contains a <CODE>target()</CODE> member instead of a <CODE>match()</CODE> member.
+This <CODE>target()</CODE> function gives back a basic decision to the main ebtables
+code. This decision is <CODE>EBT_ACCEPT</CODE>, <CODE>EBT_DROP</CODE>, <CODE>EBT_CONTINUE</CODE> or <CODE>EBT_RETURN</CODE>.
+The <CODE>target()</CODE> function should make sure the decision cannot be <CODE>EBT_RETURN</CODE> for a rule on a base chain.
+</p>
+<h3><a NAME="ss3.2.4">3.2.4</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.2.4">Miscellaneous</a>
+</h3>
+<p>
+<em>Macro's:</em>
+</p>
+<p>
+Some macro's useful to ebtables kernel modules:
+<ol>
+<li><CODE>FWINV(bool,invflg)</CODE>
+<p>
+Used in the <CODE>match()</CODE> functions. The <CODE>bool</CODE> argument contains some boolean expression
+and the <CODE>invflg</CODE> argument has the bit set for a specific option. See the implementation in <CODE>ebtables.h</CODE> and
+the usage in f.e. <CODE>ebt_ip.c</CODE> for more details.
+</p>
+</li>
+<li>
+<CODE>BASE_CHAIN</CODE>
+<p>
+True if the hook mask denotes that the rule is in a base chain,
+used in the <CODE>check()</CODE> functions.
+</p>
+</li>
+<li><CODE>CLEAR_BASE_CHAIN_BIT</CODE>
+<p>
+This macro should be used (only once) before using the <CODE>hookmask</CODE> in the <CODE>check()</CODE> function.
+If you want to use <CODE>BASE_CHAIN</CODE> you must use it earlier in the function.
+See f.e. <CODE>ebt_dnat.c</CODE>.
+</p>
+</li>
+<li><CODE>INVALID_TARGET</CODE>
+<p>
+True if the target (an integer) is not a standard target. See f.e. <CODE>ebt_dnat.c</CODE> for its usage.
+</p>
+</li>
+</ol>
+</p>
+<p>
+<em>Adding a new table:</em>
+</p>
+<p>
+You can also make a new table, see the existing implementations (e.g. <CODE>ebtable_filter.c</CODE>) for details.
+</p>
+<p>
+<em>Useful functions:</em>
+</p>
+<p>
+<ol>
+<li><CODE>int ebt_register_table(struct ebt_table *table)</CODE>
+<p>
+Registers the table with its data contained in the <CODE>struct ebt_table *table</CODE>. Returns a negative value on failure.
+This is used in the initialization function of a table module.
+</p>
+</li>
+<li><CODE>void ebt_unregister_table(struct ebt_table *table)</CODE>
+<p>
+Unregisters the table. This is used in the function that is called when the module is unloaded and also when something goes wrong
+in the initialization function.
+</p>
+</li>
+<li><CODE>int ebt_register_match(struct ebt_match *match)</CODE>
+<p>
+Registers the match with its data contained in the <CODE>struct ebt_match *match</CODE>. Returns a negative value on failure.
+This is used in the initialization function of a match module.
+</p>
+</li>
+<li><CODE>void ebt_unregister_match(struct ebt_match *match)</CODE>
+<p>
+Unregisters the match. This is used in the function that is called when the module is unloaded and also when something goes wrong
+in the initialization function.
+</p>
+</li>
+<li><CODE>int ebt_register_watcher(struct ebt_watcher *watcher)</CODE>
+<p>
+Registers the watcher with its data contained in the <CODE>struct ebt_watcher *watcher</CODE>. Returns a negative value on failure.
+This is used in the initialization function of a watcher module.
+</p>
+</li>
+<li><CODE>void ebt_unregister_watcher(struct ebt_watcher *watcher)</CODE>
+<p>
+Unregisters the watcher. This is used in the function that is called when the module is unloaded and also when something goes wrong
+in the initialization function.
+</p>
+</li>
+<li><CODE>int ebt_register_target(struct ebt_target *target)</CODE>
+<p>
+Registers the target with its data contained in the <CODE>struct ebt_target *target</CODE>. Returns a negative value on failure.
+This is used in the initialization function of a target module.
+</p>
+</li>
+<li><CODE>void ebt_unregister_target(struct ebt_target *target)</CODE>
+<p>
+Unregisters the target. This is used in the function that is called when the module is unloaded and also when something goes wrong
+in the initialization function.
+</p>
+</li>
+</ol>
+</p>
+<h2><a NAME="ss3.3">3.3</a> <a HREF="ebtables-hacking-HOWTO.html#toc3.3">General rules</a>
+</h2>
+<p>
+<ol>
+<li>
+Indentation should be done using tabs.
+</li>
+<li>
+No more than 80 columns should be used, taking into account tab width of 8 characters.
+</li>
+<li>
+Bad or corrupt data should never be accepted by the kernel module's <CODE>check()</CODE> function. The userspace module should be
+built so that no bad or corrupt data can ever be given to the kernel. If the kernel does not accept data given to it, this is considered
+a userspace bug.
+</li>
+</ol>
+</p>
+<hr>
+<a HREF="ebtables-hacking-HOWTO-4.html">Next</a>
+<a HREF="ebtables-hacking-HOWTO-2.html">Previous</a>
+<a HREF="ebtables-hacking-HOWTO.html#toc3">Contents</a>
+</body>
+</html>
diff --git a/docs/ebtables-hacking/ebtables-hacking-HOWTO-4.html b/docs/ebtables-hacking/ebtables-hacking-HOWTO-4.html
new file mode 100644
index 0000000..0de5b85
--- /dev/null
+++ b/docs/ebtables-hacking/ebtables-hacking-HOWTO-4.html
@@ -0,0 +1,597 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Ebtables Hacking HOWTO: Examples</title>
+</head>
+<body>
+<a HREF="ebtables-hacking-HOWTO-5.html">Next</a>
+<a HREF="ebtables-hacking-HOWTO-3.html">Previous</a>
+<a HREF="ebtables-hacking-HOWTO.html#toc4">Contents</a>
+<hr>
+<h2><a NAME="s4">4.</a> <a HREF="netfilter-hacking-HOWTO.html#toc4">Example</a></h2>
+<p>
+This section contains annotated example source code. This is just to give some clues, see the full code of the already implemented ebtables modules
+for more clues.
+</p>
+<h2><a NAME="ss4.1">4.1</a> <a HREF="ebtables-hacking-HOWTO.html#toc4.1">Userspace</a>
+<p>
+<em><h3>The userspace ip match module</h3></em>
+</p>
+<p>
+What follows is annotated code of pieces of the <CODE>ebt_ip.c</CODE> code. For brevity, only the <CODE>--ip-source</CODE> option is considered.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+#include &lt;stdio.h&gt;
+#include &lt;getopt.h&gt;
+#include "../include/ebtables_u.h"
+#include &lt;linux/netfilter_bridge/ebt_ip.h&gt;
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+At least these includes are needed: respectively for <CODE>printf()</CODE>, for the parsing of the options, for all the
+general ebtables userspace definitions and for the ebtables ip module specific header.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+#define IP_SOURCE '1'
+#define IP_DEST '2'
+
+static struct option opts[] =
+{
+ { "ip-source" , required_argument, 0, IP_SOURCE },
+ { "ip-src" , required_argument, 0, IP_SOURCE },
+ { 0 }
+};
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Defining the new command line options. This is a struct that the library function <CODE>getopt_long()</CODE>
+understands. The first field specifies the full length option name, the second field specifies if an argument is required
+or not, the third field should be zero and the last field specifies the value returned by <CODE>getopt_long()</CODE> when
+it encounters this option.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static void print_help()
+{
+ printf(
+"ip options:\n"
+"--ip-src [!] address[/mask]: ip source specification\n"
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Short and descriptive help.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static void init(struct ebt_entry_match *match)
+{
+ struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
+
+ ipinfo->invflags = 0;
+ ipinfo->bitmask = 0;
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Initialize the module specific data. In the example, some fields in the struct specific to the ip match module are given an initial value.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+#define OPT_SOURCE 0x01
+static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ unsigned int *flags, struct ebt_entry_match **match)
+{
+ struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)(*match)->data;
+ char *end;
+ long int i;
+
+ switch (c) {
+ case IP_SOURCE:
+ check_option(flags, OPT_SOURCE);
+ ipinfo->bitmask |= EBT_IP_SOURCE;
+
+ if (check_inverse(optarg))
+ ipinfo->invflags |= EBT_IP_SOURCE;
+
+ if (optind > argc)
+ print_error("Missing IP address argument");
+ parse_ip_address(argv[optind - 1], &ipinfo->saddr, &ipinfo->smsk);
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+This function parses the option, filling in the match specific struct or exiting on input errors. <CODE>check_option()</CODE> makes sure the option isn't
+specified twice on the command line. <CODE>check_inverse()</CODE> checks if the argument equals '!'. <CODE>optind &gt; argc</CODE> is possible if the command
+line input ends with '--ip-source !'.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static void final_check(const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match, const char *name,
+ unsigned int hookmask, unsigned int time)
+{
+ if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO)
+ print_error("For IP filtering the protocol must be "
+ "specified as IPv4");
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+This function is executed for a rule that uses the (ip) module. When there is an error, it exits using <CODE>print_error()</CODE>.
+<CODE>entry->ethproto</CODE> contains the protocol specified by the user. If the protocol wasn't specified, this field will equal zero. The specified protocol is
+in host endian form, so there is no need for <CODE>ntohs()</CODE>.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static void print(const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match)
+{
+ struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
+ int j;
+
+ if (ipinfo->bitmask & EBT_IP_SOURCE) {
+ printf("--ip-src ");
+ if (ipinfo->invflags & EBT_IP_SOURCE)
+ printf("! ");
+ for (j = 0; j < 4; j++)
+ printf("%d%s",((unsigned char *)&ipinfo->saddr)[j],
+ (j == 3) ? "" : ".");
+ printf("%s ", mask_to_dotted(ipinfo->smsk));
+ }
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Print out the data contained in the match in a form that the user could have used on the command line. End with at least one space.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static int compare(const struct ebt_entry_match *m1,
+ const struct ebt_entry_match *m2)
+{
+ struct ebt_ip_info *ipinfo1 = (struct ebt_ip_info *)m1->data;
+ struct ebt_ip_info *ipinfo2 = (struct ebt_ip_info *)m2->data;
+
+ if (ipinfo1->bitmask != ipinfo2->bitmask)
+ return 0;
+ if (ipinfo1->invflags != ipinfo2->invflags)
+ return 0;
+ if (ipinfo1->bitmask & EBT_IP_SOURCE) {
+ if (ipinfo1->saddr != ipinfo2->saddr)
+ return 0;
+ if (ipinfo1->smsk != ipinfo2->smsk)
+ return 0;
+ }
+ return 1;
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Compares the data of two "instances" of the match module, returning 1 if the data is equivalent, else 0.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static struct ebt_u_match ip_match =
+{
+ EBT_IP_MATCH,
+ sizeof(struct ebt_ip_info),
+ print_help,
+ init,
+ parse,
+ final_check,
+ print,
+ compare,
+ opts
+};
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+The struct used to register the match to the core ebtables userspace code.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static void _init(void) __attribute((constructor));
+static void _init(void)
+{
+ register_match(&ip_match);
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+The init function registers the match. Initializing its own data should be done with the <CODE>init()</CODE> function defined int the above struct.
+</p>
+<p>
+<em><h3>The (userspace) dnat <CODE>final_check()</CODE> function</h3></em>
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static void final_check_d(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target, const char *name,
+ unsigned int hookmask, unsigned int time)
+{
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
+
+ if (BASE_CHAIN && natinfo->target == EBT_RETURN)
+ print_error("--dnat-target RETURN not allowed on base chain");
+ CLEAR_BASE_CHAIN_BIT;
+ if (((hookmask & ~((1 &lt;&lt; NF_BR_PRE_ROUTING) | (1 &lt;&lt; NF_BR_LOCAL_OUT)))
+ || strcmp(name, "nat")) &&
+ ((hookmask & ~(1 &lt;&lt; NF_BR_BROUTING)) || strcmp(name, "broute")))
+ print_error("Wrong chain for dnat");
+ if (time == 0 && to_dest_supplied == 0)
+ print_error("No dnat address supplied");
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+The target returned by the dnat kernel module (see the man page) is contained in the <CODE>target</CODE> field of the module's specific struct
+(<CODE>struct ebt_nat_info</CODE>). First we check that this target isn't RETURN on one of the standard (base) chains. Then we make
+<CODE>hookmask</CODE> ready for direct use by using the <CODE>CLEAR_BASE_CHAIN_BIT</CODE> macro. Next is checked if the rule containing this
+"module instance" is accessible through illegal chains or tables.
+Finally, the argument <CODE>time</CODE> is checked. If it equals zero, the function checks to be sure a destination IP address was specified.
+<CODE>to_dest_supplied</CODE> is a static variable of this ebtables userspace module, initialized to zero by its initialization function.
+</p>
+</h2>
+<h2><a NAME="ss4.2">4.2</a> <a HREF="ebtables-hacking-HOWTO.html#toc4.2">Kernel</a>
+</h2>
+<p>
+<em><h3>The ebtables kernel ip match module</h3></em>
+</p>
+<p>
+What follows is annotated code of pieces of the <CODE>ebt_ip.c</CODE> code. For brevity, only the IP source address filtering is considered.
+As the interface towards the main ebtables code is easy, there is really not much to be said here.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+#include &lt;linux/netfilter_bridge/ebtables.h&gt;
+#include &lt;linux/netfilter_bridge/ebt_ip.h&gt;
+#include &lt;linux/ip.h&gt;
+#include &lt;linux/module.h&gt;
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+We need general ebtables definitions, the ip kernel match module's specific data, the definition of the IP header and some module definitions.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
+ const struct net_device *out, const void *data,
+ unsigned int datalen)
+{
+ struct ebt_ip_info *info = (struct ebt_ip_info *)data;
+
+ if (info->bitmask & EBT_IP_SOURCE &&
+ FWINV((((*skb).nh.iph)->saddr & info->smsk) !=
+ info->saddr, EBT_IP_SOURCE))
+ return EBT_NOMATCH;
+ return EBT_MATCH;
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+This is the filtering function of the ip match module, it is executed for every frame that comes into contact with an ebtables rule that uses the ip match. All it does
+is tell the ebtables main code if the frame matches or not.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static int ebt_ip_check(const char *tablename, unsigned int hookmask,
+ const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+ struct ebt_ip_info *info = (struct ebt_ip_info *)data;
+
+ if (datalen != sizeof(struct ebt_ip_info))
+ return -EINVAL;
+ if (e->ethproto != __constant_htons(ETH_P_IP) ||
+ e->invflags & EBT_IPROTO)
+ return -EINVAL;
+ if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
+ return -EINVAL;
+ return 0;
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+This function is executed for every rule that uses the ip match, when the kernel receives new table data. It needs to make sure no corrupt ip match data is accepted.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static struct ebt_match filter_ip =
+{
+ {NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL,
+ THIS_MODULE
+};
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+The struct we'll give to the main ebtables code to register the match.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static int __init init(void)
+{
+ return ebt_register_match(&filter_ip);
+}
+
+static void __exit fini(void)
+{
+ ebt_unregister_match(&filter_ip);
+}
+
+module_init(init);
+module_exit(fini);
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Functions executed at loading or removing of the ip match module.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+MODULE_LICENSE("GPL");
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Ofcourse your module is released under the GPL.
+</p>
+<p>
+<em><h3>The ebtables kernel filter table</h3></em>
+</p>
+<p>
+This part contains pieces of the <CODE>ebtable_filter.c</CODE> code with annotation.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+#define FILTER_VALID_HOOKS ((1 &lt;&lt; NF_BR_LOCAL_IN) | (1 &lt;&lt; NF_BR_FORWARD) | \
+ (1 &lt;&lt; NF_BR_LOCAL_OUT))
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+The valid netfilter hooks for the ebtables filter table are the bridge <CODE>LOCAL_IN</CODE> <CODE>FORWARD</CODE> and <CODE>LOCAL_OUT</CODE> hooks.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static struct ebt_entries initial_chains[] =
+{
+ {0, "INPUT", 0, EBT_ACCEPT, 0},
+ {0, "FORWARD", 0, EBT_ACCEPT, 0},
+ {0, "OUTPUT", 0, EBT_ACCEPT, 0}
+};
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+The filter table consists of three chains, initially containing zero rules and having policy <CODE>ACCEPT</CODE>.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static struct ebt_replace initial_table =
+{
+ "filter", FILTER_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries),
+ { [NF_BR_LOCAL_IN]&initial_chains[0], [NF_BR_FORWARD]&initial_chains[1],
+ [NF_BR_LOCAL_OUT]&initial_chains[2] }, 0, NULL, (char *)initial_chains
+};
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+This contains all the info about the table.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
+{
+ if (valid_hooks & ~FILTER_VALID_HOOKS)
+ return -EINVAL;
+ return 0;
+}
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+This function is executed when new table data is given to the kernel. We just check
+the valid hooks according to userspace are the same as those according to the kernel module.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static struct ebt_table frame_filter =
+{
+ {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS,
+ RW_LOCK_UNLOCKED, check, NULL
+};
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+The ebtables main code likes to use this struct.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static unsigned int
+ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in,
+ const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+ return ebt_do_table(hook, pskb, in, out, &frame_filter);
+}
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+This function is executed for every frame that passes a netfilter hook on which this function is registered.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static struct nf_hook_ops ebt_ops_filter[] = {
+ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_IN,
+ NF_BR_PRI_FILTER_BRIDGED},
+ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_FORWARD,
+ NF_BR_PRI_FILTER_BRIDGED},
+ { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_OUT,
+ NF_BR_PRI_FILTER_OTHER}
+};
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Here we say the function <CODE>ebt_hook()</CODE> is registered onto the three mentioned netfilter hooks, with a certain priority (e.g. NF_BR_PRI_FILTER_BRIDGED).
+If multiple functions are registered on the same hook, the priority of the functions determines the order in which they are executed. The lower the priority value,
+the earlier the function will get executed.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static int __init init(void)
+{
+ int i, j, ret;
+
+ ret = ebt_register_table(&frame_filter);
+ if (ret &lt; 0)
+ return ret;
+ for (i = 0; i &lt; sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
+ if ((ret = nf_register_hook(&ebt_ops_filter[i])) &lt; 0)
+ goto cleanup;
+ return ret;
+cleanup:
+ for (j = 0; j &lt; i; j++)
+ nf_unregister_hook(&ebt_ops_filter[j]);
+ ebt_unregister_table(&frame_filter);
+ return ret;
+}
+
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+register the table to the main ebtables code; register <CODE>ebt_hook()</CODE> on the appropriate netfilter hooks.
+</p>
+<p>
+<table BGCOLOR="#E0E0E0" WIDTH="100%">
+<tr><td>
+<PRE>
+static void __exit fini(void)
+{
+ int i;
+
+ for (i = 0; i &lt; sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
+ nf_unregister_hook(&ebt_ops_filter[i]);
+ ebt_unregister_table(&frame_filter);
+}
+</PRE>
+</td></tr>
+</table>
+</p>
+<p>
+Unregister from the netfilter hooks and ebtables.
+</p>
+<hr>
+Next
+<a HREF="ebtables-hacking-HOWTO-3.html">Previous</a>
+<a HREF="ebtables-hacking-HOWTO.html#toc4">Contents</a>
+</body>
+</html>
diff --git a/docs/ebtables-hacking/ebtables-hacking-HOWTO.html b/docs/ebtables-hacking/ebtables-hacking-HOWTO.html
new file mode 100644
index 0000000..37d0ea3
--- /dev/null
+++ b/docs/ebtables-hacking/ebtables-hacking-HOWTO.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<title>Ebtables Hacking HOWTO</title>
+
+</head>
+<body>
+<a HREF="ebtables-hacking-HOWTO-1.html">Next</a>
+Previous
+Contents
+<hr>
+<h1>Ebtables Hacking HOWTO</h1>
+
+<h2>Bart De Schuymer,<BR>mailing lists <code>ebtables-user@lists.sourceforge.net</code> and <code>ebtables-user@lists.sourceforge.net</code></h2>
+Last updated: 6 September 2002
+<hr>
+<em>This document describes the ebtables v2.0x architecture for Linux and how to
+implement new modules on top of it.</em>
+<hr>
+<p>
+<h2><a NAME="toc1">1.</a> <a HREF="ebtables-hacking-HOWTO-1.html">Introduction</a></h2>
+
+<ul>
+<li><a NAME="toc1.1">1.1</a> <a HREF="ebtables-hacking-HOWTO-1.html#ss1.1">What is ebtables?</a>
+<li><a NAME="toc1.2">1.2</a> <a HREF="ebtables-hacking-HOWTO-1.html#ss1.2">Why do I need ebtables?</a>
+<li><a NAME="toc1.3">1.3</a> <a HREF="ebtables-hacking-HOWTO-1.html#ss1.3">Who are you?</a>
+</ul>
+<p>
+<h2><a NAME="toc2">2.</a> <a HREF="ebtables-hacking-HOWTO-2.html">Where Can I Get The Latest?</a></h2>
+
+<p>
+<h2><a NAME="toc3">3.</a> <a HREF="ebtables-hacking-HOWTO-3.html">Reference manual</a></h2>
+
+<ul>
+<li><a NAME="toc3.1">3.1</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.1">Userspace</a>
+<ul>
+<li><a NAME="toc3.1.1">3.1.1</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.1.1">Matches</a>
+<li><a NAME="toc3.1.2">3.1.2</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.1.2">Watchers</a>
+<li><a NAME="toc3.1.3">3.1.3</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.1.3">Targets</a>
+<li><a NAME="toc3.1.4">3.1.4</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.1.4">Miscellaneous</a>
+</ul>
+<li><a NAME="toc3.2">3.2</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.2">Kernel</a>
+<ul>
+<li><a NAME="toc3.2.1">3.2.1</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.2.1">Matches</a>
+<li><a NAME="toc3.2.2">3.2.2</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.2.2">Watchers</a>
+<li><a NAME="toc3.2.3">3.2.3</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.2.3">Targets</a>
+<li><a NAME="toc3.2.4">3.2.4</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.2.4">Miscellaneous</a>
+</ul>
+<li><a NAME="toc3.3">3.3</a> <a HREF="ebtables-hacking-HOWTO-3.html#ss3.3">General rules</a>
+
+</ul>
+<p>
+<h2><a NAME="toc4">4.</a> <a HREF="ebtables-hacking-HOWTO-4.html">Examples</a></h2>
+
+<ul>
+<li><a NAME="toc4.1">4.1</a> <a HREF="ebtables-hacking-HOWTO-4.html#ss4.1">Userspace</a>
+<li><a NAME="toc4.2">4.2</a> <a HREF="ebtables-hacking-HOWTO-4.html#ss4.2">Kernel</a>
+</ul>
+</p>
+<hr>
+<a HREF="netfilter-hacking-HOWTO-1.html">Next</a>
+Previous
+Contents
+</body>
+</html
+