summaryrefslogtreecommitdiffstats
path: root/userspace
diff options
context:
space:
mode:
authorBart De Schuymer <bdschuym@pandora.be>2002-06-01 19:23:47 +0000
committerBart De Schuymer <bdschuym@pandora.be>2002-06-01 19:23:47 +0000
commitd891e9e5bc309d5aeb2ab774c76b34a92085b3e7 (patch)
tree94b68fc1c01f90cad62a171c27007ff317031008 /userspace
Initial revision
Diffstat (limited to 'userspace')
-rw-r--r--userspace/ebtables2/COPYING339
-rw-r--r--userspace/ebtables2/ChangeLog51
-rw-r--r--userspace/ebtables2/INSTALL27
-rw-r--r--userspace/ebtables2/Makefile58
-rw-r--r--userspace/ebtables2/THANKS9
-rw-r--r--userspace/ebtables2/communication.c454
-rw-r--r--userspace/ebtables2/ebtables.8434
-rw-r--r--userspace/ebtables2/ebtables.c1655
-rw-r--r--userspace/ebtables2/ethertypes34
-rw-r--r--userspace/ebtables2/extensions/Makefile12
-rw-r--r--userspace/ebtables2/extensions/ebt_arp.c289
-rw-r--r--userspace/ebtables2/extensions/ebt_ip.c318
-rw-r--r--userspace/ebtables2/extensions/ebt_log.c197
-rw-r--r--userspace/ebtables2/extensions/ebt_nat.c222
-rw-r--r--userspace/ebtables2/extensions/ebt_redirect.c109
-rw-r--r--userspace/ebtables2/extensions/ebt_standard.c70
-rw-r--r--userspace/ebtables2/extensions/ebt_vlan.c231
-rw-r--r--userspace/ebtables2/extensions/ebtable_broute.c25
-rw-r--r--userspace/ebtables2/extensions/ebtable_filter.c32
-rw-r--r--userspace/ebtables2/extensions/ebtable_nat.c32
-rw-r--r--userspace/ebtables2/include/ebtables_u.h206
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre2.001.diff121
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre2.002.diff2204
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre2.003.diff40
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre2.004.diff50
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre3.001.diff245
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre3.002.diff194
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre3.003.diff66
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre3.004.diff483
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre4.001.diff522
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre5.001.diff50
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre5.002.diff61
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre6.001.diff314
-rw-r--r--userspace/patches/zipped/ebtables-v2.0pre1.tar.gzbin0 -> 32529 bytes
-rw-r--r--userspace/patches/zipped/ebtables-v2.0pre2.tar.gzbin0 -> 49417 bytes
-rw-r--r--userspace/patches/zipped/ebtables-v2.0pre3.tar.gzbin0 -> 51235 bytes
-rw-r--r--userspace/patches/zipped/ebtables-v2.0pre4.tar.gzbin0 -> 52135 bytes
-rw-r--r--userspace/patches/zipped/ebtables-v2.0pre5.tar.gzbin0 -> 35558 bytes
-rw-r--r--userspace/patches/zipped/ebtables-v2.0pre6.tar.gzbin0 -> 36908 bytes
39 files changed, 9154 insertions, 0 deletions
diff --git a/userspace/ebtables2/COPYING b/userspace/ebtables2/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/userspace/ebtables2/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/userspace/ebtables2/ChangeLog b/userspace/ebtables2/ChangeLog
new file mode 100644
index 0000000..3a58b07
--- /dev/null
+++ b/userspace/ebtables2/ChangeLog
@@ -0,0 +1,51 @@
+20020520
+ * update help for -s and -d
+ * add VLAN in ethertypes
+ * add SYMLINK option for compiling
+20020501
+ * allow -i and --logical-in in BROUTING
+ * update the manual page
+ * rename /etc/etherproto into /etc/ethertypes (seems to be a more
+ standard name)
+ * add MAC mask for -s and -d, also added Unicast, Multicast and
+ Broadcast specification for specifying a (family of) MAC
+ addresses.
+20020427
+ * added broute table.
+ * added redirect target.
+ * added --redirect-target, --snat-target and --dnat-target options.
+ * added logical_out and logical_in
+ * snat bugfix (->size)
+20020414
+ * fixed some things in the manual.
+ * fixed -P problem.
+20020411
+ * -j standard no longer works, is this cryptic? good :)
+ * lots of beautification.
+ - made some code smaller
+ - made everything fit within 80 columns
+ * fix problems with -i and -o option
+ * print_memory now prints useful info
+ * trying to see the tables when ebtables is not loaded in kernel
+ no longer makes this be seen as a bug.
+20020403
+ ebtables v2.0 released, changes:
+ * A complete rewrite, made everything modular.
+ * Fixed a one year old bug in br_db.c. A similar bug was present
+ in ebtables.c. It was visible when the number of rules got
+ bigger (around 90).
+ * Removed the option to allow/disallow counters. Frames passing
+ by are always counted now.
+ * Didn't really add any new functionality. However, it will be
+ _alot_ easier and prettier to do so now. Feel free to add an
+ extension yourself.
+ * There are 4 types of extensions:
+ - Tables.
+ - Matches: like iptables has.
+ - Watchers: these only watch frames that passed all the matches
+ of the rule. They don't change the frame, nor give a verdict.
+ The log extension is a watcher.
+ - Targets.
+ * user32/kernel64 architectures like the Sparc64 are unsupported.
+ If you want me to change this, give me access to such a box,
+ and don't pressure me.
diff --git a/userspace/ebtables2/INSTALL b/userspace/ebtables2/INSTALL
new file mode 100644
index 0000000..dc17499
--- /dev/null
+++ b/userspace/ebtables2/INSTALL
@@ -0,0 +1,27 @@
+FOLLOW THESE SIMPLE GUIDELINES:
+-------------------------------
+
+If /usr/src/linux contains the patched kernel for ebtables:
+ %make install
+Otherwise:
+ %make KERNEL_DIR=<<where-the-patched-kernel-is>> install
+
+optional:
+If your /usr/include/linux directory is a symbolic link, use the SYMLINK=y
+option. When unsure, don't use this. If the cp program produces errors
+when executing make install, use this option.
+
+WHAT GETS INSTALLED?
+--------------------
+
+- The needed kernel headers are placed in /usr/include/linux/netfilter_bridge/
+ That's why it needs the KERNEL_DIR. If the SYMLINK=y option is supplied,
+ /usr/include/linux will be a symbolic link.
+- The ebtables manual gets installed in /usr/local/man/man8
+ To put the manual somewhere else, include MANDIR=<<man-path/man>> as
+ option on the command line.
+ The Makefile will append /man8/ebtables.8.
+- ethertypes is placed in /etc/
+- the userspace program ebtables is compiled.
+
+That's all
diff --git a/userspace/ebtables2/Makefile b/userspace/ebtables2/Makefile
new file mode 100644
index 0000000..c16801e
--- /dev/null
+++ b/userspace/ebtables2/Makefile
@@ -0,0 +1,58 @@
+# ebtables Makefile
+
+KERNEL_DIR?=/usr/src/linux
+PROGNAME:=ebtables
+PROGVERSION:="2.0pre6 (May 2002)"
+
+MANDIR?=/usr/local/man
+CFLAGS:=-Wall -Wunused
+include extensions/Makefile
+
+# Some kernel testers prefer to use a symlink for /usr/include/linux
+ifeq ($(SYMLINK), y)
+KERNEL_INCLUDES=symlink
+else
+KERNEL_INCLUDES=headers
+endif
+
+all: ebtables
+
+.PHONY: headers
+headers:
+ mkdir -p /usr/include/linux/netfilter_bridge
+ cp -f $(KERNEL_DIR)/include/linux/netfilter_bridge/* \
+ /usr/include/linux/netfilter_bridge/
+ cp -f $(KERNEL_DIR)/include/linux/br_db.h \
+ /usr/include/linux/br_db.h
+ cp -f $(KERNEL_DIR)/include/linux/netfilter_bridge.h \
+ /usr/include/linux/netfilter_bridge.h
+
+.PHONY: symlink
+symlink:
+ ln -fs $(KERNEL_DIR)/include/linux /usr/include/linux
+
+communication.o: communication.c include/ebtables_u.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ebtables.o: ebtables.c include/ebtables_u.h
+ $(CC) $(CFLAGS) -DPROGVERSION=\"$(PROGVERSION)\" \
+ -DPROGNAME=\"$(PROGNAME)\" -c -o $@ $<
+
+ebtables: ebtables.o communication.o $(EXT_OBJS)
+ $(CC) $(CFLAGS) -o $@ $^
+
+$(MANDIR)/man8/ebtables.8: ebtables.8
+ mkdir -p $(@D)
+ install -m 0644 -o root -g root $< $@
+
+/etc/ethertypes: ethertypes
+ mkdir -p $(@D)
+ install -m 0644 -o root -g root $< $@
+
+install: $(MANDIR)/man8/ebtables.8 $(KERNEL_INCLUDES) \
+ ebtables /etc/ethertypes
+
+clean:
+ -rm -f ebtables
+ rm -f *.o *.c~
+ rm -f extensions/*.o extensions/*.c~
diff --git a/userspace/ebtables2/THANKS b/userspace/ebtables2/THANKS
new file mode 100644
index 0000000..830ad5d
--- /dev/null
+++ b/userspace/ebtables2/THANKS
@@ -0,0 +1,9 @@
+Thanks go out to:
+
+Lennert Buytenhek
+Rusty Russel
+Harald Welte
+Jason Lunz
+Tim Gardner
+Loïc Minier
+Nick Fedchik
diff --git a/userspace/ebtables2/communication.c b/userspace/ebtables2/communication.c
new file mode 100644
index 0000000..02aff3f
--- /dev/null
+++ b/userspace/ebtables2/communication.c
@@ -0,0 +1,454 @@
+/*
+ * communication.c, v2.0 April 2002
+ *
+ * Author: Bart De Schuymer
+ *
+ */
+
+// All the userspace/kernel communication is in this file.
+// The other code should not have to know anything about the way the
+// kernel likes the structure of the table data.
+// The other code works with linked lists, lots of linked lists.
+// So, the translation is done here.
+
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/br_db.h> // the database
+#include <netinet/in.h> // IPPROTO_IP
+#include <asm/types.h>
+#include "include/ebtables_u.h"
+
+extern char* hooknames[NF_BR_NUMHOOKS];
+
+int sockfd = -1;
+
+void get_sockfd()
+{
+ if (sockfd == -1) {
+ sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
+ if (sockfd < 0)
+ print_error("Problem getting a socket");
+ }
+}
+
+static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
+{
+ struct ebt_replace *new;
+ struct ebt_u_entry *e;
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+ char *p, *base;
+ int i, j;
+ unsigned int entries_size = 0;
+
+ new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
+ if (!new)
+ print_memory();
+ new->valid_hooks = u_repl->valid_hooks;
+ memcpy(new->name, u_repl->name, sizeof(new->name));
+ new->nentries = u_repl->nentries;
+ new->num_counters = u_repl->num_counters;
+ new->counters = u_repl->counters;
+ memcpy(new->counter_entry, u_repl->counter_entry,
+ sizeof(new->counter_entry));
+ // determine size
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+ if (!(new->valid_hooks & (1 << i)))
+ continue;
+ entries_size += sizeof(struct ebt_entries);
+ j = 0;
+ e = u_repl->hook_entry[i]->entries;
+ while (e) {
+ j++;
+ entries_size += sizeof(struct ebt_entry);
+ m_l = e->m_list;
+ while (m_l) {
+ entries_size += m_l->m->match_size +
+ sizeof(struct ebt_entry_match);
+ m_l = m_l->next;
+ }
+ w_l = e->w_list;
+ while (w_l) {
+ entries_size += w_l->w->watcher_size +
+ sizeof(struct ebt_entry_watcher);
+ w_l = w_l->next;
+ }
+ entries_size += e->t->target_size +
+ sizeof(struct ebt_entry_target);
+ e = e->next;
+ }
+ // a little sanity check
+ if (j != u_repl->hook_entry[i]->nentries)
+ print_bug("Wrong nentries: %d != %d, hook = %s", j,
+ u_repl->hook_entry[i]->nentries, hooknames[i]);
+ }
+
+ new->entries_size = entries_size;
+ new->entries = (char *)malloc(entries_size);
+ if (!new->entries)
+ print_memory();
+
+ // put everything in one block
+ p = new->entries;
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+ struct ebt_entries *hlp;
+
+ if (!(new->valid_hooks & (1 << i)))
+ continue;
+ hlp = (struct ebt_entries *)p;
+ new->hook_entry[i] = hlp;
+ hlp->nentries = u_repl->hook_entry[i]->nentries;
+ hlp->policy = u_repl->hook_entry[i]->policy;
+ hlp->distinguisher = 0; // make the kernel see the light
+ p += sizeof(struct ebt_entries);
+ e = u_repl->hook_entry[i]->entries;
+ while (e) {
+ struct ebt_entry *tmp = (struct ebt_entry *)p;
+
+ tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
+ tmp->invflags = e->invflags;
+ tmp->ethproto = e->ethproto;
+ memcpy(tmp->in, e->in, sizeof(tmp->in));
+ memcpy(tmp->out, e->out, sizeof(tmp->out));
+ memcpy(tmp->logical_in, e->logical_in,
+ sizeof(tmp->logical_in));
+ memcpy(tmp->logical_out, e->logical_out,
+ sizeof(tmp->logical_out));
+ memcpy(tmp->sourcemac, e->sourcemac,
+ sizeof(tmp->sourcemac));
+ memcpy(tmp->sourcemsk, e->sourcemsk,
+ sizeof(tmp->sourcemsk));
+ memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
+ memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
+
+ base = p;
+ p += sizeof(struct ebt_entry);
+ m_l = e->m_list;
+ while (m_l) {
+ memcpy(p, m_l->m, m_l->m->match_size +
+ sizeof(struct ebt_entry_match));
+ p += m_l->m->match_size +
+ sizeof(struct ebt_entry_match);
+ m_l = m_l->next;
+ }
+ tmp->watchers_offset = p - base;
+ w_l = e->w_list;
+ while (w_l) {
+ memcpy(p, w_l->w, w_l->w->watcher_size +
+ sizeof(struct ebt_entry_watcher));
+ p += w_l->w->watcher_size +
+ sizeof(struct ebt_entry_watcher);
+ w_l = w_l->next;
+ }
+ tmp->target_offset = p - base;
+ memcpy(p, e->t, e->t->target_size +
+ sizeof(struct ebt_entry_target));
+ p += e->t->target_size +
+ sizeof(struct ebt_entry_target);
+ tmp->next_offset = p - base;
+ e = e->next;
+ }
+ }
+
+ // sanity check
+ if (p - new->entries != new->entries_size)
+ print_bug("Entries_size bug");
+ return new;
+}
+
+void deliver_table(struct ebt_u_replace *u_repl)
+{
+ socklen_t optlen;
+ struct ebt_replace *repl;
+
+ // translate the struct ebt_u_replace to a struct ebt_replace
+ repl = translate_user2kernel(u_repl);
+ get_sockfd();
+ // give the data to the kernel
+ optlen = sizeof(struct ebt_replace) + repl->entries_size;
+ if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
+ print_error("Couldn't update kernel chains, you probably need "
+ "to insmod an extension");
+}
+
+// gets executed after deliver_table
+void
+deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
+{
+ unsigned short *point;
+ struct ebt_counter *old, *new, *newcounters;
+ socklen_t optlen;
+ struct ebt_replace repl;
+
+ if (u_repl->nentries == 0)
+ return;
+
+ newcounters = (struct ebt_counter *)
+ malloc(u_repl->nentries * sizeof(struct ebt_counter));
+ if (!newcounters)
+ print_memory();
+ memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
+ old = u_repl->counters;
+ new = newcounters;
+ point = counterchanges;
+ while (*point != CNT_END) {
+ if (*point == CNT_NORM) {
+ // 'normal' rule, meaning we didn't do anything to it
+ // So, we just copy
+ new->pcnt = old->pcnt;
+ // we've used an old counter
+ old++;
+ // we've set a new counter
+ new++;
+ } else
+ if (*point == CNT_DEL) {
+ // don't use this old counter
+ old++;
+ } else if (*point == CNT_ADD) {
+ // new counter, let it stay 0
+ new++;
+ } else {
+ // zero it
+ new->pcnt = 0;
+ old++;
+ new++;
+ }
+ point++;
+ }
+
+ free(u_repl->counters);
+ u_repl->counters = newcounters;
+ u_repl->num_counters = u_repl->nentries;
+ optlen = u_repl->nentries * sizeof(struct ebt_counter) +
+ sizeof(struct ebt_replace);
+ // now put the stuff in the kernel's struct ebt_replace
+ repl.counters = u_repl->counters;
+ repl.num_counters = u_repl->num_counters;
+ memcpy(repl.name, u_repl->name, sizeof(repl.name));
+
+ get_sockfd();
+ if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
+ print_bug("couldn't update kernel counters");
+}
+
+static int
+ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
+{
+ struct ebt_u_match_list *new;
+
+ new = (struct ebt_u_match_list *)
+ malloc(sizeof(struct ebt_u_match_list));
+ if (!new)
+ print_memory();
+ new->m = (struct ebt_entry_match *)
+ malloc(m->match_size + sizeof(struct ebt_entry_match));
+ if (!new->m)
+ print_memory();
+ memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
+ new->next = NULL;
+ **l = new;
+ *l = &new->next;
+ if (find_match(new->m->u.name) == NULL)
+ print_error("Kernel match %s unsupported by userspace tool",
+ new->m->u.name);
+ return 0;
+}
+
+static int
+ebt_translate_watcher(struct ebt_entry_watcher *w,
+ struct ebt_u_watcher_list ***l)
+{
+ struct ebt_u_watcher_list *new;
+
+ new = (struct ebt_u_watcher_list *)
+ malloc(sizeof(struct ebt_u_watcher_list));
+ if (!new)
+ print_memory();
+ new->w = (struct ebt_entry_watcher *)
+ malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
+ if (!new->w)
+ print_memory();
+ memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
+ new->next = NULL;
+ **l = new;
+ *l = &new->next;
+ if (find_watcher(new->w->u.name) == NULL)
+ print_error("Kernel watcher %s unsupported by userspace tool",
+ new->w->u.name);
+ return 0;
+}
+
+static int
+ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
+ int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
+ unsigned int valid_hooks)
+{
+ // an entry
+ if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
+ struct ebt_u_entry *new;
+ struct ebt_u_match_list **m_l;
+ struct ebt_u_watcher_list **w_l;
+ struct ebt_entry_target *t;
+
+ new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
+ if (!new)
+ print_memory();
+ new->bitmask = e->bitmask;
+ // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
+ new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
+ new->invflags = e->invflags;
+ new->ethproto = e->ethproto;
+ memcpy(new->in, e->in, sizeof(new->in));
+ memcpy(new->out, e->out, sizeof(new->out));
+ memcpy(new->logical_in, e->logical_in,
+ sizeof(new->logical_in));
+ memcpy(new->logical_out, e->logical_out,
+ sizeof(new->logical_out));
+ memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
+ memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
+ memcpy(new->destmac, e->destmac, sizeof(new->destmac));
+ memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
+ new->m_list = NULL;
+ new->w_list = NULL;
+ new->next = NULL;
+ m_l = &new->m_list;
+ EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
+ w_l = &new->w_list;
+ EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
+
+ t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
+ new->t = (struct ebt_entry_target *)
+ malloc(t->target_size + sizeof(struct ebt_entry_target));
+ if (!new->t)
+ print_memory();
+ if (find_target(t->u.name) == NULL)
+ print_error("Kernel target %s unsupported by "
+ "userspace tool", t->u.name);
+ memcpy(new->t, t, t->target_size +
+ sizeof(struct ebt_entry_target));
+
+ // I love pointers
+ **u_e = new;
+ *u_e = &new->next;
+ (*cnt)++;
+ (*totalcnt)++;
+ return 0;
+ } else { // a new chain
+ int i;
+ struct ebt_entries *entries = (struct ebt_entries *)e;
+ struct ebt_u_entries *new;
+
+ for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
+ if (valid_hooks & (1 << i))
+ break;
+ if (i >= NF_BR_NUMHOOKS)
+ print_bug("Not enough valid hooks");
+ *hook = i;
+ if (*n != *cnt)
+ print_bug("Nr of entries in the chain is wrong");
+ *n = entries->nentries;
+ *cnt = 0;
+ new = (struct ebt_u_entries *)
+ malloc(sizeof(struct ebt_u_entries));
+ if (!new)
+ print_memory();
+ new->nentries = entries->nentries;
+ new->policy = entries->policy;
+ new->entries = NULL;
+ u_repl->hook_entry[*hook] = new;
+ *u_e = &new->entries;
+ return 0;
+ }
+}
+
+// talk with kernel to receive the kernel's table
+void get_table(struct ebt_u_replace *u_repl)
+{
+ int i, j, k, hook;
+ socklen_t optlen;
+ struct ebt_replace repl;
+ struct ebt_u_entry **u_e;
+
+ get_sockfd();
+
+ optlen = sizeof(struct ebt_replace);
+ strcpy(repl.name, u_repl->name);
+ if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_INFO, &repl, &optlen))
+ print_error("A kernel module needed by your command is probably"
+ " not loaded. Try insmod ebtables or"
+ " insmod ebtable_%s", repl.name);
+
+ if ( !(repl.entries = (char *) malloc(repl.entries_size)) )
+ print_memory();
+ if (repl.nentries) {
+ if (!(repl.counters = (struct ebt_counter *)
+ malloc(repl.nentries * sizeof(struct ebt_counter))) )
+ print_memory();
+ }
+ else
+ repl.counters = NULL;
+
+ // we want to receive the counters
+ repl.num_counters = repl.nentries;
+ optlen += repl.entries_size + repl.num_counters *
+ sizeof(struct ebt_counter);
+ if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_ENTRIES, &repl, &optlen))
+ print_bug("hmm, what is wrong??? bug#1");
+
+ // translate the struct ebt_replace to a struct ebt_u_replace
+ memcpy(u_repl->name, repl.name, sizeof(u_repl->name));
+ u_repl->valid_hooks = repl.valid_hooks;
+ u_repl->nentries = repl.nentries;
+ u_repl->num_counters = repl.num_counters;
+ u_repl->counters = repl.counters;
+ memcpy(u_repl->counter_entry, repl.counter_entry,
+ sizeof(repl.counter_entry));
+ hook = -1;
+ i = 0; // holds the expected nr. of entries for the chain
+ j = 0; // holds the up to now counted entries for the chain
+ k = 0; // holds the total nr. of entries,
+ // should equal u_repl->nentries afterwards
+ EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
+ &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks);
+ if (k != u_repl->nentries)
+ print_bug("Wrong total nentries");
+}
+
+void get_dbinfo(struct brdb_dbinfo *nr)
+{
+ socklen_t optlen = sizeof(struct brdb_dbinfo);
+
+ get_sockfd();
+
+ if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen))
+ print_error("Sorry, br_db code probably not in kernel, "
+ "try insmod br_db");
+}
+
+void get_db(int len, struct brdb_dbentry *db)
+{
+ socklen_t optlen = len;
+
+ get_sockfd();
+
+ if ( getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DB, db, &optlen) ) {
+ print_bug("hmm, what is wrong??? bug#2");
+ }
+}
+
+void deliver_allowdb(__u16 *decision)
+{
+ socklen_t optlen = sizeof(__u16);
+
+ get_sockfd();
+
+ if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB,
+ decision, optlen))
+ print_error("Sorry, br_db code probably not in kernel, "
+ "try insmod br_db");
+}
diff --git a/userspace/ebtables2/ebtables.8 b/userspace/ebtables2/ebtables.8
new file mode 100644
index 0000000..d0d7a18
--- /dev/null
+++ b/userspace/ebtables2/ebtables.8
@@ -0,0 +1,434 @@
+.TH EBTABLES 8 "01 May 2002"
+.\"
+.\" Man page written by Bart De Schuymer <bart.de.schuymer@pandora.be>
+.\" It is based on the iptables man page.
+.\"
+.\" Iptables page by Herve Eychenne March 2000.
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\"
+.SH NAME
+ebtables(v.2.0) \- ethernet bridge packet table administration
+.SH SYNOPSIS
+.BR "ebtables -[ADI] " "chain rule-specification [options]"
+.br
+.BR "ebtables -P " "chain target"
+.br
+.BR "ebtables -[FLZ] [" "chain" "]"
+.br
+.B "ebtables -L DB"
+.br
+.BR "ebtables -[b] [" "y/n" "]"
+.br
+.SH DESCRIPTION
+.B ebtables
+is used to set up, maintain, and inspect the tables of Ethernet frame
+rules in the Linux kernel. It works analogous as iptables, but is less
+complicated. This man page is written with the man page of iptables
+next to it, so don't be surprised to see copied sentences and structure.
+
+There are three tables with built-in chains. Each chain is a list
+of rules which can match frames: each rule specifies what to do with a
+frame which matches. This is called a 'target'. The tables are used to
+divide functionality into different sets of chains.
+
+.SS TARGETS
+A firewall rule specifies criteria for a frame, and a target. If the
+frame does not match, the next rule in the chain is the examined one; if
+it does match, then the next thing to do is specified by the target.
+This target can be one of these values:
+.IR ACCEPT ,
+.IR DROP ,
+.IR CONTINUE ,
+an extention.
+.PP
+.I ACCEPT
+means to let the frame through.
+.I DROP
+means the frame has to be dropped.
+.I CONTINUE
+means the next rule has to be checked. This can be handy to know how many
+frames pass a certain point in the chain or to log those frames. For the
+other targets see the
+.B "TARGET EXTENSIONS"
+section.
+.SS TABLES
+There are three tables.
+.TP
+.B "-t, --table"
+This option specifies the frame matching table which the command should
+operate on. The tables are:
+.BR filter ,
+this is the default table and contains three chains:
+.B INPUT
+(for frames destined for the bridge itself),
+.B OUTPUT
+(for locally-generated frames) and
+.B FORWARD
+(for frames being bridged).
+.BR nat ,
+this table is used to change the mac addresses and contains three chains:
+.B PREROUTING
+(for altering frames as soon as they come in),
+.B OUTPUT
+(for altering locally generated frames before they are bridged) and
+.B POSTROUTING
+(for altering frames as they are about to go out). A small note on the naming
+of chains POSTROUTING and PREROUTING: it would be more accurate to call them
+PREFORWARDING and POSTFORWARDING, but for all those who come from the
+.BR iptables " world to " ebtables
+it is easier to have the same names.
+.BR broute ,
+this table is used to make a brouter, it has one chain:
+.BR BROUTING .
+The targets
+.BR DROP " and " ACCEPT
+have special meaning in this table.
+.B DROP
+actually means the frame has to be routed, while
+.B ACCEPT
+means the frame has to be bridged. The
+.B BROUTING
+chain is traversed very early. It is only traversed by frames entering on
+a bridge enslaved nic that is in forwarding state. Normally those frames
+would be bridged, but you can decide otherwise here. The
+.B redirect
+target is very handy here.
+.SH OPTIONS
+The options can be divided into several different groups.
+.SS COMMANDS
+These options specify the specific actions to perform; only one of them
+can be specified on the command line (the
+.B -Z
+command is an exception). All these options only apply to the selected
+(or default) table.
+.TP
+.B "-A, --append"
+Append a rule to the end of the selected chain.
+.TP
+.B "-D, --delete"
+Delete the specified rule from the selected chain. There are two versions
+of this command. A rule number (starting at 1) or the complete rule can be
+specified.
+.TP
+.B "-I, --insert"
+Insert the specified rule into the selected chain at the specified rule number (1 meaning
+the head of the chain).
+.TP
+.B "-L, --list"
+List all rules in the selected chain. If no chain is selected, all chains
+are listed. If the chainname equals
+.BR DB ,
+.B ebtables
+will try to show the database. This database gives a survey of the kind of
+frames that pass the different bridge hooks. It uses the interfaces where
+the frame came in or will go out, the protocol field and the hook. This
+database is independent from the rest of
+.B ebtables
+and is in a different kernel module.
+.TP
+.B "-F, --flush"
+Flush the selected chain. If no chain is selected, every chain will be
+flushed. This does not change the policy of the chain.
+.TP
+.B "-Z, --zero"
+Put the counters of the selected chain on zero. If no chain is selected, all the counters
+are put on zero. This can be used in conjunction with the -L command (see above).
+This will cause the rule counters to be printed on the screen before they are put on zero.
+.TP
+.B "-P, --policy"
+Set the policy for the chain to the given target. The policy is either
+.B ACCEPT
+, either
+.BR DROP .
+.SS PARAMETERS
+The following parameters make up a rule specification (as used in the add
+and delete commands). A "!" argument before the specification inverts the
+test for that specification. Apart from these standard parameters, there are others, see
+.BR "MATCH EXTENSIONS" .
+.TP
+.BR "-p, --protocol " "[!] \fIprotocol\fP"
+The protocol that was responsible for creating the frame. This can be a
+hexadecimal number, above
+.IR 0x0600 ,
+a name (e.g.
+.I ARP
+) or
+.BR LENGTH .
+The protocol field of the Ethernet frame can be used to denote the
+length of the header (802.2/802.3 networks). When the value of that field is
+below (or equals)
+.IR 0x0600 ,
+the value equals the size of the header and shouldn't be used as a
+protocol number. Instead, all frames where the protocol field is used as
+the length field are assumed to be of the same 'protocol'. The protocol
+name used in
+.B ebtables
+for these frames is
+.BR LENGTH .
+.br
+The file
+.B /etc/ethertypes
+can be used to show readable
+characters instead of hexadecimal numbers for the protocols. For example,
+.I 0x0800
+will be represented by
+.IR IPV4 .
+The use of this file is not case sensitive.
+See that file for more information. The flag
+.B --proto
+is an alias for this option.
+.TP
+.BR "-i, --in-interface " "[!] \fIname\fP"
+The interface via which a frame is received (for the
+.BR INPUT ,
+.BR FORWARD ,
+.BR PREROUTING " and " BROUTING
+chains). The flag
+.B --in-if
+is an alias for this option.
+.TP
+.BR "--logical-in " "[!] \fIname\fP"
+The (logical) bridge interface via which a frame is received (for the
+.BR INPUT ,
+.BR FORWARD ,
+.BR PREROUTING " and " BROUTING
+chains).
+.TP
+.BR "-o, --out-interface " "[!] \fIname\fP"
+The interface via which a frame is going to be sent (for the
+.BR OUTPUT ,
+.B FORWARD
+and
+.B POSTROUTING
+chains). The flag
+.B --out-if
+is an alias for this option.
+.TP
+.BR "--logical-out " "[!] \fIname\fP"
+The (logical) bridge interface via which a frame is going to be sent (for
+the
+.BR OUTPUT ,
+.B FORWARD
+and
+.B POSTROUTING
+chains).
+.TP
+.BR "-s, --source " "[!] \fIaddress\fP[/\fImask\fP]"
+The source mac address. Both mask and address are written as 6 hexadecimal
+numbers seperated by colons. Alternatively one can specify Unicast,
+Multicast or Broadcast.
+.br
+Unicast=00:00:00:00:00:00/01:00:00:00:00:00,
+Multicast=01:00:00:00:00:00/01:00:00:00:00:00 and
+Broadcast=ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff. Note that a broadcast
+address will also match the multicast specification. The flag
+.B --src
+is an alias for this option.
+.TP
+.BR "-d, --destination " "[!] \fIaddress\fP[/\fImask\fP]"
+The destination mac address. See -s (above) for more details. The flag
+.B --dst
+is an alias for this option.
+
+.SS OTHER OPTIONS
+.TP
+.B "-V, --version"
+Show the version of the userprogram.
+.TP
+.B "-h, --help"
+Give a brief description of the command syntax. Here you can also specify
+names of extensions and
+.B ebtables
+will try to write help about those extensions. E.g. ebtables -h snat log ip arp.
+.TP
+.BR "-b --db " "[\fIy/n\fP]"
+.IR "" "Enable (" y ") or disable (" n ") the database."
+.TP
+.BR "-j, --jump " "\fItarget\fP"
+The target of the rule. This is one of the following values:
+.BR ACCEPT ,
+.BR DROP ,
+.BR CONTINUE ,
+or a target extension, see
+.BR "TARGET EXTENSIONS" .
+.SH MATCH EXTENSIONS
+.B ebtables
+extensions are precompiled into the userspace tool. So there is no need
+to explicitly load them with a -m option like in iptables. However, these
+extensions deal with functionality supported by supplemental kernel modules.
+.SS ip
+Specify ip specific fields. These will only work if the protocol equals
+.BR IPv4 .
+.TP
+.BR "--ip-source " "[!] \fIaddress\fP[/\fImask\fP]"
+The source ip address.
+The flag
+.B --ip-src
+is an alias for this option.
+.TP
+.BR "--ip-destination " "[!] \fIaddress\fP[/\fImask\fP]"
+The destination ip address.
+The flag
+.B --ip-dst
+is an alias for this option.
+.TP
+.BR "--ip-tos " "[!] \fItos\fP"
+The ip type of service, in hexadecimal numbers.
+.BR IPv4 .
+.TP
+.BR "--ip-protocol " "[!] \fIprotocol\fP"
+The ip protocol.
+The flag
+.B --ip-proto
+is an alias for this option.
+.SS arp
+Specify arp specific fields. These will only work if the protocol equals
+.BR ARP " or " RARP .
+.TP
+.BR "--arp-opcode " "[!] \fIopcode\fP"
+The (r)arp opcode (decimal or a string, for more details see ebtables -h arp).
+.TP
+.BR "--arp-htype " "[!] \fIhardware type\fP"
+The hardware type, this can be a decimal or the string "Ethernet". This
+is normally Ethernet (value 1).
+.TP
+.BR "--arp-ptype " "[!] \fIprotocol type\fP"
+The protocol type for which the (r)arp is used (hexadecimal or the string "IPv4").
+This is normally IPv4 (0x0800).
+.TP
+.BR "--arp-ip-src " "[!] \fIaddress\fP[/\fImask\fP]"
+The ARP IP source address specification.
+.TP
+.BR "--arp-ip-dst " "[!] \fIaddress\fP[/\fImask\fP]"
+The ARP IP destination address specification.
+.SS vlan
+Specify 802.1Q VLAN specific fields. These will only work if the protocol equals
+.BR 802_1Q .
+For more details see
+.BR "ebtables -h vlan" .
+.TP
+.BR "--vlan-id " "[!] \fIid\fP"
+The VLAN identifier (decimal number from 0 to 4095).
+.TP
+.BR "--vlan-prio " "[!] \fIprio\fP"
+The VLAN priority type, this can be a decimal number from 0 to 7. The default value is 0.
+.SH WATCHER EXTENSION(S)
+Watchers are things that only look at frames passing by. These watchers only see the
+frame if the frame passes all the matches of the rule.
+.SS log
+The fact that the log module is a watcher lets us log stuff while giving a target
+by choice. Note that the log module therefore is not a target.
+.TP
+.B "--log"
+.br
+Use this if you won't specify any other log options, so if you want to use the default
+settings: log-prefix="", no arp logging, no ip logging, log-level=info.
+.TP
+.B --log-level "\fIlevel\fP"
+.br
+defines the logging level. For the possible values: ebtables -h log.
+The default level is
+.IR info .
+.TP
+.BR --log-prefix " \fItext\fP"
+.br
+defines the prefix to be printed before the logging information.
+.TP
+.B --log-ip
+.br
+will log the ip information when a frame made by the ip protocol matches
+the rule. The default is no ip information logging.
+.TP
+.B --log-arp
+.br
+will log the (r)arp information when a frame made by the (r)arp protocols
+matches the rule. The default is no (r)arp information logging.
+.SS TARGET EXTENSIONS
+.TP
+.B snat
+The
+.B snat
+target can only be used in the
+.BR POSTROUTING " chain of the " nat " table."
+It specifies that the source mac address has to be changed.
+.br
+.BR "--to-source " "\fIaddress\fP"
+.br
+The flag
+.B --to-src
+is an alias for this option.
+.br
+.BR "--snat-target " "\fItarget\fP"
+.br
+Specifies the standard target. After doing the snat, the rule still has
+to give a standard target so
+.B ebtables
+knows what to do.
+The default target is ACCEPT. Making it CONTINUE could let you use
+multiple target extensions on the same frame. Making it DROP doesn't
+make sense, but you could do that too.
+.TP
+.B dnat
+The
+.B dnat
+target can only be used in the
+.BR BROUTING " chain of the " broute " table and the "
+.BR PREROUTING " and " OUTPUT " chains of the " nat " table."
+It specifies that the destination mac address has to be changed.
+.br
+.BR "--to-destination " "\fIaddress\fP"
+.br
+The flag
+.B --to-dst
+is an alias for this option.
+.br
+.BR "--dnat-target " "\fItarget\fP"
+.br
+Specifies the standard target. After doing the dnat, the rule still has to
+give a standard target so
+.B ebtables
+knows what to do.
+The default target is ACCEPT. Making it CONTINUE could let you use
+multiple target extensions on the same frame. Making it DROP only makes
+sense in the BROUTING chain but using the redirect target is more logical
+there.
+.TP
+.B redirect
+The
+.B redirect
+target will change the MAC target address to that of the bridge device the
+frame arrived on. This target can only be used in the
+.BR BROUTING " chain of the " broute " table and the "
+.BR PREROUTING " chain of the " nat " table."
+.br
+.BR "--redirect-target " "\fItarget\fP"
+.br
+Specifies the standard target. After doing the MAC redirect, the rule
+still has to give a standard target so
+.B ebtables
+knows what to do.
+The default target is ACCEPT. Making it CONTINUE could let you use
+multiple target extensions on the same frame. Making it DROP in the
+BROUTING chain will let the frames be routed.
+.SH FILES
+.I /etc/ethertypes
+.SH BUGS
+This won't work on an architecture with a user32/kernel64 situation like the Sparc64.
+.SH AUTHOR
+.IR "" "Bart De Schuymer <" bart.de.schuymer@pandora.be >
+.SH SEE ALSO
+.BR iptables "(8), " brctl (8)
diff --git a/userspace/ebtables2/ebtables.c b/userspace/ebtables2/ebtables.c
new file mode 100644
index 0000000..e28fd96
--- /dev/null
+++ b/userspace/ebtables2/ebtables.c
@@ -0,0 +1,1655 @@
+/*
+ * ebtables.c, v2.0 April 2002
+ *
+ * Author: Bart De Schuymer
+ *
+ * This code is stongly inspired on the iptables code which is
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/br_db.h> // the database
+#include <netinet/in.h>
+#include <asm/types.h>
+#include "include/ebtables_u.h"
+
+// here are the number-name correspondences kept for the ethernet
+// frame type field
+#define PROTOCOLFILE "/etc/ethertypes"
+
+#define DATABASEHOOKNR NF_BR_NUMHOOKS
+#define DATABASEHOOKNAME "DB"
+
+static char *prog_name = PROGNAME;
+static char *prog_version = PROGVERSION;
+char* hooknames[NF_BR_NUMHOOKS] = {
+ [NF_BR_PRE_ROUTING]"PREROUTING",
+ [NF_BR_LOCAL_IN]"INPUT",
+ [NF_BR_FORWARD]"FORWARD",
+ [NF_BR_LOCAL_OUT]"OUTPUT",
+ [NF_BR_POST_ROUTING]"POSTROUTING",
+ [NF_BR_BROUTING]"BROUTING"
+};
+
+// default command line options
+static struct option ebt_original_options[] = {
+ { "append" , required_argument, 0, 'A' },
+ { "insert" , required_argument, 0, 'I' },
+ { "delete" , required_argument, 0, 'D' },
+ { "list" , optional_argument, 0, 'L' },
+ { "zero" , optional_argument, 0, 'Z' },
+ { "flush" , optional_argument, 0, 'F' },
+ { "policy" , required_argument, 0, 'P' },
+ { "in-interface" , required_argument, 0, 'i' },
+ { "in-if" , required_argument, 0, 'i' },
+ { "logical-in" , required_argument, 0, 2 },
+ { "logical-out" , required_argument, 0, 3 },
+ { "out-interface" , required_argument, 0, 'o' },
+ { "out-if" , required_argument, 0, 'o' },
+ { "version" , no_argument , 0, 'V' },
+ { "help" , no_argument , 0, 'h' },
+ { "jump" , required_argument, 0, 'j' },
+ { "proto" , required_argument, 0, 'p' },
+ { "protocol" , required_argument, 0, 'p' },
+ { "db" , required_argument, 0, 'b' },
+ { "source" , required_argument, 0, 's' },
+ { "src" , required_argument, 0, 's' },
+ { "destination" , required_argument, 0, 'd' },
+ { "dst" , required_argument, 0, 'd' },
+ { "table" , required_argument, 0, 't' },
+ { 0 }
+};
+
+static struct option *ebt_options = ebt_original_options;
+
+// yup, all the possible target names
+char* standard_targets[NUM_STANDARD_TARGETS] = {
+ "ACCEPT",
+ "DROP",
+ "CONTINUE",
+};
+
+unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
+unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
+unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
+unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
+unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
+unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
+
+// tells what happened to the old rules
+static unsigned short *counterchanges;
+// holds all the data
+static struct ebt_u_replace replace;
+
+// the chosen table
+static struct ebt_u_table *table = NULL;
+// the lists of supported tables, matches, watchers and targets
+static struct ebt_u_table *tables = NULL;
+static struct ebt_u_match *matches = NULL;
+static struct ebt_u_watcher *watchers = NULL;
+static struct ebt_u_target *targets = NULL;
+
+struct ebt_u_target *find_target(const char *name)
+{
+ struct ebt_u_target *t = targets;
+
+ while(t && strcmp(t->name, name))
+ t = t->next;
+ return t;
+}
+
+struct ebt_u_match *find_match(const char *name)
+{
+ struct ebt_u_match *m = matches;
+
+ while(m && strcmp(m->name, name))
+ m = m->next;
+ return m;
+}
+
+struct ebt_u_watcher *find_watcher(const char *name)
+{
+ struct ebt_u_watcher *w = watchers;
+
+ while(w && strcmp(w->name, name))
+ w = w->next;
+ return w;
+}
+
+struct ebt_u_table *find_table(char *name)
+{
+ struct ebt_u_table *t = tables;
+
+ while (t && strcmp(t->name, name))
+ t = t->next;
+ return t;
+}
+
+// The pointers in here are special:
+// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
+// instead of making yet a few other structs, we just do a cast.
+// We need a struct ebt_u_target pointer because we know the address of the data
+// they point to won't change. We want to allow that the struct ebt_u_target.t
+// member can change.
+// Same holds for the struct ebt_match and struct ebt_watcher pointers
+struct ebt_u_entry *new_entry;
+
+void initialize_entry(struct ebt_u_entry *e)
+{
+ e->bitmask = EBT_NOPROTO;
+ e->invflags = 0;
+ e->ethproto = 0;
+ strcpy(e->in, "");
+ strcpy(e->out, "");
+ strcpy(e->logical_in, "");
+ strcpy(e->logical_out, "");
+ e->m_list = NULL;
+ e->w_list = NULL;
+ // the init function of the standard target should have put the verdict
+ // on CONTINUE
+ e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
+ if (!e->t)
+ print_bug("Couldn't load standard target\n");
+}
+
+// this doesn't free e, becoz the calling function might need e->next
+void free_u_entry(struct ebt_u_entry *e)
+{
+ struct ebt_u_match_list *m_l, *m_l2;
+ struct ebt_u_watcher_list *w_l, *w_l2;
+
+ m_l = e->m_list;
+ while (m_l) {
+ m_l2 = m_l->next;
+ free(m_l->m);
+ free(m_l);
+ m_l = m_l2;
+ }
+ w_l = e->w_list;
+ while (w_l) {
+ w_l2 = w_l->next;
+ free(w_l->w);
+ free(w_l);
+ w_l = w_l2;
+ }
+ free(e->t);
+}
+
+// the user will use the match, so put it in new_entry
+static void add_match(struct ebt_u_match *m)
+{
+ struct ebt_u_match_list **m_list, *new;
+
+ m->used = 1;
+ for (m_list = &new_entry->m_list;
+ *m_list; m_list = &(*m_list)->next);
+ new = (struct ebt_u_match_list *)
+ malloc(sizeof(struct ebt_u_match_list));
+ if (!new)
+ print_memory();
+ *m_list = new;
+ new->next = NULL;
+ new->m = (struct ebt_entry_match *)m;
+}
+
+static void add_watcher(struct ebt_u_watcher *w)
+{
+ struct ebt_u_watcher_list **w_list;
+ struct ebt_u_watcher_list *new;
+
+ w->used = 1;
+ for (w_list = &new_entry->w_list;
+ *w_list; w_list = &(*w_list)->next);
+ new = (struct ebt_u_watcher_list *)
+ malloc(sizeof(struct ebt_u_watcher_list));
+ if (!new)
+ print_memory();
+ *w_list = new;
+ new->next = NULL;
+ new->w = (struct ebt_entry_watcher *)w;
+}
+
+static int global_option_offset = 0;
+#define OPTION_OFFSET 256
+static struct option *
+merge_options(struct option *oldopts, const struct option *newopts,
+ unsigned int *options_offset)
+{
+ unsigned int num_old, num_new, i;
+ struct option *merge;
+
+ if (!newopts || !oldopts || !options_offset)
+ print_bug("merge wrong");
+ for (num_old = 0; oldopts[num_old].name; num_old++);
+ for (num_new = 0; newopts[num_new].name; num_new++);
+
+ global_option_offset += OPTION_OFFSET;
+ *options_offset = global_option_offset;
+
+ merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
+ if (!merge)
+ print_memory();
+ memcpy(merge, oldopts, num_old * sizeof(struct option));
+ for (i = 0; i < num_new; i++) {
+ merge[num_old + i] = newopts[i];
+ merge[num_old + i].val += *options_offset;
+ }
+ memset(merge + num_old + num_new, 0, sizeof(struct option));
+ // only free dynamically allocated stuff
+ if (oldopts != ebt_original_options)
+ free(oldopts);
+
+ return merge;
+}
+
+void register_match(struct ebt_u_match *m)
+{
+ int size = m->size + sizeof(struct ebt_entry_match);
+ struct ebt_u_match **i;
+
+ m->m = (struct ebt_entry_match *)malloc(size);
+ if (!m->m)
+ print_memory();
+ strcpy(m->m->u.name, m->name);
+ m->m->match_size = m->size;
+ ebt_options = merge_options
+ (ebt_options, m->extra_ops, &(m->option_offset));
+ m->init(m->m);
+
+ for (i = &matches; *i; i = &((*i)->next));
+ m->next = NULL;
+ *i = m;
+}
+
+void register_watcher(struct ebt_u_watcher *w)
+{
+ int size = w->size + sizeof(struct ebt_entry_watcher);
+ struct ebt_u_watcher **i;
+
+ w->w = (struct ebt_entry_watcher *)malloc(size);
+ if (!w->w)
+ print_memory();
+ strcpy(w->w->u.name, w->name);
+ w->w->watcher_size = w->size;
+ ebt_options = merge_options
+ (ebt_options, w->extra_ops, &(w->option_offset));
+ w->init(w->w);
+
+ for (i = &watchers; *i; i = &((*i)->next));
+ w->next = NULL;
+ *i = w;
+}
+
+void register_target(struct ebt_u_target *t)
+{
+ int size = t->size + sizeof(struct ebt_entry_target);
+ struct ebt_u_target **i;
+
+ t->t = (struct ebt_entry_target *)malloc(size);
+ if (!t->t)
+ print_memory();
+ strcpy(t->t->u.name, t->name);
+ t->t->target_size = t->size;
+ ebt_options = merge_options
+ (ebt_options, t->extra_ops, &(t->option_offset));
+ t->init(t->t);
+ for (i = &targets; *i; i = &((*i)->next));
+ t->next = NULL;
+ *i = t;
+}
+
+void register_table(struct ebt_u_table *t)
+{
+ t->next = tables;
+ tables = t;
+}
+
+// used to parse /etc/etherproto
+int disregard_whitespace(char *buffer, FILE *ifp)
+{
+ int hlp;
+ buffer[0] = '\t';
+ while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') {
+ hlp = fscanf(ifp, "%c", buffer);
+ if (hlp == EOF || hlp == 0) return -1;
+ }
+ return 0;
+}
+
+// used to parse /etc/etherproto
+int disregard_tabspace(char *buffer, FILE *ifp)
+{
+ int hlp;
+ buffer[0] = '\t';
+ while (buffer[0] == '\t' || buffer[0] == ' ') {
+ hlp = fscanf(ifp, "%c", buffer);
+ if (hlp == EOF || hlp == 0) return -1;
+ }
+ return 0;
+}
+
+// helper function: processes a line of data from the file /etc/etherproto
+int get_a_line(char *buffer, char *value, FILE *ifp)
+{
+ int i, hlp;
+ char anotherhlp;
+
+ /* discard comment lines && whitespace*/
+ while (1) {
+ if (disregard_whitespace(buffer, ifp)) return -1;
+ if (buffer[0] == '#')
+ while (1) {
+ hlp = fscanf(ifp, "%c", &anotherhlp);
+ if (!hlp || hlp == EOF)
+ return -1;
+ if (anotherhlp == '\n')
+ break;
+ }
+ else break;
+ }
+
+ // buffer[0] already contains the first letter
+ for (i = 1; i < 21; i++) {
+ hlp = fscanf(ifp, "%c", buffer + i);
+ if (hlp == EOF || hlp == 0) return -1;
+ if (buffer[i] == '\t' || buffer[i] == ' ')
+ break;
+ }
+ if (i == 21) return -1;
+ buffer[i] = '\0';
+ if (disregard_tabspace(value, ifp))
+ return -1;
+ // maybe I should allow 0x0800 instead of 0800, but I'm feeling lazy
+ // buffer[0] already contains the first letter
+ for (i = 1; i < 5; i++) {
+ hlp = fscanf(ifp, "%c", value+i);
+ if (value[i] == '\n' || value[i] == '\t' ||
+ value[i] == ' ' || hlp == EOF)
+ break;
+ }
+ if (i == 5) return -1;
+ /* discard comments at the end of a line */
+ if (value[i] == '\t' || value[i] == ' ')
+ while (1) {
+ hlp = fscanf(ifp, "%c", &anotherhlp);
+ if (!hlp || hlp == EOF || anotherhlp == '\n')
+ break;
+ }
+ value[i] = '\0';
+ return 0;
+}
+
+// helper function for list_em()
+int number_to_name(unsigned short proto, char *name)
+{
+ FILE *ifp;
+ char buffer[21], value[5], *bfr;
+ unsigned short i;
+
+ if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
+ return -1;
+ while (1) {
+ if (get_a_line(buffer, value, ifp)) {
+ fclose(ifp);
+ return -1;
+ }
+ i = (unsigned short) strtol(value, &bfr, 16);
+ if (*bfr != '\0' || i != proto)
+ continue;
+ strcpy(name, buffer);
+ fclose(ifp);
+ return 0;
+ }
+}
+
+// helper function for list_rules()
+static void list_em(int hooknr)
+{
+ int i, j, space = 0, digits;
+ struct ebt_u_entry *hlp;
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+ struct ebt_u_match *m;
+ struct ebt_u_watcher *w;
+ struct ebt_u_target *t;
+ char name[21];
+
+ hlp = replace.hook_entry[hooknr]->entries;
+ printf("\nBridge chain: %s\nPolicy: %s\n", hooknames[hooknr],
+ standard_targets[replace.hook_entry[hooknr]->policy]);
+ printf("nr. of entries: %d \n", replace.hook_entry[hooknr]->nentries);
+
+ i = replace.hook_entry[hooknr]->nentries;
+ while (i >9) {
+ space++;
+ i /= 10;
+ }
+
+ for (i = 0; i < replace.hook_entry[hooknr]->nentries; i++) {
+ digits = 0;
+ // A little work to get nice rule numbers.
+ while (j > 9) {
+ digits++;
+ j /= 10;
+ }
+ for (j = 0; j < space - digits; j++)
+ printf(" ");
+ printf("%d. ", i + 1);
+
+ // Don't print anything about the protocol if no protocol was
+ // specified, obviously this means any protocol will do.
+ if (!(hlp->bitmask & EBT_NOPROTO)) {
+ printf("eth proto: ");
+ if (hlp->invflags & EBT_IPROTO)
+ printf("! ");
+ if (hlp->bitmask & EBT_802_3)
+ printf("Length, ");
+ else {
+ if (number_to_name(ntohs(hlp->ethproto), name))
+ printf("0x%x, ", ntohs(hlp->ethproto));
+ else
+ printf("%s, ", name);
+ }
+ }
+ if (hlp->bitmask & EBT_SOURCEMAC) {
+ char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ printf("source mac: ");
+ if (hlp->invflags & EBT_ISOURCE)
+ printf("! ");
+ if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
+ !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
+ printf("Unicast");
+ goto endsrc;
+ }
+ if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
+ !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
+ printf("Multicast");
+ goto endsrc;
+ }
+ if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
+ !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
+ printf("Broadcast");
+ goto endsrc;
+ }
+ for (j = 0; j < ETH_ALEN; j++)
+ printf("%02x%s", hlp->sourcemac[j],
+ (j == ETH_ALEN - 1) ? "" : ":");
+ if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
+ printf("/");
+ for (j = 0; j < ETH_ALEN; j++)
+ printf("%02x%s", hlp->sourcemsk[j],
+ (j == ETH_ALEN - 1) ? "" : ":");
+ }
+endsrc:
+ printf(", ");
+ }
+ if (hlp->bitmask & EBT_DESTMAC) {
+ char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ printf("dest mac: ");
+ if (hlp->invflags & EBT_IDEST)
+ printf("! ");
+ if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
+ !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
+ printf("Unicast");
+ goto enddst;
+ }
+ if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
+ !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
+ printf("Multicast");
+ goto enddst;
+ }
+ if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
+ !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
+ printf("Broadcast");
+ goto enddst;
+ }
+ for (j = 0; j < ETH_ALEN; j++)
+ printf("%02x%s", hlp->destmac[j],
+ (j == ETH_ALEN - 1) ? "" : ":");
+ if (memcmp(hlp->destmsk, hlpmsk, 6)) {
+ printf("/");
+ for (j = 0; j < ETH_ALEN; j++)
+ printf("%02x%s", hlp->destmsk[j],
+ (j == ETH_ALEN - 1) ? "" : ":");
+ }
+enddst:
+ printf(", ");
+ }
+ if (hlp->in[0] != '\0') {
+ if (hlp->invflags & EBT_IIN)
+ printf("! ");
+ printf("in-if: %s, ", hlp->in);
+ }
+ if (hlp->logical_in[0] != '\0') {
+ if (hlp->invflags & EBT_ILOGICALIN)
+ printf("! ");
+ printf("logical in-if: %s, ", hlp->logical_in);
+ }
+ if (hlp->logical_out[0] != '\0') {
+ if (hlp->invflags & EBT_ILOGICALOUT)
+ printf("! ");
+ printf("logical out-if: %s, ", hlp->logical_out);
+ }
+ if (hlp->out[0] != '\0') {
+ if (hlp->invflags & EBT_IOUT)
+ printf("! ");
+ printf("out-if: %s, ", hlp->out);
+ }
+
+ m_l = hlp->m_list;
+ while (m_l) {
+ m = find_match(m_l->m->u.name);
+ if (!m)
+ print_bug("Match not found");
+ m->print(hlp, m_l->m);
+ m_l = m_l->next;
+ }
+ w_l = hlp->w_list;
+ while (w_l) {
+ w = find_watcher(w_l->w->u.name);
+ if (!w)
+ print_bug("Watcher not found");
+ w->print(hlp, w_l->w);
+ w_l = w_l->next;
+ }
+
+ printf("target: ");
+ t = find_target(hlp->t->u.name);
+ if (!t)
+ print_bug("Target not found");
+ t->print(hlp, hlp->t);
+ printf(", count = %llu",
+ replace.counters[replace.counter_entry[hooknr] + i].pcnt);
+ printf("\n");
+ hlp = hlp->next;
+ }
+}
+
+// parse the chain name and return the corresponding nr
+int get_hooknr(char* arg)
+{
+ int i;
+
+ // database is special case (not really a chain)
+ if (!strcmp(arg, DATABASEHOOKNAME))
+ return DATABASEHOOKNR;
+
+ for (i = 0; i < NF_BR_NUMHOOKS; i++)
+ if (!strcmp(arg, hooknames[i]))
+ return i;
+ return -1;
+}
+
+// yup, print out help
+void print_help()
+{
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+
+ printf(
+"%s v%s\n"
+"Usage:\n"
+"ebtables -[ADI] chain rule-specification [options]\n"
+"ebtables -P chain target\n"
+"ebtables -[LFZ] [chain]\n"
+"ebtables -[b] [y,n]\n"
+"Commands:\n"
+"--append -A chain : Append to chain\n"
+"--delete -D chain : Delete matching rule from chain\n"
+"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
+"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
+"--list -L [chain] : List the rules in a chain or in all chains\n"
+"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
+"--flush -F [chain] : Delete all rules in chain or in all chains\n"
+"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
+"--policy -P chain target : Change policy on chain to target\n"
+"Options:\n"
+"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
+"--src -s [!] address[/mask]: source mac address\n"
+"--dst -d [!] address[/mask]: destination mac address\n"
+"--in-if -i [!] name : network input interface name\n"
+"--out-if -o [!] name : network output interface name\n"
+"--logical-in [!] name : logical bridge input interface name\n"
+"--logical-out [!] name : logical bridge output interface name\n"
+"--version -V : print package version\n"
+"\n" ,
+ prog_name,
+ prog_version);
+
+ m_l = new_entry->m_list;
+ while (m_l) {
+ ((struct ebt_u_match *)m_l->m)->help();
+ printf("\n");
+ m_l = m_l->next;
+ }
+ w_l = new_entry->w_list;
+ while (w_l) {
+ ((struct ebt_u_watcher *)w_l->w)->help();
+ printf("\n");
+ w_l = w_l->next;
+ }
+ ((struct ebt_u_target *)new_entry->t)->help();
+ printf("\n");
+ if (table->help)
+ table->help(hooknames);
+ exit(0);
+}
+
+// execute command L
+static void list_rules()
+{
+ int i;
+
+ printf("Bridge table: %s\n", table->name);
+ if (replace.selected_hook != -1) list_em(replace.selected_hook);
+ else
+ for (i = 0; i < NF_BR_NUMHOOKS; i++)
+ if (replace.valid_hooks & (1 << i))
+ list_em(i);
+ return;
+}
+
+// execute command P
+static void change_policy(int policy)
+{
+ int i;
+
+ // don't do anything if the policy is the same
+ if (replace.hook_entry[replace.selected_hook]->policy != policy) {
+ replace.hook_entry[replace.selected_hook]->policy = policy;
+ replace.num_counters = replace.nentries;
+ if (replace.nentries) {
+ // '+ 1' for the CNT_END
+ if (!(counterchanges = (unsigned short *) malloc(
+ (replace.nentries + 1) * sizeof(unsigned short))))
+ print_memory();
+ // done nothing special to the rules
+ for (i = 0; i < replace.nentries; i++)
+ counterchanges[i] = CNT_NORM;
+ counterchanges[replace.nentries] = CNT_END;
+ }
+ else
+ counterchanges = NULL;
+ }
+ else
+ exit(0);
+}
+
+// flush one chain or the complete table
+static void flush_chains()
+{
+ int i, j, oldnentries;
+ unsigned short *cnt;
+ struct ebt_u_entry *u_e, *tmp;
+
+ // flush whole table
+ if (replace.selected_hook == -1) {
+ if (replace.nentries == 0)
+ exit(0);
+ replace.nentries = 0;
+ // no need for the kernel to give us counters back
+ replace.num_counters = 0;
+ // free everything and zero (n)entries
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+ if (!(replace.valid_hooks & (1 << i)))
+ continue;
+ replace.hook_entry[i]->nentries = 0;
+ u_e = replace.hook_entry[i]->entries;
+ while (u_e) {
+ free_u_entry(u_e);
+ tmp = u_e->next;
+ free(u_e);
+ u_e = tmp;
+ }
+ replace.hook_entry[i]->entries = NULL;
+ }
+ return;
+ }
+
+ if (replace.hook_entry[replace.selected_hook]->nentries == 0)
+ exit(0);
+ oldnentries = replace.nentries;
+ replace.nentries = replace.nentries -
+ replace.hook_entry[replace.selected_hook]->nentries;
+
+ // delete the counters belonging to the specified chain
+ if (replace.nentries) {
+ // +1 for CNT_END
+ if ( !(counterchanges = (unsigned short *)
+ malloc((oldnentries + 1) * sizeof(unsigned short))) )
+ print_memory();
+ cnt = counterchanges;
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+ if (!(replace.valid_hooks & (1 << i)))
+ continue;
+ for (j = 0; j < replace.hook_entry[i]->nentries; j++) {
+ if (i != replace.selected_hook)
+ *cnt = CNT_NORM;
+ else
+ *cnt = CNT_DEL;
+ cnt++;
+ }
+ }
+ *cnt = CNT_END;
+ replace.num_counters = oldnentries;
+ }
+ else
+ replace.num_counters = 0;
+
+ replace.hook_entry[replace.selected_hook]->nentries = 0;
+ u_e = replace.hook_entry[replace.selected_hook]->entries;
+ while (u_e) {
+ free_u_entry(u_e);
+ tmp = u_e->next;
+ free(u_e);
+ u_e = tmp;
+ }
+ replace.hook_entry[replace.selected_hook]->entries = NULL;
+}
+
+// -1 == no match
+static int check_rule_exists(int rule_nr)
+{
+ struct ebt_u_entry *u_e;
+ struct ebt_u_match_list *m_l, *m_l2;
+ struct ebt_u_match *m;
+ struct ebt_u_watcher_list *w_l, *w_l2;
+ struct ebt_u_watcher *w;
+ struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
+ int i, j, k;
+
+ // handle '-D chain rulenr' command
+ if (rule_nr != -1) {
+ if (rule_nr >
+ replace.hook_entry[replace.selected_hook]->nentries)
+ return 0;
+ // user starts counting from 1
+ return rule_nr - 1;
+ }
+ u_e = replace.hook_entry[replace.selected_hook]->entries;
+ // check for an existing rule (if there are duplicate rules,
+ // take the first occurance)
+ for (i = 0; i < replace.hook_entry[replace.selected_hook]->nentries;
+ i++, u_e = u_e->next) {
+ if (!u_e)
+ print_bug("Hmm, trouble");
+ if ( u_e->ethproto == new_entry->ethproto
+ && !strcmp(u_e->in, new_entry->in)
+ && !strcmp(u_e->out, new_entry->out)
+ && u_e->bitmask == new_entry->bitmask) {
+ if (new_entry->bitmask & EBT_SOURCEMAC &&
+ strcmp(u_e->sourcemac, new_entry->sourcemac))
+ continue;
+ if (new_entry->bitmask & EBT_DESTMAC &&
+ strcmp(u_e->destmac, new_entry->destmac))
+ continue;
+ if (new_entry->bitmask != u_e->bitmask ||
+ new_entry->invflags != u_e->invflags)
+ continue;
+ // compare all matches
+ m_l = new_entry->m_list;
+ j = 0;
+ while (m_l) {
+ m = (struct ebt_u_match *)(m_l->m);
+ m_l2 = u_e->m_list;
+ while (m_l2 &&
+ strcmp(m_l2->m->u.name, m->m->u.name))
+ m_l2 = m_l2->next;
+ if (!m_l2 || !m->compare(m->m, m_l2->m))
+ goto letscontinue;
+ j++;
+ m_l = m_l->next;
+ }
+ // now be sure they have the same nr of matches
+ k = 0;
+ m_l = u_e->m_list;
+ while (m_l) {
+ k++;
+ m_l = m_l->next;
+ }
+ if (j != k)
+ continue;
+
+ // compare all watchers
+ w_l = new_entry->w_list;
+ j = 0;
+ while (w_l) {
+ w = (struct ebt_u_watcher *)(w_l->w);
+ w_l2 = u_e->w_list;
+ while (w_l2 &&
+ strcmp(w_l2->w->u.name, w->w->u.name))
+ w_l2 = w_l2->next;
+ if (!w_l2 || !w->compare(w->w, w_l2->w))
+ goto letscontinue;
+ j++;
+ w_l = w_l->next;
+ }
+ k = 0;
+ w_l = u_e->w_list;
+ while (w_l) {
+ k++;
+ w_l = w_l->next;
+ }
+ if (j != k)
+ continue;
+ if (strcmp(t->t->u.name, u_e->t->u.name))
+ continue;
+ if (!t->compare(t->t, u_e->t))
+ continue;
+ return i;
+ }
+letscontinue:
+ }
+ return -1;
+}
+
+// execute command A
+static void add_rule(int rule_nr)
+{
+ int i, j;
+ struct ebt_u_entry *u_e, *u_e2;
+ unsigned short *cnt;
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+
+ if (rule_nr != -1) { // command -I
+ if (--rule_nr >
+ replace.hook_entry[replace.selected_hook]->nentries)
+ print_error("rule nr too high: %d > %d", rule_nr,
+ replace.hook_entry[replace.selected_hook]->nentries);
+ } else
+ rule_nr = replace.hook_entry[replace.selected_hook]->nentries;
+ // we're adding one rule
+ replace.num_counters = replace.nentries;
+ replace.nentries++;
+ replace.hook_entry[replace.selected_hook]->nentries++;
+
+ // handle counter stuff
+ // +1 for CNT_END
+ if ( !(counterchanges = (unsigned short *)
+ malloc((replace.nentries + 1) * sizeof(unsigned short))) )
+ print_memory();
+ cnt = counterchanges;
+ for (i = 0; i < replace.selected_hook; i++) {
+ if (!(replace.valid_hooks & (1 << i)))
+ continue;
+ for (j = 0; j < replace.hook_entry[i]->nentries; j++) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ }
+ for (i = 0; i < rule_nr; i++) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ *cnt = CNT_ADD;
+ cnt++;
+ while (cnt != counterchanges + replace.nentries) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ *cnt = CNT_END;
+
+ // go to the right position in the chain
+ u_e2 = NULL;
+ u_e = replace.hook_entry[replace.selected_hook]->entries;
+ for (i = 0; i < rule_nr; i++) {
+ u_e2 = u_e;
+ u_e = u_e->next;
+ }
+ // insert the rule
+ if (u_e2)
+ u_e2->next = new_entry;
+ else
+ replace.hook_entry[replace.selected_hook]->entries = new_entry;
+ new_entry->next = u_e;
+
+ // put the ebt_[match, watcher, target] pointers in place
+ m_l = new_entry->m_list;
+ while (m_l) {
+ m_l->m = ((struct ebt_u_match *)m_l->m)->m;
+ m_l = m_l->next;
+ }
+ w_l = new_entry->w_list;
+ while (w_l) {
+ w_l->w = ((struct ebt_u_watcher *)w_l->w)->w;
+ w_l = w_l->next;
+ }
+ new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
+}
+
+// execute command D
+static void delete_rule(int rule_nr)
+{
+ int i, j, lentmp = 0;
+ unsigned short *cnt;
+ struct ebt_u_entry *u_e, *u_e2;
+
+ if ( (i = check_rule_exists(rule_nr)) == -1 )
+ print_error("Sorry, rule does not exists");
+
+ // we're deleting a rule
+ replace.num_counters = replace.nentries;
+ replace.nentries--;
+
+ if (replace.nentries) {
+ for (j = 0; j < replace.selected_hook; j++) {
+ if (!(replace.valid_hooks & (1 << j)))
+ continue;
+ lentmp += replace.hook_entry[j]->nentries;
+ }
+ lentmp += i;
+ // +1 for CNT_END
+ if ( !(counterchanges = (unsigned short *)malloc(
+ (replace.num_counters + 1) * sizeof(unsigned short))) )
+ print_memory();
+ cnt = counterchanges;
+ for (j = 0; j < lentmp; j++) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ *cnt = CNT_DEL;
+ cnt++;
+ for (j = 0; j < replace.num_counters - lentmp; j++) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ *cnt = CNT_END;
+ }
+ else
+ replace.num_counters = 0;
+
+ // go to the right position in the chain
+ u_e2 = NULL;
+ u_e = replace.hook_entry[replace.selected_hook]->entries;
+ for (j = 0; j < i; j++) {
+ u_e2 = u_e;
+ u_e = u_e->next;
+ }
+
+ // remove from the chain
+ if (u_e2)
+ u_e2->next = u_e->next;
+ else
+ replace.hook_entry[replace.selected_hook]->entries = u_e->next;
+
+ replace.hook_entry[replace.selected_hook]->nentries--;
+ // free everything
+ free_u_entry(u_e);
+ free(u_e);
+}
+
+// execute command Z
+void zero_counters(int zerochain)
+{
+
+ if (zerochain == -1) {
+ // tell main() we don't update the counters
+ // this results in tricking the kernel to zero his counters,
+ // naively expecting userspace to update its counters. Muahahaha
+ counterchanges = NULL;
+ replace.num_counters = 0;
+ } else {
+ int i, j;
+ unsigned short *cnt;
+
+ if (replace.hook_entry[zerochain]->nentries == 0)
+ exit(0);
+ counterchanges = (unsigned short *)
+ malloc((replace.nentries + 1) * sizeof(unsigned short));
+ if (!counterchanges)
+ print_memory();
+ cnt = counterchanges;
+ for (i = 0; i < zerochain; i++) {
+ if (!(replace.valid_hooks & (1 << i)))
+ continue;
+ for (j = 0; j < replace.hook_entry[i]->nentries; j++) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ }
+ for (i = 0; i < replace.hook_entry[zerochain]->nentries; i++) {
+ *cnt = CNT_ZERO;
+ cnt++;
+ }
+ while (cnt != counterchanges + replace.nentries) {
+ *cnt = CNT_NORM;
+ cnt++;
+ }
+ *cnt = CNT_END;
+ }
+}
+
+// list the database (optionally compiled into the kernel)
+static void list_db()
+{
+ struct brdb_dbinfo nr;
+ struct brdb_dbentry *db;
+ char name[21];
+ int i;
+
+ get_dbinfo(&nr);
+
+ // 0 : database disabled (-db n)
+ if (!(nr.nentries))
+ print_error("Database not present"
+ " (disabled), try ebtables --db y");
+ nr.nentries--;
+ if (!nr.nentries) print_error("Database empty");
+ if ( !(db = (struct brdb_dbentry *)
+ malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
+ print_memory();
+
+ get_db(nr.nentries, db);
+ printf("number of entries: %d\n", nr.nentries);
+ for (i = 0; i < nr.nentries; i++) {
+ printf(
+ "%d:\n"
+ "hook : %s\n"
+ "in-if : %s\n"
+ "out-if : %s\n"
+ "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
+ if (db->ethproto == IDENTIFY802_3)
+ printf("802.2/802.3 STYLE LENGTH FIELD\n");
+ else {
+ if (number_to_name(ntohs(db->ethproto), name))
+ printf("%x\n",ntohs(db->ethproto));
+ else
+ printf("%s\n", name);
+ }
+ db++;
+ }
+ exit(0);
+}
+
+// handle db [dis,en]abling
+static void allowdb(char yorn)
+{
+ __u16 decision;
+
+ if (yorn != 'y' && yorn != 'n')
+ print_error("Option [y] or [n] needed");
+
+ if (yorn == 'y')
+ decision = BRDB_DB;
+ else
+ decision = BRDB_NODB;
+
+ deliver_allowdb(&decision);
+
+ exit(0);
+}
+
+// set ethproto
+int name_to_protocol(char *name)
+{
+ FILE *ifp;
+ char buffer[21], value[5], *bfr;
+ unsigned short i;
+
+ if (!strcasecmp("LENGTH", name)) {
+ new_entry->ethproto = 0;
+ new_entry->bitmask |= EBT_802_3;
+ return 1;
+ }
+ if ( !(ifp = fopen(PROTOCOLFILE, "r")) )
+ return -1;
+ while (1) {
+ if (get_a_line(buffer, value, ifp)) return -1;
+ if (strcasecmp(buffer, name))
+ continue;
+ i = (unsigned short) strtol(value, &bfr, 16);
+ if (*bfr != '\0')
+ return -1;
+ new_entry->ethproto = i;
+ fclose(ifp);
+ return 0;
+ }
+ return -1;
+}
+
+// put the mac address into 6 (ETH_ALEN) bytes
+int getmac(char *from, char *to)
+{
+ int i, tmp;
+ char *buffer;
+
+ if (strlen(from) != 3 * ETH_ALEN - 1)
+ return -1;
+ for (i = 1; i < ETH_ALEN; i++) {
+ if (from[i*3 - 1] != ':')
+ return -1;
+ from[i*3 - 1] = '\0';
+ }
+ for (i = 0; i < ETH_ALEN; i++) {
+ tmp = strtol(from + i*3, &buffer, 16);
+ if (*buffer != '\0' || tmp > 255 || tmp < 0)
+ return -1;
+ to[i] = (unsigned char) tmp;
+ }
+ return 0;
+}
+
+int getmac_and_mask(char *from, char *to, char *mask)
+{
+ char *p;
+ int i;
+
+ if (strcasecmp(from, "Unicast") == 0) {
+ memcpy(to, mac_type_unicast, ETH_ALEN);
+ memcpy(mask, msk_type_unicast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "Multicast") == 0) {
+ memcpy(to, mac_type_multicast, ETH_ALEN);
+ memcpy(mask, msk_type_multicast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "Broadcast") == 0) {
+ memcpy(to, mac_type_broadcast, ETH_ALEN);
+ memcpy(mask, msk_type_broadcast, ETH_ALEN);
+ return 0;
+ }
+ if ( (p = strrchr(from, '/')) != NULL) {
+ *p = '\0';
+ if (getmac(p + 1, mask))
+ return -1;
+ } else
+ memset(mask, 0xff, ETH_ALEN);
+ if (getmac(from, to))
+ return -1;
+ for (i = 0; i < ETH_ALEN; i++)
+ to[i] &= mask[i];
+ return 0;
+}
+
+int check_inverse(const char option[])
+{
+ if (strcmp(option, "!") == 0) {
+ optind++;
+ return 1;
+ }
+ return 0;
+}
+
+void check_option(unsigned int *flags, unsigned int mask)
+{
+ if (*flags & mask)
+ print_error("Multiple use of same option not allowed");
+ *flags |= mask;
+}
+
+#define OPT_COMMAND 0x01
+#define OPT_TABLE 0x02
+#define OPT_IN 0x04
+#define OPT_OUT 0x08
+#define OPT_JUMP 0x10
+#define OPT_PROTOCOL 0x20
+#define OPT_SOURCE 0x40
+#define OPT_DEST 0x80
+#define OPT_ZERO 0x100
+#define OPT_LOGICALIN 0x200
+#define OPT_LOGICALOUT 0x400
+// the main thing
+int main(int argc, char *argv[])
+{
+ char *buffer, allowbc = 'n';
+ int c, i;
+ // this special one for the -Z option (we can have -Z <this> -L <that>)
+ int zerochain = -1;
+ int policy = -1;
+ int rule_nr = -1;// used for -D chain number
+ struct ebt_u_target *t;
+ struct ebt_u_match *m;
+ struct ebt_u_watcher *w;
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+
+ // initialize the table name, OPT_ flags, selected hook and command
+ strcpy(replace.name, "filter");
+ replace.flags = 0;
+ replace.selected_hook = -1;
+ replace.command = 'h';
+
+ new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
+ if (!new_entry)
+ print_memory();
+ // put some sane values in our new entry
+ initialize_entry(new_entry);
+
+ // getopt saves the day
+ while ((c = getopt_long(argc, argv,
+ "-A:D:I:L::Z::F::P:Vhi:o:j:p:b:s:d:t:", ebt_options, NULL)) != -1) {
+ switch (c) {
+
+ case 'A': // add a rule
+ case 'D': // delete a rule
+ case 'P': // define policy
+ case 'I': // insert a rule
+ replace.command = c;
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.flags |= OPT_COMMAND;
+ if ((replace.selected_hook = get_hooknr(optarg)) == -1)
+ print_error("Bad chain");
+ if (c == 'D' && optind < argc &&
+ argv[optind][0] != '-') {
+ rule_nr = strtol(argv[optind], &buffer, 10);
+ if (*buffer != '\0' || rule_nr < 0)
+ print_error("Problem with the "
+ "specified rule number");
+ optind++;
+ }
+ if (c == 'P') {
+ if (optind >= argc)
+ print_error("No policy specified");
+ for (i = 0; i < 2; i++)
+ if (!strcmp(argv[optind],
+ standard_targets[i])) {
+ policy = i;
+ break;
+ }
+ if (policy == -1)
+ print_error("Wrong policy");
+ optind++;
+ }
+ if (c == 'I') {
+ if (optind >= argc)
+ print_error("No rulenr for -I"
+ " specified");
+ rule_nr = strtol(argv[optind], &buffer, 10);
+ if (*buffer != '\0' || rule_nr < 0)
+ print_error("Problem with the specified"
+ " rule number");
+ optind++;
+ }
+ break;
+
+ case 'L': // list
+ case 'F': // flush
+ case 'Z': // zero counters
+ if (c == 'Z') {
+ if (replace.flags & OPT_ZERO)
+ print_error("Multiple commands"
+ " not allowed");
+ if ( (replace.flags & OPT_COMMAND &&
+ replace.command != 'L'))
+ print_error("command -Z only allowed "
+ "together with command -L");
+ replace.flags |= OPT_ZERO;
+ } else {
+ replace.command = c;
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands"
+ " not allowed");
+ replace.flags |= OPT_COMMAND;
+ }
+ i = -1;
+ if (optarg) {
+ if ( (i = get_hooknr(optarg)) == -1 )
+ print_error("Bad chain");
+ } else
+ if (optind < argc && argv[optind][0] != '-') {
+ if ((i = get_hooknr(argv[optind]))
+ == -1)
+ print_error("Bad chain");
+ optind++;
+ }
+ if (i != -1) {
+ if (c == 'Z')
+ zerochain = i;
+ else
+ replace.selected_hook = i;
+ }
+ break;
+
+ case 'V': // version
+ replace.command = 'V';
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ printf("%s, %s\n", prog_name, prog_version);
+ exit(0);
+
+ case 'h': // help
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.command = 'h';
+ // All other arguments should be extension names
+ while (optind < argc) {
+ struct ebt_u_match *m;
+ struct ebt_u_watcher *w;
+
+ if ((m = find_match(argv[optind])))
+ add_match(m);
+ else if ((w = find_watcher(argv[optind])))
+ add_watcher(w);
+ else {
+ if (!(t = find_target(argv[optind])))
+ print_error("Extension %s "
+ "not found", argv[optind]);
+ if (replace.flags & OPT_JUMP)
+ print_error("Sorry, you can "
+ "only see help for one "
+ "target extension each time");
+ replace.flags |= OPT_JUMP;
+ new_entry->t =
+ (struct ebt_entry_target *)t;
+ }
+ optind++;
+ }
+ break;
+
+ case 't': // table
+ check_option(&replace.flags, OPT_TABLE);
+ if (strlen(optarg) > EBT_TABLE_MAXNAMELEN)
+ print_error("Table name too long");
+ strcpy(replace.name, optarg);
+ break;
+
+ case 'i': // input interface
+ case 2 : // logical input interface
+ case 'o': // output interface
+ case 3 : // logical output interface
+ case 'j': // target
+ case 'p': // net family protocol
+ case 's': // source mac
+ case 'd': // destination mac
+ if ((replace.flags & OPT_COMMAND) == 0)
+ print_error("No command specified");
+ if ( replace.command != 'A' &&
+ replace.command != 'D' && replace.command != 'I')
+ print_error("Command and option do not match");
+ if (c == 'i') {
+ check_option(&replace.flags, OPT_IN);
+ if (replace.selected_hook > 2 &&
+ replace.selected_hook < NF_BR_BROUTING)
+ print_error("Use in-interface only in "
+ "INPUT, FORWARD, PREROUTING and"
+ "BROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_IIN;
+
+ if (optind > argc)
+ print_error("No in-interface "
+ "specified");
+ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
+ print_error("Illegal interfacelength");
+ strcpy(new_entry->in, argv[optind - 1]);
+ break;
+ }
+ if (c == 2) {
+ check_option(&replace.flags, OPT_LOGICALIN);
+ if (replace.selected_hook > 2 &&
+ replace.selected_hook < NF_BR_BROUTING)
+ print_error("Use logical in-interface "
+ "only in INPUT, FORWARD, "
+ "PREROUTING and BROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_ILOGICALIN;
+
+ if (optind > argc)
+ print_error("No logical in-interface "
+ "specified");
+ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
+ print_error("Illegal interfacelength");
+ strcpy(new_entry->logical_in, argv[optind - 1]);
+ break;
+ }
+ if (c == 'o') {
+ check_option(&replace.flags, OPT_OUT);
+ if (replace.selected_hook < 2)
+ print_error("Use out-interface only"
+ " in OUTPUT, FORWARD and "
+ "POSTROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_IOUT;
+
+ if (optind > argc)
+ print_error("No out-interface "
+ "specified");
+
+ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
+ print_error("Illegal interface "
+ "length");
+ strcpy(new_entry->out, argv[optind - 1]);
+ break;
+ }
+ if (c == 3) {
+ check_option(&replace.flags, OPT_LOGICALOUT);
+ if (replace.selected_hook < 2)
+ print_error("Use logical out-interface "
+ "only in OUTPUT, FORWARD and "
+ "POSTROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_ILOGICALOUT;
+
+ if (optind > argc)
+ print_error("No logical out-interface "
+ "specified");
+
+ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
+ print_error("Illegal interface "
+ "length");
+ strcpy(new_entry->logical_out,
+ argv[optind - 1]);
+ break;
+ }
+ if (c == 'j') {
+
+ check_option(&replace.flags, OPT_JUMP);
+ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
+ if (!strcmp(optarg,
+ standard_targets[i])) {
+ t = find_target(
+ EBT_STANDARD_TARGET);
+ ((struct ebt_standard_target *)
+ t->t)->verdict = i;
+ break;
+ }
+ // must be an extension then
+ if (i == NUM_STANDARD_TARGETS) {
+ struct ebt_u_target *t;
+ t = find_target(optarg);
+ // -j standard not allowed either
+ if (!t || t ==
+ (struct ebt_u_target *)new_entry->t)
+ print_error("Illegal target "
+ "name");
+ new_entry->t =
+ (struct ebt_entry_target *)t;
+ }
+ break;
+ }
+ if (c == 's') {
+ check_option(&replace.flags, OPT_SOURCE);
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_ISOURCE;
+
+ if (optind > argc)
+ print_error("No source mac "
+ "specified");
+ if (getmac_and_mask(argv[optind - 1],
+ new_entry->sourcemac, new_entry->sourcemsk))
+ print_error("Problem with specified "
+ "source mac");
+ new_entry->bitmask |= EBT_SOURCEMAC;
+ break;
+ }
+ if (c == 'd') {
+ check_option(&replace.flags, OPT_DEST);
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_IDEST;
+
+ if (optind > argc)
+ print_error("No destination mac "
+ "specified");
+ if (getmac_and_mask(argv[optind - 1],
+ new_entry->destmac, new_entry->destmsk))
+ print_error("Problem with specified "
+ "destination mac");
+ new_entry->bitmask |= EBT_DESTMAC;
+ break;
+ }
+ check_option(&replace.flags, OPT_PROTOCOL);
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_IPROTO;
+
+ if (optind > argc)
+ print_error("No protocol specified");
+ new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
+ i = strtol(argv[optind - 1], &buffer, 16);
+ if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
+ print_error("Problem with the specified "
+ "protocol");
+ new_entry->ethproto = i;
+ if (*buffer != '\0')
+ if (name_to_protocol(argv[optind - 1]) == -1)
+ print_error("Problem with the specified"
+ " protocol");
+ if (new_entry->ethproto < 1536 &&
+ !(new_entry->bitmask & EBT_802_3))
+ print_error("Sorry, protocols have values above"
+ " or equal to 1536 (0x0600)");
+ break;
+
+ case 'b': // allow database?
+ if (replace.flags & OPT_COMMAND)
+ print_error("Multiple commands not allowed");
+ replace.command = c;
+ allowbc = *optarg;
+ break;
+
+ default:
+
+ // is it a target option?
+ t = (struct ebt_u_target *)new_entry->t;
+ if ((t->parse(c - t->option_offset, argv, argc,
+ new_entry, &t->flags, &t->t)))
+ continue;
+
+ // is it a match_option?
+ for (m = matches; m; m = m->next)
+ if (m->parse(c - m->option_offset, argv,
+ argc, new_entry, &m->flags, &m->m))
+ break;
+
+ if (m != NULL) {
+ if (m->used == 0)
+ add_match(m);
+ continue;
+ }
+
+ // is it a watcher option?
+ for (w = watchers; w; w = w->next)
+ if (w->parse(c-w->option_offset, argv,
+ argc, new_entry, &w->flags, &w->w))
+ break;
+
+ if (w == NULL)
+ print_error("Unknown argument");
+ if (w->used == 0)
+ add_watcher(w);
+ }
+ }
+
+ // database stuff before ebtables stuff
+ if (replace.command == 'b')
+ allowdb(allowbc);
+ if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
+ list_db();
+
+ if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
+ replace.flags & OPT_ZERO )
+ print_error("Command -Z only allowed together with command -L");
+
+ if (replace.command == 'A' || replace.command == 'I' ||
+ replace.command == 'D') {
+ if (replace.selected_hook == -1)
+ print_error("Not enough information");
+ }
+
+ if ( !(table = find_table(replace.name)) )
+ print_error("Bad table name");
+
+ // do this after parsing everything, so we can print specific info
+ if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
+ print_help();
+
+ // do the final checks
+ m_l = new_entry->m_list;
+ w_l = new_entry->w_list;
+ t = (struct ebt_u_target *)new_entry->t;
+ while (m_l) {
+ m = (struct ebt_u_match *)(m_l->m);
+ m->final_check(new_entry, m->m, replace.name,
+ replace.selected_hook);
+ m_l = m_l->next;
+ }
+ while (w_l) {
+ w = (struct ebt_u_watcher *)(w_l->w);
+ w->final_check(new_entry, w->w, replace.name,
+ replace.selected_hook);
+ w_l = w_l->next;
+ }
+ t->final_check(new_entry, t->t, replace.name, replace.selected_hook);
+
+ // so, the extensions can work with the host endian
+ // the kernel does not have to do this ofcourse
+ new_entry->ethproto = htons(new_entry->ethproto);
+
+ // get the kernel's information
+ get_table(&replace);
+ // check if selected_hook is a valid_hook
+ if (replace.selected_hook >= 0 &&
+ !(replace.valid_hooks & (1 << replace.selected_hook)))
+ print_error("Bad chain name");
+ if (replace.command == 'P')
+ change_policy(policy);
+ else if (replace.command == 'L') {
+ list_rules();
+ if (replace.flags & OPT_ZERO)
+ zero_counters(zerochain);
+ else
+ exit(0);
+ }
+ if (replace.flags & OPT_ZERO)
+ zero_counters(zerochain);
+ else if (replace.command == 'F')
+ flush_chains();
+ else if (replace.command == 'A' || replace.command == 'I')
+ add_rule(rule_nr);
+ else if (replace.command == 'D')
+ delete_rule(rule_nr);
+
+ if (table->check)
+ table->check(&replace);
+
+ deliver_table(&replace);
+
+ if (counterchanges)
+ deliver_counters(&replace, counterchanges);
+ return 0;
+}
diff --git a/userspace/ebtables2/ethertypes b/userspace/ebtables2/ethertypes
new file mode 100644
index 0000000..0123bf3
--- /dev/null
+++ b/userspace/ebtables2/ethertypes
@@ -0,0 +1,34 @@
+# all whitespace is ignored
+# comment lines must have a '#' as the first character
+# all protocol numbers are in hexadecimal form
+# maximum namesize = 20 characters
+# always put tabs or spaces between the name and the protocol number
+# don't use more than 4 digits for the protocol number
+# programs using this file should not be case sensitive
+# that's all :-))
+IPV4 0800 put your comments behind, on the same line, after a tab
+X25 0800 or whitespace
+ARP 0806
+802_1Q 8100 802.1Q Virtual LAN tagged frame
+IPX 8137
+IPV6 86DD
+NetBEUI 8191
+BPQ 08FF G8BPQ AX.25 Ethernet Packet
+DEC 6000 DEC Assigned proto
+DNA_DL 6001 DEC DNA Dump/Load
+DNA_RC 6002 DEC DNA Remote Console
+DNA_RT 6003 DEC DNA Routing
+LAT 6004 DEC LAT
+DIAG 6005 DEC Diagnostics
+CUST 6006 DEC Customer use
+SCA 6007 DEC Systems Comms Arch
+RARP 8035 Reverse Addr Res packet
+ATALK 809B Appletalk DDP
+AARP 80F3 Appletalk AARP
+IPX 8137 IPX over DIX
+PPP_DISC 8863 PPPoE discovery messages
+PPP_SES 8864 PPPoE session messages
+ATMMPOA 884C MultiProtocol over ATM
+ATMFATE 8884 Frame-based ATM Transport over Ethernet
+
+
diff --git a/userspace/ebtables2/extensions/Makefile b/userspace/ebtables2/extensions/Makefile
new file mode 100644
index 0000000..109af35
--- /dev/null
+++ b/userspace/ebtables2/extensions/Makefile
@@ -0,0 +1,12 @@
+#! /usr/bin/make
+
+EXT_FUNC+=nat arp ip standard log redirect vlan
+EXT_TABLES+=filter nat broute
+EXT_OBJS+=$(foreach T,$(EXT_FUNC), extensions/ebt_$(T).o)
+EXT_OBJS+=$(foreach T,$(EXT_TABLES), extensions/ebtable_$(T).o)
+
+extensions/ebt_%.o: extensions/ebt_%.c include/ebtables_u.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+extensions/ebtable_%.o: extensions/ebtable_%.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
diff --git a/userspace/ebtables2/extensions/ebt_arp.c b/userspace/ebtables2/extensions/ebt_arp.c
new file mode 100644
index 0000000..0e22b0b
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebt_arp.c
@@ -0,0 +1,289 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <getopt.h>
+#include "../include/ebtables_u.h"
+#include <linux/netfilter_bridge/ebt_arp.h>
+
+#define ARP_OPCODE '1'
+#define ARP_HTYPE '2'
+#define ARP_PTYPE '3'
+#define ARP_IP_S '4'
+#define ARP_IP_D '5'
+static struct option opts[] =
+{
+ { "arp-opcode" , required_argument, 0, ARP_OPCODE },
+ { "arp-op" , required_argument, 0, ARP_OPCODE },
+ { "arp-htype" , required_argument, 0, ARP_HTYPE },
+ { "arp-ptype" , required_argument, 0, ARP_PTYPE },
+ { "arp-ip-src" , required_argument, 0, ARP_IP_S },
+ { "arp-ip-dst" , required_argument, 0, ARP_IP_D },
+ { 0 }
+};
+
+// a few names
+static char *opcodes[] =
+{
+ "Request",
+ "Reply",
+ "Request Reverse",
+ "Reply Reverse",
+ "DRARP Request",
+ "DRARP Reply",
+ "DRARP Error",
+ "InARP Request",
+ "ARP NAK",
+ ""
+};
+
+static void print_help()
+{
+ int i = 0;
+
+ printf(
+"arp options:\n"
+"--arp-opcode opcode : ARP opcode (integer or string)\n"
+"--arp-htype type : ARP hardware type (integer or string)\n"
+"--arp-ptype type : ARP protocol type (hexadecimal or string)\n"
+"--arp-ip-src [!] address[/mask]: ARP ip source specification\n"
+"--arp-ip-dst [!] address[/mask]: ARP ip target specification\n"
+" opcode strings: \n");
+ while (strcmp(opcodes[i], "")) {
+ printf("%d = %s\n", i + 1, opcodes[i]);
+ i++;
+ }
+ printf(
+" hardware type string: \n 1 = Ethernet\n"
+" protocol type string: \n 0x0800 = IPv4\n");
+}
+
+static void init(struct ebt_entry_match *match)
+{
+ struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data;
+
+ arpinfo->invflags = 0;
+ arpinfo->bitmask = 0;
+}
+
+// defined in ebt_ip.c
+void parse_ip_address(char *address, __u32 *addr, __u32 *msk);
+
+#define OPT_OPCODE 0x01
+#define OPT_HTYPE 0x02
+#define OPT_PTYPE 0x04
+#define OPT_IP_S 0x08
+#define OPT_IP_D 0x10
+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_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data;
+ int i;
+ char *end;
+ __u32 *addr;
+ __u32 *mask;
+
+ switch (c) {
+ case ARP_OPCODE:
+ check_option(flags, OPT_OPCODE);
+ if (check_inverse(optarg))
+ arpinfo->invflags |= EBT_ARP_OPCODE;
+
+ if (optind > argc)
+ print_error("Missing arp opcode argument");
+ i = strtol(argv[optind - 1], &end, 10);
+ if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
+ i = 0;
+ while (strcmp(opcodes[i], "")) {
+ if (!strcasecmp(opcodes[i], optarg))
+ break;
+ i++;
+ }
+ if (!strcmp(opcodes[i], ""))
+ print_error("Problem with specified "
+ "arp opcode");
+ }
+ arpinfo->opcode = htons(i);
+ arpinfo->bitmask |= EBT_ARP_OPCODE;
+ break;
+
+ case ARP_HTYPE:
+ check_option(flags, OPT_HTYPE);
+ if (check_inverse(optarg))
+ arpinfo->invflags |= EBT_ARP_HTYPE;
+
+ if (optind > argc)
+ print_error("Missing arp hardware type argument");
+ i = strtol(argv[optind - 1], &end, 10);
+ if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
+ if (!strcasecmp("Ethernet", argv[optind - 1]))
+ i = 1;
+ else
+ print_error("Problem with specified arp "
+ "hardware type");
+ }
+ arpinfo->htype = htons(i);
+ arpinfo->bitmask |= EBT_ARP_HTYPE;
+ break;
+
+ case ARP_PTYPE:
+ check_option(flags, OPT_PTYPE);
+ if (check_inverse(optarg))
+ arpinfo->invflags |= EBT_ARP_PTYPE;
+
+ if (optind > argc)
+ print_error("Missing arp protocol type argument");
+ i = strtol(argv[optind - 1], &end, 16);
+ if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
+ if (!strcasecmp("IPv4", argv[optind - 1]))
+ i = 0x0800;
+ else
+ print_error("Problem with specified arp "
+ "protocol type");
+ }
+ arpinfo->ptype = htons(i);
+ arpinfo->bitmask |= EBT_ARP_PTYPE;
+ break;
+
+ case ARP_IP_S:
+ case ARP_IP_D:
+ if (c == ARP_IP_S) {
+ check_option(flags, OPT_IP_S);
+ addr = &arpinfo->saddr;
+ mask = &arpinfo->smsk;
+ arpinfo->bitmask |= EBT_ARP_SRC_IP;
+ } else {
+ check_option(flags, OPT_IP_D);
+ addr = &arpinfo->daddr;
+ mask = &arpinfo->dmsk;
+ arpinfo->bitmask |= EBT_ARP_DST_IP;
+ }
+ if (check_inverse(optarg)) {
+ if (c == ARP_IP_S)
+ arpinfo->invflags |= EBT_ARP_SRC_IP;
+ else
+ arpinfo->invflags |= EBT_ARP_DST_IP;
+ }
+ if (optind > argc)
+ print_error("Missing ip address argument");
+ parse_ip_address(argv[optind - 1], addr, mask);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void final_check(const struct ebt_u_entry *entry,
+const struct ebt_entry_match *match, const char *name, unsigned int hook)
+{
+ if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 ||
+ (entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP))
+ print_error("For (R)ARP filtering the protocol must be "
+ "specified as ARP or RARP");
+}
+
+// defined in the ebt_ip.c
+char *mask_to_dotted(__u32 mask);
+static void print(const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match)
+{
+ struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data;
+ int i;
+
+ if (arpinfo->bitmask & EBT_ARP_OPCODE) {
+ printf("arp opcode: ");
+ if (arpinfo->invflags & EBT_ARP_OPCODE)
+ printf("! ");
+ printf("%d ", ntohs(arpinfo->opcode));
+ }
+ if (arpinfo->bitmask & EBT_ARP_HTYPE) {
+ printf("arp htype: ");
+ if (arpinfo->invflags & EBT_ARP_HTYPE)
+ printf("! ");
+ printf("%d ", ntohs(arpinfo->htype));
+ }
+ if (arpinfo->bitmask & EBT_ARP_PTYPE) {
+ printf("arp ptype: ");
+ if (arpinfo->invflags & EBT_ARP_PTYPE)
+ printf("! ");
+ printf("0x%x ", ntohs(arpinfo->ptype));
+ }
+ if (arpinfo->bitmask & EBT_ARP_SRC_IP) {
+ printf("arp src IP ");
+ if (arpinfo->invflags & EBT_ARP_SRC_IP)
+ printf("! ");
+ for (i = 0; i < 4; i++)
+ printf("%d%s", ((unsigned char *)&arpinfo->saddr)[i],
+ (i == 3) ? "" : ".");
+ printf("%s, ", mask_to_dotted(arpinfo->smsk));
+ }
+ if (arpinfo->bitmask & EBT_ARP_DST_IP) {
+ printf("arp dst IP ");
+ if (arpinfo->invflags & EBT_ARP_DST_IP)
+ printf("! ");
+ for (i = 0; i < 4; i++)
+ printf("%d%s", ((unsigned char *)&arpinfo->daddr)[i],
+ (i == 3) ? "" : ".");
+ printf("%s, ", mask_to_dotted(arpinfo->dmsk));
+ }
+}
+
+static int compare(const struct ebt_entry_match *m1,
+ const struct ebt_entry_match *m2)
+{
+ struct ebt_arp_info *arpinfo1 = (struct ebt_arp_info *)m1->data;
+ struct ebt_arp_info *arpinfo2 = (struct ebt_arp_info *)m2->data;
+
+ if (arpinfo1->bitmask != arpinfo2->bitmask)
+ return 0;
+ if (arpinfo1->invflags != arpinfo2->invflags)
+ return 0;
+ if (arpinfo1->bitmask & EBT_ARP_OPCODE) {
+ if (arpinfo1->opcode != arpinfo2->opcode)
+ return 0;
+ }
+ if (arpinfo1->bitmask & EBT_ARP_HTYPE) {
+ if (arpinfo1->htype != arpinfo2->htype)
+ return 0;
+ }
+ if (arpinfo1->bitmask & EBT_ARP_PTYPE) {
+ if (arpinfo1->ptype != arpinfo2->ptype)
+ return 0;
+ }
+ if (arpinfo1->bitmask & EBT_ARP_SRC_IP) {
+ if (arpinfo1->saddr != arpinfo2->saddr)
+ return 0;
+ if (arpinfo1->smsk != arpinfo2->smsk)
+ return 0;
+ }
+ if (arpinfo1->bitmask & EBT_ARP_DST_IP) {
+ if (arpinfo1->daddr != arpinfo2->daddr)
+ return 0;
+ if (arpinfo1->dmsk != arpinfo2->dmsk)
+ return 0;
+ }
+ return 1;
+}
+
+static struct ebt_u_match arp_match =
+{
+ EBT_ARP_MATCH,
+ sizeof(struct ebt_arp_info),
+ print_help,
+ init,
+ parse,
+ final_check,
+ print,
+ compare,
+ opts,
+};
+
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_match(&arp_match);
+}
diff --git a/userspace/ebtables2/extensions/ebt_ip.c b/userspace/ebtables2/extensions/ebt_ip.c
new file mode 100644
index 0000000..5d62d3a
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebt_ip.c
@@ -0,0 +1,318 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <getopt.h>
+#include "../include/ebtables_u.h"
+#include <linux/netfilter_bridge/ebt_ip.h>
+
+#define IP_SOURCE '1'
+#define IP_DEST '2'
+#define IP_myTOS '3' // include/bits/in.h seems to already define IP_TOS
+#define IP_PROTO '4'
+
+static struct option opts[] =
+{
+ { "ip-source" , required_argument, 0, IP_SOURCE },
+ { "ip-src" , required_argument, 0, IP_SOURCE },
+ { "ip-destination", required_argument, 0, IP_DEST },
+ { "ip-dst" , required_argument, 0, IP_DEST },
+ { "ip-tos" , required_argument, 0, IP_myTOS },
+ { "ip-protocol" , required_argument, 0, IP_PROTO },
+ { "ip-proto" , required_argument, 0, IP_PROTO },
+ { 0 }
+};
+
+// put the ip string into 4 bytes
+static int undot_ip(char *ip, unsigned char *ip2)
+{
+ char *p, *q, *end;
+ int onebyte, i;
+ char buf[20];
+
+ strncpy(buf, ip, sizeof(buf) - 1);
+
+ p = buf;
+ for (i = 0; i < 3; i++) {
+ if ((q = strchr(p, '.')) == NULL)
+ return -1;
+ *q = '\0';
+ onebyte = strtol(p, &end, 10);
+ if (*end != '\0' || onebyte > 255 || onebyte < 0)
+ return -1;
+ ip2[i] = (unsigned char)onebyte;
+ p = q + 1;
+ }
+
+ onebyte = strtol(p, &end, 10);
+ if (*end != '\0' || onebyte >255 || onebyte < 0)
+ return -1;
+ ip2[3] = (unsigned char)onebyte;
+
+ return 0;
+}
+
+// put the mask into 4 bytes
+static int ip_mask(char *mask, unsigned char *mask2)
+{
+ char *end;
+ int bits;
+ __u32 mask22;
+
+ if (undot_ip(mask, mask2)) {
+ // not the /a.b.c.e format, maybe the /x format
+ bits = strtol(mask, &end, 10);
+ if (*end != '\0' || bits > 32 || bits < 0)
+ return -1;
+ if (bits != 0) {
+ mask22 = htonl(0xFFFFFFFF << (32 - bits));
+ memcpy(mask2, &mask22, 4);
+ } else {
+ mask22 = 0xFFFFFFFF;
+ memcpy(mask2, &mask22, 4);
+ }
+ }
+ return 0;
+}
+
+// set the ip mask and ip address
+void parse_ip_address(char *address, __u32 *addr, __u32 *msk)
+{
+ char *p;
+ int i;
+
+ // first the mask
+ if ((p = strrchr(address, '/')) != NULL) {
+ *p = '\0';
+ i = ip_mask(p + 1, (unsigned char *)msk);
+ if (i)
+ print_error("Problem with the ip mask");
+ }
+ else
+ *msk = 0xFFFFFFFF;
+
+ i = undot_ip(address, (unsigned char *)addr);
+ if (i)
+ print_error("Problem with the ip address");
+ *addr = *addr & *msk;
+}
+
+// transform the ip mask into a string ready for output
+char *mask_to_dotted(__u32 mask)
+{
+ int i;
+ static char buf[20];
+ __u32 maskaddr, bits;
+
+ maskaddr = ntohl(mask);
+
+ // don't print /32
+ if (mask == 0xFFFFFFFFL)
+ return "";
+
+ i = 32;
+ bits = 0xFFFFFFFEL; // case 0xFFFFFFFF has just been dealt with
+ while (--i >= 0 && maskaddr != bits)
+ bits <<= 1;
+
+ if (i > 0)
+ sprintf(buf, "/%d", i);
+ else if (!i)
+ *buf = '\0';
+ else
+ // mask was not a decent combination of 1's and 0's
+ sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
+ ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
+ ((unsigned char *)&mask)[3]);
+
+ return buf;
+}
+
+static void print_help()
+{
+ printf(
+"ip options:\n"
+"--ip-src [!] address[/mask]: ip source specification\n"
+"--ip-dst [!] address[/mask]: ip destination specification\n"
+"--ip-tos [!] tos : ip tos specification\n"
+"--ip-proto [!] protocol : ip protocol specification\n");
+}
+
+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;
+}
+
+#define OPT_SOURCE 0x01
+#define OPT_DEST 0x02
+#define OPT_TOS 0x04
+#define OPT_PROTO 0x08
+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, *buffer;
+ int i;
+
+ switch (c) {
+ case IP_SOURCE:
+ check_option(flags, OPT_SOURCE);
+ ipinfo->bitmask |= EBT_IP_SOURCE;
+
+ case IP_DEST:
+ if (c == IP_DEST) {
+ check_option(flags, OPT_DEST);
+ ipinfo->bitmask |= EBT_IP_DEST;
+ }
+ if (check_inverse(optarg)) {
+ if (c == IP_SOURCE)
+ ipinfo->invflags |= EBT_IP_SOURCE;
+ else
+ ipinfo->invflags |= EBT_IP_DEST;
+ }
+
+ if (optind > argc)
+ print_error("Missing ip address argument");
+ if (c == IP_SOURCE)
+ parse_ip_address(argv[optind - 1], &ipinfo->saddr,
+ &ipinfo->smsk);
+ else
+ parse_ip_address(argv[optind - 1], &ipinfo->daddr,
+ &ipinfo->dmsk);
+ break;
+
+ case IP_myTOS:
+ check_option(flags, OPT_TOS);
+ if (check_inverse(optarg))
+ ipinfo->invflags |= EBT_IP_TOS;
+
+ if (optind > argc)
+ print_error("Missing ip tos argument");
+ i = strtol(argv[optind - 1], &end, 16);
+ if (i < 0 || i > 255 || *buffer != '\0')
+ print_error("Problem with specified ip tos");
+ ipinfo->tos = i;
+ ipinfo->bitmask |= EBT_IP_TOS;
+ break;
+
+ case IP_PROTO:
+ check_option(flags, OPT_PROTO);
+ if (check_inverse(optarg))
+ ipinfo->invflags |= EBT_IP_PROTO;
+ if (optind > argc)
+ print_error("Missing ip protocol argument");
+ i = strtol(argv[optind - 1], &end, 10);
+ if (i < 0 || i > 255 || *end != '\0')
+ print_error("Problem with specified ip protocol");
+ ipinfo->protocol = i;
+ ipinfo->bitmask |= EBT_IP_PROTO;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void final_check(const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match, const char *name, unsigned int hook)
+{
+ if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 ||
+ entry->ethproto != ETH_P_IP)
+ print_error("For IP filtering the protocol must be "
+ "specified as IPv4");
+}
+
+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("source ip: ");
+ 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));
+ }
+ if (ipinfo->bitmask & EBT_IP_DEST) {
+ printf("dest ip: ");
+ if (ipinfo->invflags & EBT_IP_DEST)
+ printf("! ");
+ for (j = 0; j < 4; j++)
+ printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j],
+ (j == 3) ? "" : ".");
+ printf("%s, ", mask_to_dotted(ipinfo->dmsk));
+ }
+ if (ipinfo->bitmask & EBT_IP_TOS) {
+ printf("ip TOS: ");
+ if (ipinfo->invflags & EBT_IP_TOS)
+ printf("! ");
+ printf("0x%02X, ", ipinfo->tos);
+ }
+ if (ipinfo->bitmask & EBT_IP_PROTO) {
+ printf("ip proto: ");
+ if (ipinfo->invflags & EBT_IP_DEST)
+ printf("! ");
+ printf("%d, ", ipinfo->protocol);
+ }
+}
+
+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;
+ }
+ if (ipinfo1->bitmask & EBT_IP_DEST) {
+ if (ipinfo1->daddr != ipinfo2->daddr)
+ return 0;
+ if (ipinfo1->dmsk != ipinfo2->dmsk)
+ return 0;
+ }
+ if (ipinfo1->bitmask & EBT_IP_TOS) {
+ if (ipinfo1->tos != ipinfo2->tos)
+ return 0;
+ }
+ if (ipinfo1->bitmask & EBT_IP_PROTO) {
+ if (ipinfo1->protocol != ipinfo2->protocol)
+ return 0;
+ }
+ return 1;
+}
+
+static struct ebt_u_match ip_match =
+{
+ EBT_IP_MATCH,
+ sizeof(struct ebt_ip_info),
+ print_help,
+ init,
+ parse,
+ final_check,
+ print,
+ compare,
+ opts,
+};
+
+static void _init(void) __attribute((constructor));
+static void _init(void)
+{
+ register_match(&ip_match);
+}
diff --git a/userspace/ebtables2/extensions/ebt_log.c b/userspace/ebtables2/extensions/ebt_log.c
new file mode 100644
index 0000000..6dff952
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebt_log.c
@@ -0,0 +1,197 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <getopt.h>
+#include "../include/ebtables_u.h"
+#include <linux/netfilter_bridge/ebt_log.h>
+
+// copied from syslog.h
+// used for the LOG target
+#define LOG_EMERG 0 // system is unusable
+#define LOG_ALERT 1 // action must be taken immediately
+#define LOG_CRIT 2 // critical conditions
+#define LOG_ERR 3 // error conditions
+#define LOG_WARNING 4 // warning conditions
+#define LOG_NOTICE 5 // normal but significant condition
+#define LOG_INFO 6 // informational
+#define LOG_DEBUG 7 // debug-level messages
+#define LOG_DEFAULT_LEVEL LOG_INFO
+
+typedef struct _code {
+ char *c_name;
+ int c_val;
+} CODE;
+
+static CODE eight_priority[] = {
+ { "emerg", LOG_EMERG },
+ { "alert", LOG_ALERT },
+ { "crit", LOG_CRIT },
+ { "error", LOG_ERR },
+ { "warning", LOG_WARNING },
+ { "notice", LOG_NOTICE },
+ { "info", LOG_INFO },
+ { "debug", LOG_DEBUG },
+ { NULL, -1 }
+};
+
+static int name_to_loglevel(char* arg)
+{
+ int i = 0, c_val = eight_priority[0].c_val;
+
+ while (c_val != -1) {
+ if (!strcmp(arg, eight_priority[i].c_name))
+ return c_val;
+ i++;
+ c_val = eight_priority[i].c_val;
+ }
+ // return bad loglevel
+ return 9;
+}
+
+#define LOG_PREFIX '1'
+#define LOG_LEVEL '2'
+#define LOG_ARP '3'
+#define LOG_IP '4'
+#define LOG_LOG '5'
+static struct option opts[] =
+{
+ { "log-prefix", required_argument, 0, LOG_PREFIX },
+ { "log-level" , required_argument, 0, LOG_LEVEL },
+ { "log-arp" , no_argument , 0, LOG_ARP },
+ { "log-ip" , no_argument , 0, LOG_IP },
+ { "log" , no_argument , 0, LOG_LOG },
+ { 0 }
+};
+
+static void print_help()
+{
+ int i;
+
+ printf(
+"log options:\n"
+"--log : use this if you're not specifying anything\n"
+"--log-level level : level = [1-8] or a string\n"
+"--log-prefix prefix : max. %d chars.\n"
+"--log-ip : put ip info. in the log for ip packets\n"
+"--log-arp : put (r)arp info. in the log for (r)arp packets\n"
+ , EBT_LOG_PREFIX_SIZE - 1);
+ printf("levels:\n");
+ for (i = 0; i < 8; i++)
+ printf("%d = %s\n", eight_priority[i].c_val,
+ eight_priority[i].c_name);
+}
+
+static void init(struct ebt_entry_watcher *watcher)
+{
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)watcher->data;
+
+ loginfo->bitmask = 0;
+ loginfo->prefix[0] = '\0';
+ loginfo->loglevel = LOG_NOTICE;
+}
+
+#define OPT_PREFIX 0x01
+#define OPT_LEVEL 0x02
+#define OPT_ARP 0x04
+#define OPT_IP 0x08
+#define OPT_LOG 0x10
+static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ unsigned int *flags, struct ebt_entry_watcher **watcher)
+{
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)(*watcher)->data;
+ int i;
+ char *end;
+
+ switch (c) {
+ case LOG_PREFIX:
+ check_option(flags, OPT_PREFIX);
+ if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
+ print_error("Prefix too long");
+ strcpy(loginfo->prefix, optarg);
+ break;
+
+ case LOG_LEVEL:
+ check_option(flags, OPT_LEVEL);
+ i = strtol(optarg, &end, 16);
+ if (*end != '\0' || i < 0 || i > 7)
+ loginfo->loglevel = name_to_loglevel(optarg);
+ else
+ loginfo->loglevel = i;
+ if (loginfo->loglevel == 9)
+ print_error("Problem with the log-level");
+ break;
+
+ case LOG_IP:
+ check_option(flags, OPT_IP);
+ loginfo->bitmask |= EBT_LOG_IP;
+ break;
+
+ case LOG_ARP:
+ check_option(flags, OPT_ARP);
+ loginfo->bitmask |= EBT_LOG_ARP;
+ break;
+
+ case LOG_LOG:
+ check_option(flags, OPT_LOG);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void final_check(const struct ebt_u_entry *entry,
+ const struct ebt_entry_watcher *watcher, const char *name, unsigned int hook)
+{
+ return;
+}
+
+static void print(const struct ebt_u_entry *entry,
+ const struct ebt_entry_watcher *watcher)
+{
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)watcher->data;
+
+ printf("log: log-level = %s - log-prefix = \"%s\"",
+ eight_priority[loginfo->loglevel].c_name,
+ loginfo->prefix);
+ if (loginfo->bitmask & EBT_LOG_IP)
+ printf(" - log-ip");
+ if (loginfo->bitmask & EBT_LOG_ARP)
+ printf(" - log-arp");
+ printf(" ");
+}
+
+static int compare(const struct ebt_entry_watcher *w1,
+ const struct ebt_entry_watcher *w2)
+{
+ struct ebt_log_info *loginfo1 = (struct ebt_log_info *)w1->data;
+ struct ebt_log_info *loginfo2 = (struct ebt_log_info *)w2->data;
+
+ if (loginfo1->loglevel != loginfo2->loglevel)
+ return 0;
+ if (loginfo1->bitmask != loginfo2->bitmask)
+ return 0;
+ return !strcmp(loginfo1->prefix, loginfo2->prefix);
+}
+
+static struct ebt_u_watcher log_watcher =
+{
+ EBT_LOG_WATCHER,
+ sizeof(struct ebt_log_info),
+ print_help,
+ init,
+ parse,
+ final_check,
+ print,
+ compare,
+ opts,
+};
+
+#undef _init
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_watcher(&log_watcher);
+}
diff --git a/userspace/ebtables2/extensions/ebt_nat.c b/userspace/ebtables2/extensions/ebt_nat.c
new file mode 100644
index 0000000..dbdb5a4
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebt_nat.c
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <getopt.h>
+#include "../include/ebtables_u.h"
+#include <linux/netfilter_bridge/ebt_nat.h>
+
+extern char *standard_targets[NUM_STANDARD_TARGETS];
+
+int to_source_supplied, to_dest_supplied;
+
+#define NAT_S '1'
+#define NAT_D '1'
+#define NAT_S_TARGET '2'
+#define NAT_D_TARGET '2'
+static struct option opts_s[] =
+{
+ { "to-source" , required_argument, 0, NAT_S },
+ { "to-src" , required_argument, 0, NAT_S },
+ { "snat-target" , required_argument, 0, NAT_S_TARGET },
+ { 0 }
+};
+
+static struct option opts_d[] =
+{
+ { "to-destination", required_argument, 0, NAT_D },
+ { "to-dst" , required_argument, 0, NAT_D },
+ { "dnat-target" , required_argument, 0, NAT_D_TARGET },
+ { 0 }
+};
+
+static void print_help_s()
+{
+ printf(
+ "snat options:\n"
+ " --to-src address : MAC address to map source to\n"
+ " --snat-target target : ACCEPT, DROP or CONTINUE\n");
+}
+
+static void print_help_d()
+{
+ printf(
+ "dnat options:\n"
+ " --to-dst address : MAC address to map destination to\n"
+ " --dnat-target target : ACCEPT, DROP or CONTINUE\n");
+}
+
+static void init_s(struct ebt_entry_target *target)
+{
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
+
+ to_source_supplied = 0;
+ natinfo->target = EBT_ACCEPT;
+ return;
+}
+
+static void init_d(struct ebt_entry_target *target)
+{
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
+
+ to_dest_supplied = 0;
+ natinfo->target = EBT_ACCEPT;
+ return;
+}
+
+#define OPT_SNAT 0x01
+#define OPT_SNAT_TARGET 0x02
+static int parse_s(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_target **target)
+{
+ int i;
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
+
+ switch (c) {
+ case NAT_S:
+ check_option(flags, OPT_SNAT);
+ to_source_supplied = 1;
+ if (getmac(optarg, natinfo->mac))
+ print_error("Problem with specified to-source mac");
+ break;
+ case NAT_S_TARGET:
+ check_option(flags, OPT_SNAT_TARGET);
+ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
+ if (!strcmp(optarg, standard_targets[i])) {
+ natinfo->target = i;
+ break;
+ }
+ if (i == NUM_STANDARD_TARGETS)
+ print_error("Illegal --snat-target target");
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+#define OPT_DNAT 0x01
+#define OPT_DNAT_TARGET 0x02
+static int parse_d(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_target **target)
+{
+ int i;
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
+
+ switch (c) {
+ case NAT_D:
+ check_option(flags, OPT_DNAT);
+ to_dest_supplied = 1;
+ if (getmac(optarg, natinfo->mac))
+ print_error("Problem with specified "
+ "to-destination mac");
+ break;
+ case NAT_D_TARGET:
+ check_option(flags, OPT_DNAT_TARGET);
+ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
+ if (!strcmp(optarg, standard_targets[i])) {
+ natinfo->target = i;
+ break;
+ }
+ if (i == NUM_STANDARD_TARGETS)
+ print_error("Illegal --dnat-target target");
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void final_check_s(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+{
+ if (hook != NF_BR_POST_ROUTING || strcmp(name, "nat"))
+ print_error("Wrong chain for snat");
+ if (to_source_supplied == 0)
+ print_error("No snat address supplied");
+}
+
+static void final_check_d(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+{
+ if ( ((hook != NF_BR_PRE_ROUTING && hook != NF_BR_LOCAL_OUT) ||
+ strcmp(name, "nat")) &&
+ (hook != NF_BR_BROUTING || strcmp(name, "broute")) )
+ print_error("Wrong chain for dnat");
+ if (to_dest_supplied == 0)
+ print_error("No dnat address supplied");
+}
+
+static void print_s(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target)
+{
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
+ int i;
+
+ printf("snat - to: ");
+ for (i = 0; i < ETH_ALEN; i++)
+ printf("%02x%s",
+ natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
+ printf(" --snat-target %s", standard_targets[natinfo->target]);
+}
+
+static void print_d(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target)
+{
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
+ int i;
+
+ printf("dnat - to: ");
+ for (i = 0; i < ETH_ALEN; i++)
+ printf("%02x%s",
+ natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
+ printf(" --dnat-target %s", standard_targets[natinfo->target]);
+}
+
+static int compare(const struct ebt_entry_target *t1,
+ const struct ebt_entry_target *t2)
+{
+ struct ebt_nat_info *natinfo1 = (struct ebt_nat_info *)t1->data;
+ struct ebt_nat_info *natinfo2 = (struct ebt_nat_info *)t2->data;
+
+
+ return !memcmp(natinfo1->mac, natinfo2->mac, sizeof(natinfo1->mac)) &&
+ natinfo1->target == natinfo2->target;
+}
+
+static struct ebt_u_target snat_target =
+{
+ EBT_SNAT_TARGET,
+ sizeof(struct ebt_nat_info),
+ print_help_s,
+ init_s,
+ parse_s,
+ final_check_s,
+ print_s,
+ compare,
+ opts_s,
+};
+
+static struct ebt_u_target dnat_target =
+{
+ EBT_DNAT_TARGET,
+ sizeof(struct ebt_nat_info),
+ print_help_d,
+ init_d,
+ parse_d,
+ final_check_d,
+ print_d,
+ compare,
+ opts_d,
+};
+
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_target(&snat_target);
+ register_target(&dnat_target);
+}
diff --git a/userspace/ebtables2/extensions/ebt_redirect.c b/userspace/ebtables2/extensions/ebt_redirect.c
new file mode 100644
index 0000000..3dff790
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebt_redirect.c
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <getopt.h>
+#include "../include/ebtables_u.h"
+#include <linux/netfilter_bridge/ebt_redirect.h>
+
+extern char *standard_targets[NUM_STANDARD_TARGETS];
+
+#define REDIRECT_TARGET '1'
+static struct option opts[] =
+{
+ { "redirect-target" , required_argument, 0, REDIRECT_TARGET },
+ { 0 }
+};
+
+static void print_help()
+{
+ printf(
+ "redirect option:\n"
+ " --redirect-target target : ACCEPT, DROP or CONTINUE\n");
+}
+
+static void init(struct ebt_entry_target *target)
+{
+ struct ebt_redirect_info *redirectinfo =
+ (struct ebt_redirect_info *)target->data;
+
+ redirectinfo->target = EBT_ACCEPT;
+ return;
+}
+
+
+#define OPT_REDIRECT_TARGET 0x01
+static int parse(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_target **target)
+{
+ int i;
+ struct ebt_redirect_info *redirectinfo =
+ (struct ebt_redirect_info *)(*target)->data;
+
+ switch (c) {
+ case REDIRECT_TARGET:
+ check_option(flags, OPT_REDIRECT_TARGET);
+ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
+ if (!strcmp(optarg, standard_targets[i])) {
+ redirectinfo->target = i;
+ break;
+ }
+ if (i == NUM_STANDARD_TARGETS)
+ print_error("Illegal --redirect-target target");
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void final_check(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+{
+ if ( (hook != NF_BR_PRE_ROUTING || strcmp(name, "nat")) &&
+ (hook != NF_BR_BROUTING || strcmp(name, "broute")) )
+ print_error("Wrong chain for redirect");
+}
+
+static void print(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target)
+{
+ struct ebt_redirect_info *redirectinfo =
+ (struct ebt_redirect_info *)target->data;
+
+ printf("redirect");
+ printf(" --redirect-target %s", standard_targets[redirectinfo->target]);
+}
+
+static int compare(const struct ebt_entry_target *t1,
+ const struct ebt_entry_target *t2)
+{
+ struct ebt_redirect_info *redirectinfo1 =
+ (struct ebt_redirect_info *)t1->data;
+ struct ebt_redirect_info *redirectinfo2 =
+ (struct ebt_redirect_info *)t2->data;
+
+ return redirectinfo1->target == redirectinfo2->target;
+}
+
+static struct ebt_u_target redirect_target =
+{
+ EBT_REDIRECT_TARGET,
+ sizeof(struct ebt_redirect_info),
+ print_help,
+ init,
+ parse,
+ final_check,
+ print,
+ compare,
+ opts,
+};
+
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_target(&redirect_target);
+}
diff --git a/userspace/ebtables2/extensions/ebt_standard.c b/userspace/ebtables2/extensions/ebt_standard.c
new file mode 100644
index 0000000..983d055
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebt_standard.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <getopt.h>
+#include "../include/ebtables_u.h"
+
+static struct option opts[] =
+{
+ {0}
+};
+
+static void print_help()
+{
+ printf("Standard targets: DROP, ACCEPT and CONTINUE\n");
+}
+
+static void init(struct ebt_entry_target *t)
+{
+ ((struct ebt_standard_target *)t)->verdict = EBT_CONTINUE;
+}
+
+static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ unsigned int *flags, struct ebt_entry_target **target)
+{
+ return 0;
+}
+
+static void final_check(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+{
+}
+
+static void print(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target)
+{
+ __u8 verdict = ((struct ebt_standard_target *)target)->verdict;
+
+ if (verdict == EBT_CONTINUE)
+ printf("Continue ");
+ else if (verdict == EBT_ACCEPT)
+ printf("Accept ");
+ else
+ printf("Drop ");
+}
+
+static int compare(const struct ebt_entry_target *t1,
+ const struct ebt_entry_target *t2)
+{
+ return ((struct ebt_standard_target *)t1)->verdict ==
+ ((struct ebt_standard_target *)t2)->verdict;
+}
+
+static struct ebt_u_target standard =
+{
+ EBT_STANDARD_TARGET,
+ sizeof(struct ebt_standard_target) - sizeof(struct ebt_entry_target),
+ print_help,
+ init,
+ parse,
+ final_check,
+ print,
+ compare,
+ opts
+};
+
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_target(&standard);
+}
diff --git a/userspace/ebtables2/extensions/ebt_vlan.c b/userspace/ebtables2/extensions/ebt_vlan.c
new file mode 100644
index 0000000..ad3e6f7
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebt_vlan.c
@@ -0,0 +1,231 @@
+/*
+ * Summary: ebt_vlan userspace module
+ *
+ * Description: 802.1Q Virtual LAN match support module for ebtables project.
+ * Enable to match 802.1Q VLAN tagged frames by VLAN numeric
+ * identifier (12-bites field) and frame priority (3-bites field)
+ *
+ * Authors:
+ * Bart De Schuymer <bart.de.schuymer@pandora.be>
+ * Nick Fedchik <nick@fedchik.org.ua>
+ *
+ * May, 2002
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <getopt.h>
+#include "../include/ebtables_u.h"
+#include <linux/netfilter_bridge/ebt_vlan.h>
+
+#define VLAN_ID '1'
+#define VLAN_PRIO '2'
+
+static struct option opts[] = {
+ {"vlan-id", required_argument, 0, VLAN_ID},
+ {"vlan-prio", required_argument, 0, VLAN_PRIO},
+ {0}
+};
+
+/*
+ * Print out help for ebtables -h vlan
+ */
+static void print_help ()
+{
+ printf ("802.1Q VLAN options:\n"
+ "--vlan-id [!] id : VLAN ID 1-4095 (integer)\n"
+ "--vlan-prio [!] prio : VLAN Priority 0-7 (integer)\n");
+}
+
+/*
+ * Initialization function
+ */
+static void init (struct ebt_entry_match *match)
+{
+ struct ebt_vlan_info *vlaninfo =
+ (struct ebt_vlan_info *) match->data;
+ /*
+ * Just clean initial values
+ */
+ vlaninfo->id = 0;
+ vlaninfo->prio = 0;
+ vlaninfo->invflags = 0;
+ vlaninfo->bitmask = 0;
+}
+
+#define OPT_VLAN_ID 0x01
+#define OPT_VLAN_PRIO 0x02
+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_vlan_info *vlaninfo =
+ (struct ebt_vlan_info *) (*match)->data;
+ unsigned short i;
+ char *end;
+
+ switch (c) {
+ case VLAN_ID:
+ check_option (flags, OPT_VLAN_ID);
+ /*
+ * Check If we got inversed arg for VID,
+ * otherwise unset inversion flag
+ */
+ if (check_inverse (optarg))
+ vlaninfo->invflags |= EBT_VLAN_ID;
+ /*
+ * Check arg value presense
+ */
+ if (optind > argc)
+ print_error ("Missing VLAN ID argument\n");
+ /*
+ * Convert argv to long int,
+ * set *end to end of argv string,
+ * base set 10 for decimal only
+ */
+ (unsigned short) i = strtol (argv[optind - 1], &end, 10);
+ /*
+ * Check arg val range
+ */
+ if (i < 1 || i >= 4096 || *end != '\0') {
+ i = 0;
+ print_error
+ ("Problem with specified VLAN ID range\n");
+ }
+ vlaninfo->id = i;
+ vlaninfo->bitmask|=EBT_VLAN_ID;
+ break;
+
+ case VLAN_PRIO:
+ check_option (flags, OPT_VLAN_PRIO);
+ if (check_inverse (optarg))
+ vlaninfo->invflags |= EBT_VLAN_PRIO;
+ if (optind > argc)
+ print_error
+ ("Missing VLAN Priority level argument\n");
+ /*
+ * Convert argv to long int,
+ * set *end to end of argv string,
+ * base set 10 for decimal only
+ */
+ (unsigned short) i = strtol (argv[optind - 1], &end, 10);
+ /*
+ * Check arg val range
+ */
+ if (i >= 8 || *end != '\0') {
+ i = 0;
+ print_error
+ ("Problem with specified VLAN Priority range\n");
+ }
+ vlaninfo->prio = i;
+ vlaninfo->bitmask|=EBT_VLAN_PRIO;
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Final check
+ */
+static void
+final_check (const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match,
+ const char *name, unsigned int hook)
+{
+ /*
+ * Is any proto supplied there? Or specified proto isn't 802.1Q?
+ */
+ if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q)
+ print_error
+ ("For matching 802.1Q VLAN the protocol must be specified as 802_1Q\n");
+}
+
+/*
+ * Print line when listing rules by ebtables -L
+ */
+static void
+print (const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match)
+{
+ struct ebt_vlan_info *vlaninfo =
+ (struct ebt_vlan_info *) match->data;
+
+ /*
+ * Print VLAN ID if they are specified
+ */
+ if (vlaninfo->bitmask & EBT_VLAN_ID) {
+ printf ("vlan id: %s%d, ",
+ vlaninfo->invflags & EBT_VLAN_ID ? "!" : "",
+ vlaninfo->id);
+ }
+ /*
+ * Print VLAN priority if they are specified
+ */
+ if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
+ printf ("vlan prio: %s%d, ",
+ vlaninfo->invflags & EBT_VLAN_PRIO ? "!" : "",
+ vlaninfo->prio);
+ }
+}
+
+
+static int
+compare (const struct ebt_entry_match *vlan1,
+ const struct ebt_entry_match *vlan2)
+{
+ struct ebt_vlan_info *vlaninfo1 =
+ (struct ebt_vlan_info *) vlan1->data;
+ struct ebt_vlan_info *vlaninfo2 =
+ (struct ebt_vlan_info *) vlan2->data;
+ /*
+ * Compare argc
+ */
+ if (vlaninfo1->bitmask != vlaninfo2->bitmask)
+ return 0;
+ /*
+ * Compare inv flags
+ */
+ if (vlaninfo1->invflags != vlaninfo2->invflags)
+ return 0;
+ /*
+ * Compare VLAN ID if they are present
+ */
+ if (vlaninfo1->bitmask & EBT_VLAN_ID) {
+ if (vlaninfo1->id != vlaninfo2->id)
+ return 0;
+ };
+ /*
+ * Compare VLAN Prio if they are present
+ */
+ if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
+ if (vlaninfo1->prio != vlaninfo2->prio)
+ return 0;
+ };
+ return 1;
+}
+
+static struct ebt_u_match vlan_match = {
+ EBT_VLAN_MATCH,
+ sizeof (struct ebt_vlan_info),
+ print_help,
+ init,
+ parse,
+ final_check,
+ print,
+ compare,
+ opts,
+};
+
+static void _init (void) __attribute__ ((constructor));
+static void _init (void)
+{
+ register_match (&vlan_match);
+}
diff --git a/userspace/ebtables2/extensions/ebtable_broute.c b/userspace/ebtables2/extensions/ebtable_broute.c
new file mode 100644
index 0000000..2abfcb6
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebtable_broute.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include "../include/ebtables_u.h"
+
+
+static void print_help(char **hn)
+{
+ printf("Supported chain for the nat table:\n");
+ printf("%s\n",hn[NF_BR_BROUTING]);
+}
+
+static struct
+ebt_u_table table =
+{
+ "broute",
+ NULL,
+ print_help,
+ NULL
+};
+
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_table(&table);
+}
diff --git a/userspace/ebtables2/extensions/ebtable_filter.c b/userspace/ebtables2/extensions/ebtable_filter.c
new file mode 100644
index 0000000..cf26983
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebtable_filter.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include "../include/ebtables_u.h"
+
+#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
+ (1 << NF_BR_LOCAL_OUT))
+
+static void print_help(char **hn)
+{
+ int i;
+
+ printf("Supported chains for the filter table:\n");
+ for (i = 0; i < NF_BR_NUMHOOKS; i++)
+ if (FILTER_VALID_HOOKS & (1 << i))
+ printf("%s ", hn[i]);
+ printf("\n");
+}
+
+static struct ebt_u_table table =
+{
+ "filter",
+ NULL,
+ print_help,
+ NULL
+};
+
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_table(&table);
+}
diff --git a/userspace/ebtables2/extensions/ebtable_nat.c b/userspace/ebtables2/extensions/ebtable_nat.c
new file mode 100644
index 0000000..4b4ca48
--- /dev/null
+++ b/userspace/ebtables2/extensions/ebtable_nat.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include "../include/ebtables_u.h"
+
+#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
+ (1 << NF_BR_POST_ROUTING))
+
+static void print_help(char **hn)
+{
+ int i;
+
+ printf("Supported chains for the nat table:\n");
+ for (i = 0; i < NF_BR_NUMHOOKS; i++)
+ if (NAT_VALID_HOOKS & (1 << i))
+ printf("%s ", hn[i]);
+ printf("\n");
+}
+
+static struct
+ebt_u_table table =
+{
+ "nat",
+ NULL,
+ print_help,
+ NULL
+};
+
+static void _init(void) __attribute__ ((constructor));
+static void _init(void)
+{
+ register_table(&table);
+}
diff --git a/userspace/ebtables2/include/ebtables_u.h b/userspace/ebtables2/include/ebtables_u.h
new file mode 100644
index 0000000..d31186c
--- /dev/null
+++ b/userspace/ebtables2/include/ebtables_u.h
@@ -0,0 +1,206 @@
+/*
+ * $Id: ebtables.c,v 1.03 2002/01/19
+ *
+ * Copyright (C) 2001-2002 Bart De Schuymer
+ *
+ * This code is stongly inspired on the iptables code which is
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef EBTABLES_U_H
+#define EBTABLES_U_H
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/br_db.h>
+
+struct ebt_u_entries
+{
+ __u8 policy;
+ __u32 nentries;
+ struct ebt_u_entry *entries;
+};
+
+
+struct ebt_u_replace
+{
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ // nr of rules in the table
+ unsigned int nentries;
+ struct ebt_u_entries *hook_entry[NF_BR_NUMHOOKS];
+ // how many counters in front of it?
+ unsigned int counter_entry[NF_BR_NUMHOOKS];
+ // nr of counters userspace expects back
+ unsigned int num_counters;
+ // where the kernel will put the old counters
+ struct ebt_counter *counters;
+ // can be used e.g. to know if a standard option
+ // has been specified twice
+ unsigned int flags;
+ // we stick the specified command (e.g. -A) in here
+ char command;
+ // here we stick the hook to do our thing on (can be -1 if unspecified)
+ int selected_hook;
+};
+
+struct ebt_u_table
+{
+ char name[EBT_TABLE_MAXNAMELEN];
+ int (*check)(struct ebt_u_replace *repl);
+ void (*help)(char **);
+ struct ebt_u_table *next;
+};
+
+struct ebt_u_match_list
+{
+ struct ebt_u_match_list *next;
+ struct ebt_entry_match *m;
+};
+
+struct ebt_u_watcher_list
+{
+ struct ebt_u_watcher_list *next;
+ struct ebt_entry_watcher *w;
+};
+
+struct ebt_u_entry
+{
+ __u32 bitmask;
+ __u32 invflags;
+ __u16 ethproto;
+ __u8 in[IFNAMSIZ];
+ __u8 logical_in[IFNAMSIZ];
+ __u8 out[IFNAMSIZ];
+ __u8 logical_out[IFNAMSIZ];
+ __u8 sourcemac[ETH_ALEN];
+ __u8 sourcemsk[ETH_ALEN];
+ __u8 destmac[ETH_ALEN];
+ __u8 destmsk[ETH_ALEN];
+ struct ebt_u_match_list *m_list;
+ struct ebt_u_watcher_list *w_list;
+ struct ebt_entry_target *t;
+ struct ebt_u_entry *next;
+};
+
+struct ebt_u_match
+{
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ // size of the real match data + sizeof struct ebt_match
+ unsigned int size;
+ void (*help)(void);
+ void (*init)(struct ebt_entry_match *m);
+ int (*parse)(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_match **match);
+ void (*final_check)(const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match,
+ const char *name, unsigned int hook);
+ void (*print)(const struct ebt_u_entry *entry,
+ const struct ebt_entry_match *match);
+ int (*compare)(const struct ebt_entry_match *m1,
+ const struct ebt_entry_match *m2);
+ const struct option *extra_ops;
+ // can be used e.g. to check for multiple occurance of the same option
+ unsigned int flags;
+ unsigned int option_offset;
+ struct ebt_entry_match *m;
+ // if used == 1 we no longer have to add it to
+ // the match chain of the new entry
+ unsigned int used;
+ struct ebt_u_match *next;
+};
+
+struct ebt_u_watcher
+{
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ unsigned int size;
+ void (*help)(void);
+ void (*init)(struct ebt_entry_watcher *w);
+ int (*parse)(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_watcher **watcher);
+ void (*final_check)(const struct ebt_u_entry *entry,
+ const struct ebt_entry_watcher *watch, const char *name,
+ unsigned int hook);
+ void (*print)(const struct ebt_u_entry *entry,
+ const struct ebt_entry_watcher *watcher);
+ int (*compare)(const struct ebt_entry_watcher *w1,
+ const struct ebt_entry_watcher *w2);
+ const struct option *extra_ops;
+ unsigned int flags;
+ unsigned int option_offset;
+ struct ebt_entry_watcher *w;
+ unsigned int used;
+ struct ebt_u_watcher *next;
+};
+
+struct ebt_u_target
+{
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ unsigned int size;
+ void (*help)(void);
+ void (*init)(struct ebt_entry_target *t);
+ int (*parse)(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_target **target);
+ void (*final_check)(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target, const char *name,
+ unsigned int hook);
+ void (*print)(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target);
+ int (*compare)(const struct ebt_entry_target *t1,
+ const struct ebt_entry_target *t2);
+ const struct option *extra_ops;
+ unsigned int option_offset;
+ unsigned int flags;
+ struct ebt_entry_target *t;
+ unsigned int used;
+ struct ebt_u_target *next;
+};
+
+void register_table(struct ebt_u_table *);
+void register_match(struct ebt_u_match *);
+void register_watcher(struct ebt_u_watcher *);
+void register_target(struct ebt_u_target *t);
+void get_table(struct ebt_u_replace *repl);
+struct ebt_u_target *find_target(const char *name);
+struct ebt_u_match *find_match(const char *name);
+struct ebt_u_watcher *find_watcher(const char *name);
+void deliver_counters(struct ebt_u_replace *repl,
+ unsigned short * counterchanges);
+void deliver_table(struct ebt_u_replace *repl);
+void get_dbinfo(struct brdb_dbinfo *nr);
+void get_db(int len, struct brdb_dbentry *db);
+void deliver_allowdb(__u16 *decision);
+int getmac(char *from, char *to);
+void check_option(unsigned int *flags, unsigned int mask);
+int check_inverse(const char option[]);
+#define print_bug(format, args...) \
+ {printf("BUG: "format".\n", ##args); exit(-1);}
+#define print_error(format, args...) {printf(format".\n", ##args); exit(-1);}
+#define print_memory() {printf("Ebtables: " __FILE__ " " __FUNCTION__ \
+ " %d :Out of memory.\n", __LINE__); exit(-1);}
+
+
+
+// used for keeping the rule counters right during rule adds or deletes
+#define CNT_NORM 0
+#define CNT_DEL 1
+#define CNT_ADD 2
+#define CNT_END 3
+#define CNT_ZERO 4
+
+#endif /* EBTABLES_U_H */
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre2.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre2.001.diff
new file mode 100644
index 0000000..80cc94b
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre2.001.diff
@@ -0,0 +1,121 @@
+Changed the Makefile hacking to initialize things (taken from iptables)
+to using __attribute__ ((constructor)). Makes things cleaner.
+
+--- ebtables-v2.0pre1/Makefile Wed Apr 3 18:24:15 2002
++++ ebtables-v2.0pre2/Makefile Sat Apr 6 21:53:00 2002
+@@ -26,7 +26,7 @@
+ $(CC) $(CFLAGS) -DPROGVERSION=\"$(PROGVERSION)\" \
+ -DPROGNAME=\"$(PROGNAME)\" -c -o $@ $<
+
+-ebtables: ebtables.o communication.o initext.o $(EXT_OBJS)
++ebtables: ebtables.o communication.o $(EXT_OBJS)
+ $(CC) $(CFLAGS) -o $@ $^
+
+ $(MANDIR)/man8/ebtables.8: ebtables.8
+--- ebtables-v2.0pre1/ebtables.c Wed Apr 3 20:06:18 2002
++++ ebtables-v2.0pre2/ebtables.c Sat Apr 6 21:57:05 2002
+@@ -1051,7 +1051,6 @@
+ replace.selected_hook = -1;
+ replace.command = 'h';
+ // execute the _init functions of the extensions
+- init_extensions();
+
+ new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
+ if (!new_entry)
+--- ebtables-v2.0pre1/extensions/ebt_nat.c Wed Apr 3 12:27:59 2002
++++ ebtables-v2.0pre2/extensions/ebt_nat.c Sat Apr 6 21:59:43 2002
+@@ -160,7 +160,8 @@
+ opts_d,
+ };
+
+-void _init(void)
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
+ {
+ register_target(&snat_target);
+ register_target(&dnat_target);
+--- ebtables-v2.0pre1/extensions/ebt_ip.c Wed Apr 3 12:28:44 2002
++++ ebtables-v2.0pre2/extensions/ebt_ip.c Sat Apr 6 21:58:23 2002
+@@ -301,7 +301,8 @@
+ opts,
+ };
+
+-void _init(void)
++static void _init(void) __attribute((constructor));
++static void _init(void)
+ {
+ register_match(&ip_match);
+ }
+--- ebtables-v2.0pre1/extensions/ebt_arp.c Wed Apr 3 12:29:17 2002
++++ ebtables-v2.0pre2/extensions/ebt_arp.c Sat Apr 6 21:58:05 2002
+@@ -271,7 +271,8 @@
+ opts,
+ };
+
+-void _init(void)
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
+ {
+ register_match(&arp_match);
+ }
+--- ebtables-v2.0pre1/extensions/ebt_log.c Wed Apr 3 16:23:56 2002
++++ ebtables-v2.0pre2/extensions/ebt_log.c Sat Apr 6 21:59:34 2002
+@@ -182,7 +182,9 @@
+ opts,
+ };
+
+-void _init(void)
++#undef _init
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
+ {
+ register_watcher(&log_watcher);
+ }
+--- ebtables-v2.0pre1/extensions/ebt_standard.c Mon Apr 1 12:49:59 2002
++++ ebtables-v2.0pre2/extensions/ebt_standard.c Sat Apr 6 22:01:29 2002
+@@ -59,7 +59,8 @@
+ opts
+ };
+
+-void _init(void)
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
+ {
+ register_target(&standard);
+ }
+--- ebtables-v2.0pre1/extensions/ebtable_filter.c Mon Apr 1 21:25:57 2002
++++ ebtables-v2.0pre2/extensions/ebtable_filter.c Sat Apr 6 22:00:02 2002
+@@ -24,7 +24,8 @@
+ NULL
+ };
+
+-void _init(void)
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
+ {
+ register_table(&table);
+ }
+--- ebtables-v2.0pre1/extensions/ebtable_nat.c Wed Apr 3 10:16:46 2002
++++ ebtables-v2.0pre2/extensions/ebtable_nat.c Sat Apr 6 21:59:53 2002
+@@ -24,7 +24,8 @@
+ NULL
+ };
+
+-void _init(void)
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
+ {
+ register_table(&table);
+ }
+--- ebtables-v2.0pre1/include/ebtables_u.h Wed Apr 3 17:20:17 2002
++++ ebtables-v2.0pre2/include/ebtables_u.h Sat Apr 6 21:56:16 2002
+@@ -25,9 +25,6 @@
+ #define EBTABLES_U_H
+ #include <linux/netfilter_bridge/ebtables.h>
+ #include <linux/br_db.h>
+-#ifdef _INIT
+-#define _init _INIT
+-#endif
+
+ struct ebt_u_entries
+ {
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre2.002.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre2.002.diff
new file mode 100644
index 0000000..c638367
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre2.002.diff
@@ -0,0 +1,2204 @@
+This is a big patch.
+Hope I didn't break anything.
+
+--- ebtables-v2.0pre2.001/Makefile Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/Makefile Thu Apr 11 18:38:47 2002
+@@ -2,8 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre1 (April 2002)"
+-
++PROGVERSION:="2.0pre2.001 (April 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+--- ebtables-v2.0pre2.001/ebtables.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/ebtables.c Wed Apr 10 22:46:27 2002
+@@ -34,7 +34,8 @@
+ #include <asm/types.h>
+ #include "include/ebtables_u.h"
+
+-// here are the number-name correspondences kept for the ethernet frame type field
++// here are the number-name correspondences kept for the ethernet
++// frame type field
+ #define PROTOCOLFILE "/etc/etherproto"
+
+ #define DATABASEHOOKNR NF_BR_NUMHOOKS
+@@ -81,27 +82,28 @@
+
+ // yup, all the possible target names
+ char* standard_targets[NUM_STANDARD_TARGETS] = {
+- "ACCEPT" ,
++ "ACCEPT",
+ "DROP",
+ "CONTINUE",
+ };
+
+ // tells what happened to the old rules
+-unsigned short *counterchanges;
++static unsigned short *counterchanges;
+ // holds all the data
+-struct ebt_u_replace replace;
++static struct ebt_u_replace replace;
+
+ // the chosen table
+-struct ebt_u_table *table = NULL;
++static struct ebt_u_table *table = NULL;
+ // the lists of supported tables, matches, watchers and targets
+-struct ebt_u_table *tables = NULL;
+-struct ebt_u_match *matches = NULL;
+-struct ebt_u_watcher *watchers = NULL;
+-struct ebt_u_target *targets = NULL;
++static struct ebt_u_table *tables = NULL;
++static struct ebt_u_match *matches = NULL;
++static struct ebt_u_watcher *watchers = NULL;
++static struct ebt_u_target *targets = NULL;
+
+ struct ebt_u_target *find_target(const char *name)
+ {
+ struct ebt_u_target *t = targets;
++
+ while(t && strcmp(t->name, name))
+ t = t->next;
+ return t;
+@@ -110,6 +112,7 @@
+ struct ebt_u_match *find_match(const char *name)
+ {
+ struct ebt_u_match *m = matches;
++
+ while(m && strcmp(m->name, name))
+ m = m->next;
+ return m;
+@@ -118,6 +121,7 @@
+ struct ebt_u_watcher *find_watcher(const char *name)
+ {
+ struct ebt_u_watcher *w = watchers;
++
+ while(w && strcmp(w->name, name))
+ w = w->next;
+ return w;
+@@ -126,17 +130,18 @@
+ struct ebt_u_table *find_table(char *name)
+ {
+ struct ebt_u_table *t = tables;
++
+ while (t && strcmp(t->name, name))
+ t = t->next;
+ return t;
+ }
+
+-// the pointers in here are special:
+-// the struct ebt_target * pointer is actually a struct ebt_u_target * pointer
+-// instead of making yet a few other structs, we just do a cast
+-// we need a struct ebt_u_target pointer because we know the address of the data they
+-// point to won't change. We want to allow that the struct ebt_u_target.t member can
+-// change.
++// The pointers in here are special:
++// The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
++// instead of making yet a few other structs, we just do a cast.
++// We need a struct ebt_u_target pointer because we know the address of the data
++// they point to won't change. We want to allow that the struct ebt_u_target.t
++// member can change.
+ // Same holds for the struct ebt_match and struct ebt_watcher pointers
+ struct ebt_u_entry *new_entry;
+
+@@ -149,13 +154,14 @@
+ strcpy(e->out, "");
+ e->m_list = NULL;
+ e->w_list = NULL;
+- // the init function of the standard target should have put the verdict on CONTINUE
++ // the init function of the standard target should have put the verdict
++ // on CONTINUE
+ e->t = (struct ebt_entry_target *)find_target(EBT_STANDARD_TARGET);
+ if (!e->t)
+ print_bug("Couldn't load standard target\n");
+ }
+
+-// this doesn't free e, basically becoz it's lazy
++// this doesn't free e, becoz the calling function might need e->next
+ void free_u_entry(struct ebt_u_entry *e)
+ {
+ struct ebt_u_match_list *m_l, *m_l2;
+@@ -178,6 +184,40 @@
+ free(e->t);
+ }
+
++// the user will use the match, so put it in new_entry
++static void add_match(struct ebt_u_match *m)
++{
++ struct ebt_u_match_list **m_list, *new;
++
++ m->used = 1;
++ for (m_list = &new_entry->m_list;
++ *m_list; m_list = &(*m_list)->next);
++ new = (struct ebt_u_match_list *)
++ malloc(sizeof(struct ebt_u_match_list));
++ if (!new)
++ print_memory();
++ *m_list = new;
++ new->next = NULL;
++ new->m = (struct ebt_entry_match *)m;
++}
++
++static void add_watcher(struct ebt_u_watcher *w)
++{
++ struct ebt_u_watcher_list **w_list;
++ struct ebt_u_watcher_list *new;
++
++ w->used = 1;
++ for (w_list = &new_entry->w_list;
++ *w_list; w_list = &(*w_list)->next);
++ new = (struct ebt_u_watcher_list *)
++ malloc(sizeof(struct ebt_u_watcher_list));
++ if (!new)
++ print_memory();
++ *w_list = new;
++ new->next = NULL;
++ new->w = (struct ebt_entry_watcher *)w;
++}
++
+ static int global_option_offset = 0;
+ #define OPTION_OFFSET 256
+ static struct option *
+@@ -196,6 +236,8 @@
+ *options_offset = global_option_offset;
+
+ merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
++ if (!merge)
++ print_memory();
+ memcpy(merge, oldopts, num_old * sizeof(struct option));
+ for (i = 0; i < num_new; i++) {
+ merge[num_old + i] = newopts[i];
+@@ -219,7 +261,8 @@
+ print_memory();
+ strcpy(m->m->u.name, m->name);
+ m->m->match_size = size;
+- ebt_options = merge_options(ebt_options, m->extra_ops, &(m->option_offset));
++ ebt_options = merge_options
++ (ebt_options, m->extra_ops, &(m->option_offset));
+ m->init(m->m);
+
+ for (i = &matches; *i; i = &((*i)->next));
+@@ -237,7 +280,8 @@
+ print_memory();
+ strcpy(w->w->u.name, w->name);
+ w->w->watcher_size = size;
+- ebt_options = merge_options(ebt_options, w->extra_ops, &(w->option_offset));
++ ebt_options = merge_options
++ (ebt_options, w->extra_ops, &(w->option_offset));
+ w->init(w->w);
+
+ for (i = &watchers; *i; i = &((*i)->next));
+@@ -255,7 +299,8 @@
+ print_memory();
+ strcpy(t->t->u.name, t->name);
+ t->t->target_size = size;
+- ebt_options = merge_options(ebt_options, t->extra_ops, &(t->option_offset));
++ ebt_options = merge_options
++ (ebt_options, t->extra_ops, &(t->option_offset));
+ t->init(t->t);
+ for (i = &targets; *i; i = &((*i)->next));
+ t->next = NULL;
+@@ -292,7 +337,7 @@
+ return 0;
+ }
+
+-/* helper function: processes a line of data from the file brebt_protocolnames */
++// helper function: processes a line of data from the file /etc/etherproto
+ int get_a_line(char *buffer, char *value, FILE *ifp)
+ {
+ int i, hlp;
+@@ -314,7 +359,7 @@
+
+ // buffer[0] already contains the first letter
+ for (i = 1; i < 21; i++) {
+- hlp = fscanf(ifp, "%c", buffer+i);
++ hlp = fscanf(ifp, "%c", buffer + i);
+ if (hlp == EOF || hlp == 0) return -1;
+ if (buffer[i] == '\t' || buffer[i] == ' ')
+ break;
+@@ -327,7 +372,8 @@
+ // buffer[0] already contains the first letter
+ for (i = 1; i < 5; i++) {
+ hlp = fscanf(ifp, "%c", value+i);
+- if (value[i] == '\n' || value[i] == '\t' || value[i] == ' ' || hlp == EOF)
++ if (value[i] == '\n' || value[i] == '\t' ||
++ value[i] == ' ' || hlp == EOF)
+ break;
+ }
+ if (i == 5) return -1;
+@@ -342,7 +388,7 @@
+ return 0;
+ }
+
+-/* helper function for list_em() */
++// helper function for list_em()
+ int number_to_name(unsigned short proto, char *name)
+ {
+ FILE *ifp;
+@@ -363,13 +409,12 @@
+ fclose(ifp);
+ return 0;
+ }
+- return -1;
+ }
+
+-/* helper function for list_rules() */
++// helper function for list_rules()
+ static void list_em(int hooknr)
+ {
+- int i, space = 0;
++ int i, j, space = 0, digits;
+ struct ebt_u_entry *hlp;
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+@@ -379,7 +424,8 @@
+ char name[21];
+
+ hlp = replace.hook_entry[hooknr]->entries;
+- printf("\nBridge chain: %s\nPolicy: %s\n", hooknames[hooknr], standard_targets[(int)(replace.hook_entry[hooknr]->policy)]);
++ printf("\nBridge chain: %s\nPolicy: %s\n", hooknames[hooknr],
++ standard_targets[replace.hook_entry[hooknr]->policy]);
+ printf("nr. of entries: %d \n", replace.hook_entry[hooknr]->nentries);
+
+ i = replace.hook_entry[hooknr]->nentries;
+@@ -389,19 +435,18 @@
+ }
+
+ for (i = 0; i < replace.hook_entry[hooknr]->nentries; i++) {
+- int j = i + 1, space2 = 0;
+- // a little work to get nice rule numbers
+- // this can probably be done easier - so what
++ digits = 0;
++ // A little work to get nice rule numbers.
+ while (j > 9) {
+- space2++;
++ digits++;
+ j /= 10;
+ }
+- for (j = 0; j < space - space2; j++)
++ for (j = 0; j < space - digits; j++)
+ printf(" ");
+ printf("%d. ", i + 1);
+
+- // don't print anything about the protocol if no protocol was specified
+- // obviously this means any protocol will do
++ // Don't print anything about the protocol if no protocol was
++ // specified, obviously this means any protocol will do.
+ if (!(hlp->bitmask & EBT_NOPROTO)) {
+ printf("eth proto: ");
+ if (hlp->invflags & EBT_IPROTO)
+@@ -416,20 +461,20 @@
+ }
+ }
+ if (hlp->bitmask & EBT_SOURCEMAC) {
+- int j;
+ printf("source mac: ");
+ if (hlp->invflags & EBT_ISOURCE)
+ printf("! ");
+ for (j = 0; j < ETH_ALEN; j++)
+- printf("%02x%s", hlp->sourcemac[j], (j == ETH_ALEN - 1) ? ", " : ":");
++ printf("%02x%s", hlp->sourcemac[j],
++ (j == ETH_ALEN - 1) ? ", " : ":");
+ }
+ if (hlp->bitmask & EBT_DESTMAC) {
+- int j;
+ printf("dest mac: ");
+ if (hlp->invflags & EBT_IDEST)
+ printf("! ");
+ for (j = 0; j < ETH_ALEN; j++)
+- printf("%02x%s", hlp->destmac[j], (j == ETH_ALEN - 1) ? ", " : ":");
++ printf("%02x%s", hlp->destmac[j],
++ (j == ETH_ALEN - 1) ? ", " : ":");
+ }
+ if (hlp->in[0] != '\0') {
+ if (hlp->invflags & EBT_IIN)
+@@ -462,9 +507,10 @@
+ printf("target: ");
+ t = find_target(hlp->t->u.name);
+ if (!t)
+- print_error("Target not found.");
++ print_bug("Target not found");
+ t->print(hlp, hlp->t);
+- printf(", count = %llu", replace.counters[replace.counter_entry[hooknr] + i].pcnt);
++ printf(", count = %llu",
++ replace.counters[replace.counter_entry[hooknr] + i].pcnt);
+ printf("\n");
+ hlp = hlp->next;
+ }
+@@ -492,30 +538,30 @@
+ struct ebt_u_watcher_list *w_l;
+
+ printf(
+- "%s v%s\n"
+- "Usage:\n"
+- "ebtables -[ADI] chain rule-specification [options]\n"
+- "ebtables -P chain target\n"
+- "ebtables -[LFZ] [chain]\n"
+- "ebtables -[b] [y,n]\n"
+- "Commands:\n"
+- "--append -A chain : Append to chain\n"
+- "--delete -D chain : Delete matching rule from chain\n"
+- "--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
+- "--insert -I chain rulenum : insert rule at position rulenum in chain\n"
+- "--list -L [chain] : List the rules in a chain or in all chains\n"
+- "--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
+- "--flush -F [chain] : Delete all rules in chain or in all chains\n"
+- "--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
+- "--policy -P chain target : Change policy on chain to target\n"
+- "Options:\n"
+- "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
+- "--src -s [!] address : source mac address\n"
+- "--dst -d [!] address : destination mac address\n"
+- "--in-if -i [!] name : network input interface name\n"
+- "--out-if -o [!] name : network output interface name\n"
+- "--version -V : print package version\n"
+- "\n" ,
++"%s v%s\n"
++"Usage:\n"
++"ebtables -[ADI] chain rule-specification [options]\n"
++"ebtables -P chain target\n"
++"ebtables -[LFZ] [chain]\n"
++"ebtables -[b] [y,n]\n"
++"Commands:\n"
++"--append -A chain : Append to chain\n"
++"--delete -D chain : Delete matching rule from chain\n"
++"--delete -D chain rulenum : Delete rule at position rulenum from chain\n"
++"--insert -I chain rulenum : insert rule at position rulenum in chain\n"
++"--list -L [chain] : List the rules in a chain or in all chains\n"
++"--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
++"--flush -F [chain] : Delete all rules in chain or in all chains\n"
++"--zero -Z [chain] : Put counters on zero in chain or in all chains\n"
++"--policy -P chain target : Change policy on chain to target\n"
++"Options:\n"
++"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
++"--src -s [!] address : source mac address\n"
++"--dst -d [!] address : destination mac address\n"
++"--in-if -i [!] name : network input interface name\n"
++"--out-if -o [!] name : network output interface name\n"
++"--version -V : print package version\n"
++"\n" ,
+ prog_name,
+ prog_version);
+
+@@ -538,7 +584,7 @@
+ exit(0);
+ }
+
+-/* execute command L */
++// execute command L
+ static void list_rules()
+ {
+ int i;
+@@ -563,7 +609,8 @@
+ replace.num_counters = replace.nentries;
+ if (replace.nentries) {
+ // '+ 1' for the CNT_END
+- if ( !(counterchanges = (unsigned short *)malloc((replace.nentries + 1) * sizeof(unsigned short))) )
++ if (!(counterchanges = (unsigned short *) malloc(
++ (replace.nentries + 1) * sizeof(unsigned short))))
+ print_memory();
+ // done nothing special to the rules
+ for (i = 0; i < replace.nentries; i++)
+@@ -611,12 +658,14 @@
+ if (replace.hook_entry[replace.selected_hook]->nentries == 0)
+ exit(0);
+ oldnentries = replace.nentries;
+- replace.nentries = replace.nentries - replace.hook_entry[replace.selected_hook]->nentries;
++ replace.nentries = replace.nentries -
++ replace.hook_entry[replace.selected_hook]->nentries;
+
+ // delete the counters belonging to the specified chain
+ if (replace.nentries) {
+ // +1 for CNT_END
+- if ( !(counterchanges = (unsigned short *)malloc((oldnentries + 1) * sizeof(unsigned short))) )
++ if ( !(counterchanges = (unsigned short *)
++ malloc((oldnentries + 1) * sizeof(unsigned short))) )
+ print_memory();
+ cnt = counterchanges;
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+@@ -660,23 +709,31 @@
+
+ // handle '-D chain rulenr' command
+ if (rule_nr != -1) {
+- if (rule_nr > replace.hook_entry[replace.selected_hook]->nentries)
++ if (rule_nr >
++ replace.hook_entry[replace.selected_hook]->nentries)
+ return 0;
++ // user starts counting from 1
+ return rule_nr - 1;
+ }
+ u_e = replace.hook_entry[replace.selected_hook]->entries;
+- // check for an existing rule (if there are duplicate rules, take the first occurance)
+- for (i = 0; i < replace.hook_entry[replace.selected_hook]->nentries; i++, u_e = u_e->next) {
++ // check for an existing rule (if there are duplicate rules,
++ // take the first occurance)
++ for (i = 0; i < replace.hook_entry[replace.selected_hook]->nentries;
++ i++, u_e = u_e->next) {
+ if (!u_e)
+ print_bug("Hmm, trouble");
+ if ( u_e->ethproto == new_entry->ethproto
+- && !strncmp(u_e->in, new_entry->in, IFNAMSIZ)
+- && !strncmp(u_e->out, new_entry->out, IFNAMSIZ) && u_e->bitmask == new_entry->bitmask) {
+- if (new_entry->bitmask & EBT_SOURCEMAC && strncmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
++ && !strcmp(u_e->in, new_entry->in)
++ && !strcmp(u_e->out, new_entry->out)
++ && u_e->bitmask == new_entry->bitmask) {
++ if (new_entry->bitmask & EBT_SOURCEMAC &&
++ strcmp(u_e->sourcemac, new_entry->sourcemac))
+ continue;
+- if (new_entry->bitmask & EBT_DESTMAC && strncmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
++ if (new_entry->bitmask & EBT_DESTMAC &&
++ strcmp(u_e->destmac, new_entry->destmac))
+ continue;
+- if (new_entry->bitmask != u_e->bitmask || new_entry->invflags != u_e->invflags)
++ if (new_entry->bitmask != u_e->bitmask ||
++ new_entry->invflags != u_e->invflags)
+ continue;
+ // compare all matches
+ m_l = new_entry->m_list;
+@@ -684,7 +741,8 @@
+ while (m_l) {
+ m = (struct ebt_u_match *)(m_l->m);
+ m_l2 = u_e->m_list;
+- while (m_l2 && strcmp(m_l2->m->u.name, m->m->u.name))
++ while (m_l2 &&
++ strcmp(m_l2->m->u.name, m->m->u.name))
+ m_l2 = m_l2->next;
+ if (!m_l2 || !m->compare(m->m, m_l2->m))
+ goto letscontinue;
+@@ -707,7 +765,8 @@
+ while (w_l) {
+ w = (struct ebt_u_watcher *)(w_l->w);
+ w_l2 = u_e->w_list;
+- while (w_l2 && strcmp(w_l2->w->u.name, w->w->u.name))
++ while (w_l2 &&
++ strcmp(w_l2->w->u.name, w->w->u.name))
+ w_l2 = w_l2->next;
+ if (!w_l2 || !w->compare(w->w, w_l2->w))
+ goto letscontinue;
+@@ -743,8 +802,10 @@
+ struct ebt_u_watcher_list *w_l;
+
+ if (rule_nr != -1) { // command -I
+- if (--rule_nr > replace.hook_entry[replace.selected_hook]->nentries)
+- print_error("rule nr too high: %d > %d.", rule_nr, replace.hook_entry[replace.selected_hook]->nentries);
++ if (--rule_nr >
++ replace.hook_entry[replace.selected_hook]->nentries)
++ print_error("rule nr too high: %d > %d", rule_nr,
++ replace.hook_entry[replace.selected_hook]->nentries);
+ } else
+ rule_nr = replace.hook_entry[replace.selected_hook]->nentries;
+ // we're adding one rule
+@@ -754,7 +815,8 @@
+
+ // handle counter stuff
+ // +1 for CNT_END
+- if ( !(counterchanges = (unsigned short *)malloc((replace.nentries + 1) * sizeof(unsigned short))) )
++ if ( !(counterchanges = (unsigned short *)
++ malloc((replace.nentries + 1) * sizeof(unsigned short))) )
+ print_memory();
+ cnt = counterchanges;
+ for (i = 0; i < replace.selected_hook; i++) {
+@@ -813,7 +875,7 @@
+ struct ebt_u_entry *u_e, *u_e2;
+
+ if ( (i = check_rule_exists(rule_nr)) == -1 )
+- print_error("Sorry, rule does not exists.");
++ print_error("Sorry, rule does not exists");
+
+ // we're deleting a rule
+ replace.num_counters = replace.nentries;
+@@ -827,7 +889,8 @@
+ }
+ lentmp += i;
+ // +1 for CNT_END
+- if ( !(counterchanges = (unsigned short *)malloc((replace.num_counters + 1) * sizeof(unsigned short))) )
++ if ( !(counterchanges = (unsigned short *)malloc(
++ (replace.num_counters + 1) * sizeof(unsigned short))) )
+ print_memory();
+ cnt = counterchanges;
+ for (j = 0; j < lentmp; j++) {
+@@ -871,8 +934,8 @@
+
+ if (zerochain == -1) {
+ // tell main() we don't update the counters
+- // this results in tricking the kernel to zero his counters, naively expecting
+- // userspace to update its counters. Muahahaha
++ // this results in tricking the kernel to zero his counters,
++ // naively expecting userspace to update its counters. Muahahaha
+ counterchanges = NULL;
+ replace.num_counters = 0;
+ } else {
+@@ -881,7 +944,10 @@
+
+ if (replace.hook_entry[zerochain]->nentries == 0)
+ exit(0);
+- counterchanges = (unsigned short *)malloc((replace.nentries + 1) * sizeof(unsigned short));
++ counterchanges = (unsigned short *)
++ malloc((replace.nentries + 1) * sizeof(unsigned short));
++ if (!counterchanges)
++ print_memory();
+ cnt = counterchanges;
+ for (i = 0; i < zerochain; i++) {
+ if (!(replace.valid_hooks & (1 << i)))
+@@ -915,10 +981,12 @@
+
+ // 0 : database disabled (-db n)
+ if (!(nr.nentries))
+- print_error("Database not present (disabled), try ebtables --db y.");
+- (nr.nentries)--;
+- if (!nr.nentries) print_error("Database empty.");
+- if ( !(db = (struct brdb_dbentry *) malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
++ print_error("Database not present"
++ " (disabled), try ebtables --db y");
++ nr.nentries--;
++ if (!nr.nentries) print_error("Database empty");
++ if ( !(db = (struct brdb_dbentry *)
++ malloc(nr.nentries * sizeof(struct brdb_dbentry))) )
+ print_memory();
+
+ get_db(nr.nentries, db);
+@@ -931,7 +999,7 @@
+ "out-if : %s\n"
+ "protocol: ", i + 1, hooknames[db->hook], db->in, db->out);
+ if (db->ethproto == IDENTIFY802_3)
+- printf("NO PROTO, OLD 802.3 STYLE LENGTH FIELD\n");
++ printf("802.2/802.3 STYLE LENGTH FIELD\n");
+ else {
+ if (number_to_name(ntohs(db->ethproto), name))
+ printf("%x\n",ntohs(db->ethproto));
+@@ -943,13 +1011,13 @@
+ exit(0);
+ }
+
+-// handle counter and db disabling and enabling
++// handle db [dis,en]abling
+ static void allowdb(char yorn)
+ {
+ __u16 decision;
+
+ if (yorn != 'y' && yorn != 'n')
+- print_error("Option [y] or [n] needed.");
++ print_error("Option [y] or [n] needed");
+
+ if (yorn == 'y')
+ decision = BRDB_DB;
+@@ -980,7 +1048,8 @@
+ if (strcasecmp(buffer, name))
+ continue;
+ i = (unsigned short) strtol(value, &bfr, 16);
+- if (*bfr != '\0') return -1;
++ if (*bfr != '\0')
++ return -1;
+ new_entry->ethproto = i;
+ fclose(ifp);
+ return 0;
+@@ -1022,7 +1091,7 @@
+ void check_option(unsigned int *flags, unsigned int mask)
+ {
+ if (*flags & mask)
+- print_error("Multiple use of same option not allowed.");
++ print_error("Multiple use of same option not allowed");
+ *flags |= mask;
+ }
+
+@@ -1040,17 +1109,21 @@
+ {
+ char *buffer, allowbc = 'n';
+ int c, i;
+- int zerochain = -1; // this special one for the -Z option (we can have -Z <this> -L <that>)
++ // this special one for the -Z option (we can have -Z <this> -L <that>)
++ int zerochain = -1;
+ int policy = -1;
+ int rule_nr = -1;// used for -D chain number
+ struct ebt_u_target *t;
++ struct ebt_u_match *m;
++ struct ebt_u_watcher *w;
++ struct ebt_u_match_list *m_l;
++ struct ebt_u_watcher_list *w_l;
+
+- // initialize the table name, OPT_ flags and selected hook
++ // initialize the table name, OPT_ flags, selected hook and command
+ strcpy(replace.name, "filter");
+ replace.flags = 0;
+ replace.selected_hook = -1;
+ replace.command = 'h';
+- // execute the _init functions of the extensions
+
+ new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
+ if (!new_entry)
+@@ -1059,7 +1132,8 @@
+ initialize_entry(new_entry);
+
+ // getopt saves the day
+- while ((c = getopt_long(argc, argv, "-A:D:I:L::Z::F::P:Vhi:o:j:p:b:s:d:t:", ebt_options, NULL)) != -1) {
++ while ((c = getopt_long(argc, argv,
++ "-A:D:I:L::Z::F::P:Vhi:o:j:p:b:s:d:t:", ebt_options, NULL)) != -1) {
+ switch (c) {
+
+ case 'A': // add a rule
+@@ -1068,33 +1142,39 @@
+ case 'I': // insert a rule
+ replace.command = c;
+ if (replace.flags & OPT_COMMAND)
+- print_error("Multiple commands not allowed.");
++ print_error("Multiple commands not allowed");
+ replace.flags |= OPT_COMMAND;
+ if ((replace.selected_hook = get_hooknr(optarg)) == -1)
+- print_error("Bad chain.");
+- // '-' denotes another option, if no other option it must be the (optional) rule number
+- if (c == 'D' && optind < argc && argv[optind][0] != '-') {
++ print_error("Bad chain");
++ if (c == 'D' && optind < argc &&
++ argv[optind][0] != '-') {
+ rule_nr = strtol(argv[optind], &buffer, 10);
+ if (*buffer != '\0' || rule_nr < 0)
+- print_error("Problem with the specified rule number.");
++ print_error("Problem with the "
++ "specified rule number");
+ optind++;
+ }
+ if (c == 'P') {
+ if (optind >= argc)
+- print_error("No policy specified.");
++ print_error("No policy specified");
+ for (i = 0; i < 2; i++)
+- if (!strcmp(argv[optind], standard_targets[i]))
++ if (!strcmp(argv[optind],
++ standard_targets[i])) {
+ policy = i;
++ break;
++ }
+ if (policy == -1)
+- print_error("Wrong policy.");
++ print_error("Wrong policy");
+ optind++;
+ }
+ if (c == 'I') {
+ if (optind >= argc)
+- print_error("No rulenr for -I specified.");
++ print_error("No rulenr for -I"
++ " specified");
+ rule_nr = strtol(argv[optind], &buffer, 10);
+ if (*buffer != '\0' || rule_nr < 0)
+- print_error("Problem with the specified rule number.");
++ print_error("Problem with the specified"
++ " rule number");
+ optind++;
+ }
+ break;
+@@ -1104,24 +1184,29 @@
+ case 'Z': // zero counters
+ if (c == 'Z') {
+ if (replace.flags & OPT_ZERO)
+- print_error("Multiple commands not allowed.");
+- if ( (replace.flags & OPT_COMMAND && replace.command != 'L'))
+- print_error("command -Z only allowed together with command -L.");
++ print_error("Multiple commands"
++ " not allowed");
++ if ( (replace.flags & OPT_COMMAND &&
++ replace.command != 'L'))
++ print_error("command -Z only allowed "
++ "together with command -L");
+ replace.flags |= OPT_ZERO;
+ } else {
+ replace.command = c;
+ if (replace.flags & OPT_COMMAND)
+- print_error("Multiple commands not allowed.");
++ print_error("Multiple commands"
++ " not allowed");
+ replace.flags |= OPT_COMMAND;
+ }
+ i = -1;
+ if (optarg) {
+ if ( (i = get_hooknr(optarg)) == -1 )
+- print_error("Bad chain.");
++ print_error("Bad chain");
+ } else
+ if (optind < argc && argv[optind][0] != '-') {
+- if ( (i = get_hooknr(argv[optind])) == -1 )
+- print_error("Bad chain.");
++ if ((i = get_hooknr(argv[optind]))
++ == -1)
++ print_error("Bad chain");
+ optind++;
+ }
+ if (i != -1) {
+@@ -1135,47 +1220,34 @@
+ case 'V': // version
+ replace.command = 'V';
+ if (replace.flags & OPT_COMMAND)
+- print_error("Multiple commands not allowed.");
++ print_error("Multiple commands not allowed");
+ printf("%s, %s\n", prog_name, prog_version);
+ exit(0);
+
+ case 'h': // help
+ if (replace.flags & OPT_COMMAND)
+- print_error("Multiple commands not allowed.");
++ print_error("Multiple commands not allowed");
+ replace.command = 'h';
+ // All other arguments should be extension names
+ while (optind < argc) {
+ struct ebt_u_match *m;
+ struct ebt_u_watcher *w;
+
+- if ((m = find_match(argv[optind]))) {
+- struct ebt_u_match_list **m_list, *new;
+-
+- m->used = 1;
+- for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
+- new = (struct ebt_u_match_list *)malloc(sizeof(struct ebt_u_match_list));
+- if (!new)
+- print_memory();
+- *m_list = new;
+- new->next = NULL;
+- new->m = (struct ebt_entry_match *)m;
+- } else if ((w = find_watcher(argv[optind]))) {
+- struct ebt_u_watcher_list **w_list, *new;
+- w->used = 1;
+- for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
+- new = (struct ebt_u_watcher_list *)malloc(sizeof(struct ebt_u_watcher_list));
+- if (!new)
+- print_memory();
+- *w_list = new;
+- new->next = NULL;
+- new->w = (struct ebt_entry_watcher *)w;
+- } else {
++ if ((m = find_match(argv[optind])))
++ add_match(m);
++ else if ((w = find_watcher(argv[optind])))
++ add_watcher(w);
++ else {
+ if (!(t = find_target(argv[optind])))
+- print_error("Extension %s not found.", argv[optind]);
++ print_error("Extension %s "
++ "not found", argv[optind]);
+ if (replace.flags & OPT_JUMP)
+- print_error("Sorry, you can only see help for one target extension each time.");
++ print_error("Sorry, you can "
++ "only see help for one "
++ "target extension each time");
+ replace.flags |= OPT_JUMP;
+- new_entry->t = (struct ebt_entry_target *)t;
++ new_entry->t =
++ (struct ebt_entry_target *)t;
+ }
+ optind++;
+ }
+@@ -1184,7 +1256,7 @@
+ case 't': // table
+ check_option(&replace.flags, OPT_TABLE);
+ if (strlen(optarg) > EBT_TABLE_MAXNAMELEN)
+- print_error("Table name too long.");
++ print_error("Table name too long");
+ strcpy(replace.name, optarg);
+ break;
+
+@@ -1195,56 +1267,69 @@
+ case 's': // source mac
+ case 'd': // destination mac
+ if ((replace.flags & OPT_COMMAND) == 0)
+- print_error("No command specified.");
+- if ( replace.command != 'A' && replace.command != 'D' && replace.command != 'I')
+- print_error("Command and option do not match.");
++ print_error("No command specified");
++ if ( replace.command != 'A' &&
++ replace.command != 'D' && replace.command != 'I')
++ print_error("Command and option do not match");
+ if (c == 'i') {
+ check_option(&replace.flags, OPT_IN);
+- if (replace.selected_hook == 2)
+- print_error("Use in-interface only in INPUT, FORWARD and PREROUTING chains.");
++ if (replace.selected_hook > 2)
++ print_error("Use in-interface only in "
++ "INPUT, FORWARD and PREROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_IIN;
+
+ if (optind > argc)
+- print_error("Missing interface argument.");
++ print_error("No in-interface "
++ "specified");
+ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
+- print_error("Illegal interfacelength.");
+- strncpy(new_entry->in, argv[optind - 1], IFNAMSIZ);
++ print_error("Illegal interfacelength");
++ strcpy(new_entry->in, argv[optind - 1]);
+ break;
+ }
+ if (c == 'o') {
+ check_option(&replace.flags, OPT_OUT);
+- if (replace.selected_hook == 0)
+- print_error("Use out-interface only in OUTPUT, FORWARD and POSTROUTING chains.");
++ if (replace.selected_hook < 2)
++ print_error("Use out-interface only"
++ " in OUTPUT, FORWARD and "
++ "POSTROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_IOUT;
+
+ if (optind > argc)
+- print_error("Missing interface argument.");
++ print_error("No out-interface "
++ "specified");
++
+ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
+- print_error("Illegal interface length.");
+- strncpy(new_entry->out, argv[optind - 1], IFNAMSIZ);
++ print_error("Illegal interface "
++ "length");
++ strcpy(new_entry->out, argv[optind - 1]);
+ break;
+ }
+ if (c == 'j') {
+
+ check_option(&replace.flags, OPT_JUMP);
+ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
+- if (!strcmp(optarg, standard_targets[i])) {
+- t = find_target(EBT_STANDARD_TARGET);
+- ((struct ebt_standard_target *)t->t)->verdict = i;
++ if (!strcmp(optarg,
++ standard_targets[i])) {
++ t = find_target(
++ EBT_STANDARD_TARGET);
++ ((struct ebt_standard_target *)
++ t->t)->verdict = i;
+ break;
+ }
+ // must be an extension then
+ if (i == NUM_STANDARD_TARGETS) {
+ struct ebt_u_target *t;
+ t = find_target(optarg);
+- if (!t)
+- print_error("Illegal target name.");
+- new_entry->t = (struct ebt_entry_target *)t;
+- } else
+- ((struct ebt_standard_target *)(((struct ebt_u_target *)new_entry->t)->t))->verdict = i;
+-
++ // -j standard not allowed either
++ if (!t || t ==
++ (struct ebt_u_target *)new_entry->t)
++ print_error("Illegal target "
++ "name");
++ new_entry->t =
++ (struct ebt_entry_target *)t;
++ }
+ break;
+ }
+ if (c == 's') {
+@@ -1253,9 +1338,12 @@
+ new_entry->invflags |= EBT_ISOURCE;
+
+ if (optind > argc)
+- print_error("Missing source mac argument.");
+- if (getmac(argv[optind - 1], new_entry->sourcemac))
+- print_error("Problem with specified source mac.");
++ print_error("No source mac "
++ "specified");
++ if (getmac(argv[optind - 1],
++ new_entry->sourcemac))
++ print_error("Problem with specified "
++ "source mac");
+ new_entry->bitmask |= EBT_SOURCEMAC;
+ break;
+ }
+@@ -1265,9 +1353,12 @@
+ new_entry->invflags |= EBT_IDEST;
+
+ if (optind > argc)
+- print_error("Missing destination mac argument.");
+- if (getmac(argv[optind - 1], new_entry->destmac))
+- print_error("Problem with specified destination mac.");
++ print_error("No destination mac "
++ "specified");
++ if (getmac(argv[optind - 1],
++ new_entry->destmac))
++ print_error("Problem with specified "
++ "destination mac");
+ new_entry->bitmask |= EBT_DESTMAC;
+ break;
+ }
+@@ -1276,22 +1367,26 @@
+ new_entry->invflags |= EBT_IPROTO;
+
+ if (optind > argc)
+- print_error("Missing protocol argument.");
++ print_error("No protocol specified");
+ new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
+ i = strtol(argv[optind - 1], &buffer, 16);
+ if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
+- print_error("Problem with the specified protocol.");
++ print_error("Problem with the specified "
++ "protocol");
+ new_entry->ethproto = i;
+ if (*buffer != '\0')
+ if (name_to_protocol(argv[optind - 1]) == -1)
+- print_error("Problem with the specified protocol.");
+- if (new_entry->ethproto < 1536 && !(new_entry->bitmask & EBT_802_3))
+- print_error("Sorry, protocols have values above or equal to 1536 (0x0600).");
++ print_error("Problem with the specified"
++ " protocol");
++ if (new_entry->ethproto < 1536 &&
++ !(new_entry->bitmask & EBT_802_3))
++ print_error("Sorry, protocols have values above"
++ " or equal to 1536 (0x0600)");
+ break;
+
+ case 'b': // allow database?
+ if (replace.flags & OPT_COMMAND)
+- print_error("Multiple commands not allowed.");
++ print_error("Multiple commands not allowed");
+ replace.command = c;
+ allowbc = *optarg;
+ break;
+@@ -1300,49 +1395,32 @@
+
+ // is it a target option?
+ t = (struct ebt_u_target *)new_entry->t;
+- if (!(t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) {
+- struct ebt_u_match *m;
+-
+- // is it a match_option?
+- for (m = matches; m; m = m->next)
+- if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m))
+- break;
++ if ((t->parse(c - t->option_offset, argv, argc,
++ new_entry, &t->flags, &t->t)))
++ continue;
+
+- if (m == NULL) {
+- struct ebt_u_watcher *w;
++ // is it a match_option?
++ for (m = matches; m; m = m->next)
++ if (m->parse(c - m->option_offset, argv,
++ argc, new_entry, &m->flags, &m->m))
++ break;
+
+- // is it a watcher option?
+- for (w = watchers; w; w = w->next)
+- if (w->parse(c - w->option_offset, argv, argc, new_entry, &w->flags, &w->w))
+- break;
+-
+- if (w == NULL)
+- print_error("Unknown argument.");
+- if (w->used == 0) {
+- struct ebt_u_watcher_list **w_list, *new;
+- w->used = 1;
+- for (w_list = &new_entry->w_list; *w_list; w_list = &(*w_list)->next);
+- new = (struct ebt_u_watcher_list *)malloc(sizeof(struct ebt_u_watcher_list));
+- if (!new)
+- print_memory();
+- *w_list = new;
+- new->next = NULL;
+- new->w = (struct ebt_entry_watcher *)w;
+- }
+- } else {
+- if (m->used == 0) {
+- struct ebt_u_match_list **m_list, *new;
+- m->used = 1;
+- for (m_list = &new_entry->m_list; *m_list; m_list = &(*m_list)->next);
+- new = (struct ebt_u_match_list *)malloc(sizeof(struct ebt_u_match_list));
+- if (!new)
+- print_memory();
+- *m_list = new;
+- new->next = NULL;
+- new->m = (struct ebt_entry_match *)m;
+- }
+- }
++ if (m != NULL) {
++ if (m->used == 0)
++ add_match(m);
++ continue;
+ }
++
++ // is it a watcher option?
++ for (w = watchers; w; w = w->next)
++ if (w->parse(c-w->option_offset, argv,
++ argc, new_entry, &w->flags, &w->w))
++ break;
++
++ if (w == NULL)
++ print_error("Unknown argument");
++ if (w->used == 0)
++ add_watcher(w);
+ }
+ }
+
+@@ -1352,43 +1430,40 @@
+ if (replace.command == 'L' && replace.selected_hook == DATABASEHOOKNR)
+ list_db();
+
+- if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' && replace.flags & OPT_ZERO )
+- print_error("Command -Z only allowed together with command -L.");
++ if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
++ replace.flags & OPT_ZERO )
++ print_error("Command -Z only allowed together with command -L");
+
+- if (replace.command == 'A' || replace.command == 'I' || replace.command == 'D') {
++ if (replace.command == 'A' || replace.command == 'I' ||
++ replace.command == 'D') {
+ if (replace.selected_hook == -1)
+- print_error("Not enough information.");
++ print_error("Not enough information");
+ }
+
+ if ( !(table = find_table(replace.name)) )
+- print_error("Bad table name.");
++ print_error("Bad table name");
+
+ // do this after parsing everything, so we can print specific info
+ if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
+ print_help();
+
+ // do the final checks
+- {
+- struct ebt_u_match_list *m_l = new_entry->m_list;
+- struct ebt_u_match *m;
+- struct ebt_u_watcher_list *w_l = new_entry->w_list;
+- struct ebt_u_watcher *w;
+- struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t;
+-
++ m_l = new_entry->m_list;
++ w_l = new_entry->w_list;
++ t = (struct ebt_u_target *)new_entry->t;
+ while (m_l) {
+ m = (struct ebt_u_match *)(m_l->m);
+- m->final_check(new_entry, m->m, replace.name, replace.selected_hook);
++ m->final_check(new_entry, m->m, replace.name,
++ replace.selected_hook);
+ m_l = m_l->next;
+ }
+-
+ while (w_l) {
+ w = (struct ebt_u_watcher *)(w_l->w);
+- w->final_check(new_entry, w->w, replace.name, replace.selected_hook);
++ w->final_check(new_entry, w->w, replace.name,
++ replace.selected_hook);
+ w_l = w_l->next;
+ }
+-
+ t->final_check(new_entry, t->t, replace.name, replace.selected_hook);
+- }
+
+ // so, the extensions can work with the host endian
+ // the kernel does not have to do this ofcourse
+@@ -1396,10 +1471,10 @@
+
+ // get the kernel's information
+ get_table(&replace);
+- replace.nentries = replace.nentries;
+ // check if selected_hook is a valid_hook
+- if (replace.selected_hook >= 0 && !(replace.valid_hooks & (1 << replace.selected_hook)))
+- print_error("Bad chain name.");
++ if (replace.selected_hook >= 0 &&
++ !(replace.valid_hooks & (1 << replace.selected_hook)))
++ print_error("Bad chain name");
+ if (replace.command == 'P')
+ change_policy(policy);
+ else if (replace.command == 'L') {
+--- ebtables-v2.0pre2.001/communication.c Wed Apr 3 17:22:39 2002
++++ ebtables-v2.0pre2.002/communication.c Wed Apr 10 22:10:49 2002
+@@ -25,12 +25,6 @@
+
+ extern char* hooknames[NF_BR_NUMHOOKS];
+
+-void print_memory()
+-{
+- printf("Out of memory\n");
+- exit(0);
+-}
+-
+ int sockfd = -1;
+
+ void get_sockfd()
+@@ -38,7 +32,7 @@
+ if (sockfd == -1) {
+ sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
+ if (sockfd < 0)
+- print_error("Problem getting a socket.");
++ print_error("Problem getting a socket");
+ }
+ }
+
+@@ -60,7 +54,8 @@
+ new->nentries = u_repl->nentries;
+ new->num_counters = u_repl->num_counters;
+ new->counters = u_repl->counters;
+- memcpy(new->counter_entry, u_repl->counter_entry, sizeof(new->counter_entry));
++ memcpy(new->counter_entry, u_repl->counter_entry,
++ sizeof(new->counter_entry));
+ // determine size
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+ if (!(new->valid_hooks & (1 << i)))
+@@ -86,7 +81,8 @@
+ }
+ // a little sanity check
+ if (j != u_repl->hook_entry[i]->nentries)
+- print_bug("Wrong nentries: %d != %d, hook = %s", j, u_repl->hook_entry[i]->nentries, hooknames[i]);
++ print_bug("Wrong nentries: %d != %d, hook = %s", j,
++ u_repl->hook_entry[i]->nentries, hooknames[i]);
+ }
+
+ new->entries_size = entries_size;
+@@ -116,7 +112,8 @@
+ tmp->ethproto = e->ethproto;
+ memcpy(tmp->in, e->in, sizeof(tmp->in));
+ memcpy(tmp->out, e->out, sizeof(tmp->out));
+- memcpy(tmp->sourcemac, e->sourcemac, sizeof(tmp->sourcemac));
++ memcpy(tmp->sourcemac, e->sourcemac,
++ sizeof(tmp->sourcemac));
+ memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
+
+ base = p;
+@@ -159,11 +156,13 @@
+ // give the data to the kernel
+ optlen = sizeof(struct ebt_replace) + repl->entries_size;
+ if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
+- print_error("Couldn't update kernel chains, you probably need to insmod an extension.");
++ print_error("Couldn't update kernel chains, you probably need "
++ "to insmod an extension");
+ }
+
+ // gets executed after deliver_table
+-void deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
++void
++deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
+ {
+ unsigned short *point;
+ struct ebt_counter *old, *new, *newcounters;
+@@ -173,7 +172,8 @@
+ if (u_repl->nentries == 0)
+ return;
+
+- newcounters = (struct ebt_counter *)malloc(u_repl->nentries * sizeof(struct ebt_counter));
++ newcounters = (struct ebt_counter *)
++ malloc(u_repl->nentries * sizeof(struct ebt_counter));
+ if (!newcounters)
+ print_memory();
+ memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
+@@ -208,7 +208,8 @@
+ free(u_repl->counters);
+ u_repl->counters = newcounters;
+ u_repl->num_counters = u_repl->nentries;
+- optlen = u_repl->nentries * sizeof(struct ebt_counter) + sizeof(struct ebt_replace);
++ optlen = u_repl->nentries * sizeof(struct ebt_counter) +
++ sizeof(struct ebt_replace);
+ // now put the stuff in the kernel's struct ebt_replace
+ repl.counters = u_repl->counters;
+ repl.num_counters = u_repl->num_counters;
+@@ -224,7 +225,8 @@
+ {
+ struct ebt_u_match_list *new;
+
+- new = (struct ebt_u_match_list *)malloc(sizeof(struct ebt_u_match_list));
++ new = (struct ebt_u_match_list *)
++ malloc(sizeof(struct ebt_u_match_list));
+ if (!new)
+ print_memory();
+ new->m = (struct ebt_entry_match *)malloc(m->match_size);
+@@ -235,12 +237,14 @@
+ **l = new;
+ *l = &new->next;
+ if (find_match(new->m->u.name) == NULL)
+- print_error("Kernel match %s unsupported by userspace tool.", new->m->u.name);
++ print_error("Kernel match %s unsupported by userspace tool",
++ new->m->u.name);
+ return 0;
+ }
+
+ static int
+-ebt_translate_watcher(struct ebt_entry_watcher *w, struct ebt_u_watcher_list ***l)
++ebt_translate_watcher(struct ebt_entry_watcher *w,
++ struct ebt_u_watcher_list ***l)
+ {
+ struct ebt_u_watcher_list *new;
+
+@@ -255,13 +259,15 @@
+ **l = new;
+ *l = &new->next;
+ if (find_watcher(new->w->u.name) == NULL)
+- print_error("Kernel watcher %s unsupported by userspace tool.", new->w->u.name);
++ print_error("Kernel watcher %s unsupported by userspace tool",
++ new->w->u.name);
+ return 0;
+ }
+
+ static int
+-ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, int *totalcnt,
+- struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl, unsigned int valid_hooks)
++ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
++ int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
++ unsigned int valid_hooks)
+ {
+ // an entry
+ if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
+@@ -295,7 +301,8 @@
+ if (!new->t)
+ print_memory();
+ if (find_target(t->u.name) == NULL)
+- print_error("Kernel target %s unsupported by userspace tool.", t->u.name);
++ print_error("Kernel target %s unsupported by "
++ "userspace tool", t->u.name);
+ memcpy(new->t, t, t->target_size);
+
+ // I love pointers
+@@ -304,7 +311,7 @@
+ (*cnt)++;
+ (*totalcnt)++;
+ return 0;
+- } else {// a new chain
++ } else { // a new chain
+ int i;
+ struct ebt_entries *entries = (struct ebt_entries *)e;
+ struct ebt_u_entries *new;
+@@ -319,7 +326,8 @@
+ print_bug("Nr of entries in the chain is wrong");
+ *n = entries->nentries;
+ *cnt = 0;
+- new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries));
++ new = (struct ebt_u_entries *)
++ malloc(sizeof(struct ebt_u_entries));
+ if (!new)
+ print_memory();
+ new->nentries = entries->nentries;
+@@ -344,12 +352,14 @@
+ optlen = sizeof(struct ebt_replace);
+ strcpy(repl.name, u_repl->name);
+ if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_INFO, &repl, &optlen))
+- print_bug("hmm, what is wrong??? bug#3");
++ print_error("A kernel module needed by your command is probably"
++ " not loaded. Try insmod ebtables or the like");
+
+ if ( !(repl.entries = (char *) malloc(repl.entries_size)) )
+ print_memory();
+ if (repl.nentries) {
+- if (!(repl.counters = (struct ebt_counter *) malloc(repl.nentries * sizeof(struct ebt_counter))) )
++ if (!(repl.counters = (struct ebt_counter *)
++ malloc(repl.nentries * sizeof(struct ebt_counter))) )
+ print_memory();
+ }
+ else
+@@ -357,7 +367,8 @@
+
+ // we want to receive the counters
+ repl.num_counters = repl.nentries;
+- optlen += repl.entries_size + repl.num_counters * sizeof(struct ebt_counter);
++ optlen += repl.entries_size + repl.num_counters *
++ sizeof(struct ebt_counter);
+ if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_ENTRIES, &repl, &optlen))
+ print_bug("hmm, what is wrong??? bug#1");
+
+@@ -367,12 +378,15 @@
+ u_repl->nentries = repl.nentries;
+ u_repl->num_counters = repl.num_counters;
+ u_repl->counters = repl.counters;
+- memcpy(u_repl->counter_entry, repl.counter_entry, sizeof(repl.counter_entry));
++ memcpy(u_repl->counter_entry, repl.counter_entry,
++ sizeof(repl.counter_entry));
+ hook = -1;
+ i = 0; // holds the expected nr. of entries for the chain
+ j = 0; // holds the up to now counted entries for the chain
+- k = 0; // holds the total nr. of entries, should equal u_repl->nentries afterwards
+- EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks);
++ k = 0; // holds the total nr. of entries,
++ // should equal u_repl->nentries afterwards
++ EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
++ &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks);
+ if (k != u_repl->nentries)
+ print_bug("Wrong total nentries");
+ }
+@@ -384,7 +398,8 @@
+ get_sockfd();
+
+ if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen))
+- print_error("Sorry, br_db code probably not in kernel, try insmod br_db.");
++ print_error("Sorry, br_db code probably not in kernel, "
++ "try insmod br_db");
+ }
+
+ void get_db(int len, struct brdb_dbentry *db)
+@@ -405,5 +420,6 @@
+ get_sockfd();
+
+ if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB, decision, optlen))
+- print_error("Sorry, br_db code probably not in kernel, try insmod br_db.");
++ print_error("Sorry, br_db code probably not in kernel, "
++ "try insmod br_db");
+ }
+--- ebtables-v2.0pre2.001/extensions/ebt_nat.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/extensions/ebt_nat.c Thu Apr 11 18:12:55 2002
+@@ -52,8 +52,9 @@
+ }
+
+ #define OPT_SNAT 0x01
+-static int parse_s(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags,
+- struct ebt_entry_target **target)
++static int parse_s(int c, char **argv, int argc,
++ const struct ebt_u_entry *entry, unsigned int *flags,
++ struct ebt_entry_target **target)
+ {
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
+
+@@ -62,7 +63,7 @@
+ check_option(flags, OPT_SNAT);
+ to_source_supplied = 1;
+ if (getmac(optarg, natinfo->mac))
+- print_error("Problem with specified to-source mac.");
++ print_error("Problem with specified to-source mac");
+ break;
+ default:
+ return 0;
+@@ -71,8 +72,9 @@
+ }
+
+ #define OPT_DNAT 0x01
+-static int parse_d(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags,
+- struct ebt_entry_target **target)
++static int parse_d(int c, char **argv, int argc,
++ const struct ebt_u_entry *entry, unsigned int *flags,
++ struct ebt_entry_target **target)
+ {
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
+
+@@ -81,7 +83,8 @@
+ check_option(flags, OPT_DNAT);
+ to_dest_supplied = 1;
+ if (getmac(optarg, natinfo->mac))
+- print_error("Problem with specified to-destination mac.");
++ print_error("Problem with specified "
++ "to-destination mac");
+ break;
+ default:
+ return 0;
+@@ -89,44 +92,52 @@
+ return 1;
+ }
+
+-static void final_check_s(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hook)
++static void final_check_s(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+ {
+ if (hook != NF_BR_POST_ROUTING || strcmp(name, "nat"))
+- print_error("Wrong chain for SNAT.");
++ print_error("Wrong chain for SNAT");
+ if (to_source_supplied == 0)
+- print_error("No snat address supplied.");
++ print_error("No snat address supplied");
+
+ }
+
+-static void final_check_d(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hook)
++static void final_check_d(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+ {
+- if ( (hook != NF_BR_PRE_ROUTING && hook != NF_BR_LOCAL_OUT) || strcmp(name, "nat") )
+- print_error("Wrong chain for DNAT.");
++ if ( (hook != NF_BR_PRE_ROUTING && hook != NF_BR_LOCAL_OUT) ||
++ strcmp(name, "nat") )
++ print_error("Wrong chain for DNAT");
+ if (to_dest_supplied == 0)
+- print_error("No dnat address supplied.");
++ print_error("No dnat address supplied");
+ }
+
+-static void print_s(const struct ebt_u_entry *entry, const struct ebt_entry_target *target)
++static void print_s(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target)
+ {
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
+ int i;
+
+ printf("snat - to: ");
+ for (i = 0; i < ETH_ALEN; i++)
+- printf("%02x%s", natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
++ printf("%02x%s",
++ natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
+ }
+
+-static void print_d(const struct ebt_u_entry *entry, const struct ebt_entry_target *target)
++static void print_d(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target)
+ {
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
+ int i;
+
+ printf("dnat - to: ");
+ for (i = 0; i < ETH_ALEN; i++)
+- printf("%02x%s", natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
++ printf("%02x%s",
++ natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
+ }
+
+-static int compare(const struct ebt_entry_target *t1, const struct ebt_entry_target *t2)
++static int compare(const struct ebt_entry_target *t1,
++ const struct ebt_entry_target *t2)
+ {
+ struct ebt_nat_info *natinfo1 = (struct ebt_nat_info *)t1->data;
+ struct ebt_nat_info *natinfo2 = (struct ebt_nat_info *)t2->data;
+--- ebtables-v2.0pre2.001/extensions/ebt_ip.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/extensions/ebt_ip.c Wed Apr 10 23:28:40 2002
+@@ -40,16 +40,16 @@
+ return -1;
+ *q = '\0';
+ onebyte = strtol(p, &end, 10);
+- if (*end != '\0' || onebyte >255 || onebyte < 0)
++ if (*end != '\0' || onebyte > 255 || onebyte < 0)
+ return -1;
+- ip2[i] = (unsigned char) onebyte;
++ ip2[i] = (unsigned char)onebyte;
+ p = q + 1;
+ }
+
+ onebyte = strtol(p, &end, 10);
+ if (*end != '\0' || onebyte >255 || onebyte < 0)
+ return -1;
+- ip2[3] = (unsigned char) onebyte;
++ ip2[3] = (unsigned char)onebyte;
+
+ return 0;
+ }
+@@ -88,15 +88,15 @@
+ *p = '\0';
+ i = ip_mask(p + 1, (unsigned char *)msk);
+ if (i)
+- print_error("Problem with the ip mask.");
++ print_error("Problem with the ip mask");
+ }
+ else
+ *msk = 0xFFFFFFFF;
+
+ i = undot_ip(address, (unsigned char *)addr);
+- *addr = *addr & *msk;
+ if (i)
+- print_error("Problem with the ip address.");
++ print_error("Problem with the ip address");
++ *addr = *addr & *msk;
+ }
+
+ // transform the ip mask into a string ready for output
+@@ -106,7 +106,6 @@
+ static char buf[20];
+ __u32 maskaddr, bits;
+
+- // cool hack I copied from iptables.c ... Think about it :-)
+ maskaddr = ntohl(mask);
+
+ // don't print /32
+@@ -114,7 +113,7 @@
+ return "";
+
+ i = 32;
+- bits = 0xFFFFFFFEL;// case 0xFFFFFFFF has just been dealt with
++ bits = 0xFFFFFFFEL; // case 0xFFFFFFFF has just been dealt with
+ while (--i >= 0 && maskaddr != bits)
+ bits <<= 1;
+
+@@ -123,9 +122,10 @@
+ else if (!i)
+ *buf = '\0';
+ else
+- /* mask was not a decent combination of 1's and 0's */
+- sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0], ((unsigned char *)&mask)[1],
+- ((unsigned char *)&mask)[2], ((unsigned char *)&mask)[3]);
++ // mask was not a decent combination of 1's and 0's
++ sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
++ ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
++ ((unsigned char *)&mask)[3]);
+
+ return buf;
+ }
+@@ -133,11 +133,11 @@
+ static void print_help()
+ {
+ printf(
+- "ip options:\n"
+- "--ip-src [!] address[/mask]: ip source specification\n"
+- "--ip-dst [!] address[/mask]: ip destination specification\n"
+- "--ip-tos [!] tos : ip tos specification\n"
+- "--ip-proto [!] protocol : ip protocol specification\n");
++"ip options:\n"
++"--ip-src [!] address[/mask]: ip source specification\n"
++"--ip-dst [!] address[/mask]: ip destination specification\n"
++"--ip-tos [!] tos : ip tos specification\n"
++"--ip-proto [!] protocol : ip protocol specification\n");
+ }
+
+ static void init(struct ebt_entry_match *match)
+@@ -152,9 +152,8 @@
+ #define OPT_DEST 0x02
+ #define OPT_TOS 0x04
+ #define OPT_PROTO 0x08
+-static int parse(int c, char **argv, int argc,
+- const struct ebt_u_entry *entry, unsigned int *flags,
+- struct ebt_entry_match **match)
++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, *buffer;
+@@ -163,13 +162,13 @@
+ switch (c) {
+ case IP_SOURCE:
+ check_option(flags, OPT_SOURCE);
++ ipinfo->bitmask |= EBT_IP_SOURCE;
++
+ case IP_DEST:
+- if (c == IP_DEST)
++ if (c == IP_DEST) {
+ check_option(flags, OPT_DEST);
+- if (c == IP_SOURCE)
+- ipinfo->bitmask |= EBT_IP_SOURCE;
+- else
+ ipinfo->bitmask |= EBT_IP_DEST;
++ }
+ if (check_inverse(optarg)) {
+ if (c == IP_SOURCE)
+ ipinfo->invflags |= EBT_IP_SOURCE;
+@@ -178,34 +177,38 @@
+ }
+
+ if (optind > argc)
+- print_error("Missing ip address argument.");
++ print_error("Missing ip address argument");
+ if (c == IP_SOURCE)
+- parse_ip_address(argv[optind - 1], &ipinfo->saddr, &ipinfo->smsk);
++ parse_ip_address(argv[optind - 1], &ipinfo->saddr,
++ &ipinfo->smsk);
+ else
+- parse_ip_address(argv[optind - 1], &ipinfo->daddr, &ipinfo->dmsk);
++ parse_ip_address(argv[optind - 1], &ipinfo->daddr,
++ &ipinfo->dmsk);
+ break;
++
+ case IP_myTOS:
+ check_option(flags, OPT_TOS);
+ if (check_inverse(optarg))
+ ipinfo->invflags |= EBT_IP_TOS;
+
+ if (optind > argc)
+- print_error("Missing ip tos argument.");
++ print_error("Missing ip tos argument");
+ i = strtol(argv[optind - 1], &end, 16);
+ if (i < 0 || i > 255 || *buffer != '\0')
+- print_error("Problem with specified ip tos.");
++ print_error("Problem with specified ip tos");
+ ipinfo->tos = i;
+ ipinfo->bitmask |= EBT_IP_TOS;
+ break;
++
+ case IP_PROTO:
+ check_option(flags, OPT_PROTO);
+ if (check_inverse(optarg))
+ ipinfo->invflags |= EBT_IP_PROTO;
+ if (optind > argc)
+- print_error("Missing ip protocol argument.");
++ print_error("Missing ip protocol argument");
+ i = strtol(argv[optind - 1], &end, 10);
+ if (i < 0 || i > 255 || *end != '\0')
+- print_error("Problem with specified ip protocol.");
++ print_error("Problem with specified ip protocol");
+ ipinfo->protocol = i;
+ ipinfo->bitmask |= EBT_IP_PROTO;
+ break;
+@@ -215,13 +218,17 @@
+ return 1;
+ }
+
+-static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hook)
++static void final_check(const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match, const char *name, unsigned int hook)
+ {
+- if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 || entry->ethproto != ETH_P_IP)
+- print_error("For IP filtering the protocol must be specified as IPV4.");
++ if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 ||
++ entry->ethproto != ETH_P_IP)
++ print_error("For IP filtering the protocol must be "
++ "specified as IPv4");
+ }
+
+-static void print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match)
++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;
+@@ -231,7 +238,8 @@
+ if (ipinfo->invflags & EBT_IP_SOURCE)
+ printf("! ");
+ for (j = 0; j < 4; j++)
+- printf("%d%s", ((unsigned char *)&ipinfo->saddr)[j], (j == 3) ? "" : ".");
++ printf("%d%s",((unsigned char *)&ipinfo->saddr)[j],
++ (j == 3) ? "" : ".");
+ printf("%s, ", mask_to_dotted(ipinfo->smsk));
+ }
+ if (ipinfo->bitmask & EBT_IP_DEST) {
+@@ -239,7 +247,8 @@
+ if (ipinfo->invflags & EBT_IP_DEST)
+ printf("! ");
+ for (j = 0; j < 4; j++)
+- printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j], (j == 3) ? "" : ".");
++ printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j],
++ (j == 3) ? "" : ".");
+ printf("%s, ", mask_to_dotted(ipinfo->dmsk));
+ }
+ if (ipinfo->bitmask & EBT_IP_TOS) {
+@@ -256,7 +265,8 @@
+ }
+ }
+
+-static int compare(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2)
++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;
+--- ebtables-v2.0pre2.001/extensions/ebt_arp.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/extensions/ebt_arp.c Wed Apr 10 23:05:29 2002
+@@ -44,20 +44,20 @@
+ int i = 0;
+
+ printf(
+- "arp options:\n"
+- "--arp-opcode opcode : ARP opcode (integer or string)\n"
+- "--arp-htype type : ARP hardware type (integer or string)\n"
+- "--arp-ptype type : ARP protocol type (hexadecimal or string)\n"
+- "--arp-ip-src [!] address[/mask]: ARP ip source specification\n"
+- "--arp-ip-dst [!] address[/mask]: ARP ip target specification\n"
+- " opcode strings: \n");
++"arp options:\n"
++"--arp-opcode opcode : ARP opcode (integer or string)\n"
++"--arp-htype type : ARP hardware type (integer or string)\n"
++"--arp-ptype type : ARP protocol type (hexadecimal or string)\n"
++"--arp-ip-src [!] address[/mask]: ARP ip source specification\n"
++"--arp-ip-dst [!] address[/mask]: ARP ip target specification\n"
++" opcode strings: \n");
+ while (strcmp(opcodes[i], "")) {
+ printf("%d = %s\n", i + 1, opcodes[i]);
+ i++;
+ }
+ printf(
+- " hardware type string: \n 1 = Ethernet\n"
+- " protocol type string: \n 0x0800 = IPv4\n");
++" hardware type string: \n 1 = Ethernet\n"
++" protocol type string: \n 0x0800 = IPv4\n");
+ }
+
+ static void init(struct ebt_entry_match *match)
+@@ -68,7 +68,8 @@
+ arpinfo->bitmask = 0;
+ }
+
+-void parse_ip_address(char *address, __u32 *addr, __u32 *msk); // defined in ebt_ip.c
++// defined in ebt_ip.c
++void parse_ip_address(char *address, __u32 *addr, __u32 *msk);
+
+ #define OPT_OPCODE 0x01
+ #define OPT_HTYPE 0x02
+@@ -87,15 +88,14 @@
+
+ switch (c) {
+ case ARP_OPCODE:
+-
+ check_option(flags, OPT_OPCODE);
+ if (check_inverse(optarg))
+ arpinfo->invflags |= EBT_ARP_OPCODE;
+
+ if (optind > argc)
+- print_error("Missing arp opcode argument.");
++ print_error("Missing arp opcode argument");
+ i = strtol(argv[optind - 1], &end, 10);
+- if (i < 0 || i > (0x1 << 16) || *end !='\0') {
++ if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
+ i = 0;
+ while (strcmp(opcodes[i], "")) {
+ if (!strcasecmp(opcodes[i], optarg))
+@@ -103,7 +103,8 @@
+ i++;
+ }
+ if (!strcmp(opcodes[i], ""))
+- print_error("Problem with specified arp opcode.");
++ print_error("Problem with specified "
++ "arp opcode");
+ }
+ arpinfo->opcode = htons(i);
+ arpinfo->bitmask |= EBT_ARP_OPCODE;
+@@ -115,13 +116,14 @@
+ arpinfo->invflags |= EBT_ARP_HTYPE;
+
+ if (optind > argc)
+- print_error("Missing arp hardware type argument.");
++ print_error("Missing arp hardware type argument");
+ i = strtol(argv[optind - 1], &end, 10);
+- if (i < 0 || i > (0x1 << 16) || *end !='\0') {
++ if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
+ if (!strcasecmp("Ethernet", argv[optind - 1]))
+ i = 1;
+ else
+- print_error("Problem with specified arp hardware type.");
++ print_error("Problem with specified arp "
++ "hardware type");
+ }
+ arpinfo->htype = htons(i);
+ arpinfo->bitmask |= EBT_ARP_HTYPE;
+@@ -133,13 +135,14 @@
+ arpinfo->invflags |= EBT_ARP_PTYPE;
+
+ if (optind > argc)
+- print_error("Missing arp protocol type argument.");
++ print_error("Missing arp protocol type argument");
+ i = strtol(argv[optind - 1], &end, 16);
+- if (i < 0 || i > (0x1 << 16) || *end !='\0') {
++ if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
+ if (!strcasecmp("IPv4", argv[optind - 1]))
+ i = 0x0800;
+ else
+- print_error("Problem with specified arp protocol type.");
++ print_error("Problem with specified arp "
++ "protocol type");
+ }
+ arpinfo->ptype = htons(i);
+ arpinfo->bitmask |= EBT_ARP_PTYPE;
+@@ -165,7 +168,7 @@
+ arpinfo->invflags |= EBT_ARP_DST_IP;
+ }
+ if (optind > argc)
+- print_error("Missing ip address argument.");
++ print_error("Missing ip address argument");
+ parse_ip_address(argv[optind - 1], addr, mask);
+ break;
+ default:
+@@ -174,14 +177,19 @@
+ return 1;
+ }
+
+-static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hook)
++static void final_check(const struct ebt_u_entry *entry,
++const struct ebt_entry_match *match, const char *name, unsigned int hook)
+ {
+- if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 || (entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP))
+- print_error("For (R)ARP filtering the protocol must be specified as ARP or RARP.");
++ if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 ||
++ (entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP))
++ print_error("For (R)ARP filtering the protocol must be "
++ "specified as ARP or RARP");
+ }
+
+-char *mask_to_dotted(__u32 mask); // defined in the ebt_ip.c
+-static void print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match)
++// defined in the ebt_ip.c
++char *mask_to_dotted(__u32 mask);
++static void print(const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match)
+ {
+ struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data;
+ int i;
+@@ -209,7 +217,8 @@
+ if (arpinfo->invflags & EBT_ARP_SRC_IP)
+ printf("! ");
+ for (i = 0; i < 4; i++)
+- printf("%d%s", ((unsigned char *)&arpinfo->saddr)[i], (i == 3) ? "" : ".");
++ printf("%d%s", ((unsigned char *)&arpinfo->saddr)[i],
++ (i == 3) ? "" : ".");
+ printf("%s, ", mask_to_dotted(arpinfo->smsk));
+ }
+ if (arpinfo->bitmask & EBT_ARP_DST_IP) {
+@@ -217,12 +226,14 @@
+ if (arpinfo->invflags & EBT_ARP_DST_IP)
+ printf("! ");
+ for (i = 0; i < 4; i++)
+- printf("%d%s", ((unsigned char *)&arpinfo->daddr)[i], (i == 3) ? "" : ".");
++ printf("%d%s", ((unsigned char *)&arpinfo->daddr)[i],
++ (i == 3) ? "" : ".");
+ printf("%s, ", mask_to_dotted(arpinfo->dmsk));
+ }
+ }
+
+-static int compare(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2)
++static int compare(const struct ebt_entry_match *m1,
++ const struct ebt_entry_match *m2)
+ {
+ struct ebt_arp_info *arpinfo1 = (struct ebt_arp_info *)m1->data;
+ struct ebt_arp_info *arpinfo2 = (struct ebt_arp_info *)m2->data;
+--- ebtables-v2.0pre2.001/extensions/ebt_log.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/extensions/ebt_log.c Wed Apr 10 23:51:18 2002
+@@ -9,14 +9,14 @@
+
+ // copied from syslog.h
+ // used for the LOG target
+-#define LOG_EMERG 0 /* system is unusable */
+-#define LOG_ALERT 1 /* action must be taken immediately */
+-#define LOG_CRIT 2 /* critical conditions */
+-#define LOG_ERR 3 /* error conditions */
+-#define LOG_WARNING 4 /* warning conditions */
+-#define LOG_NOTICE 5 /* normal but significant condition */
+-#define LOG_INFO 6 /* informational */
+-#define LOG_DEBUG 7 /* debug-level messages */
++#define LOG_EMERG 0 // system is unusable
++#define LOG_ALERT 1 // action must be taken immediately
++#define LOG_CRIT 2 // critical conditions
++#define LOG_ERR 3 // error conditions
++#define LOG_WARNING 4 // warning conditions
++#define LOG_NOTICE 5 // normal but significant condition
++#define LOG_INFO 6 // informational
++#define LOG_DEBUG 7 // debug-level messages
+ #define LOG_DEFAULT_LEVEL LOG_INFO
+
+ typedef struct _code {
+@@ -70,16 +70,17 @@
+ int i;
+
+ printf(
+- "log options:\n"
+- "--log : use this if you're not specifying anything\n"
+- "--log-level level : level = [1-8] or a string\n"
+- "--log-prefix prefix : max. %d chars.\n"
+- "--log-ip : put ip info. in the log for ip packets\n"
+- "--log-arp : put (r)arp info. in the log for (r)arp packets\n"
++"log options:\n"
++"--log : use this if you're not specifying anything\n"
++"--log-level level : level = [1-8] or a string\n"
++"--log-prefix prefix : max. %d chars.\n"
++"--log-ip : put ip info. in the log for ip packets\n"
++"--log-arp : put (r)arp info. in the log for (r)arp packets\n"
+ , EBT_LOG_PREFIX_SIZE - 1);
+ printf("levels:\n");
+ for (i = 0; i < 8; i++)
+- printf("%d = %s\n", eight_priority[i].c_val, eight_priority[i].c_name);
++ printf("%d = %s\n", eight_priority[i].c_val,
++ eight_priority[i].c_name);
+ }
+
+ static void init(struct ebt_entry_watcher *watcher)
+@@ -88,7 +89,7 @@
+
+ loginfo->bitmask = 0;
+ loginfo->prefix[0] = '\0';
+- loginfo->loglevel = 6;
++ loginfo->loglevel = LOG_NOTICE;
+ }
+
+ #define OPT_PREFIX 0x01
+@@ -96,9 +97,8 @@
+ #define OPT_ARP 0x04
+ #define OPT_IP 0x08
+ #define OPT_LOG 0x10
+-static int parse(int c, char **argv, int argc,
+- const struct ebt_u_entry *entry, unsigned int *flags,
+- struct ebt_entry_watcher **watcher)
++static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
++ unsigned int *flags, struct ebt_entry_watcher **watcher)
+ {
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)(*watcher)->data;
+ int i;
+@@ -108,9 +108,10 @@
+ case LOG_PREFIX:
+ check_option(flags, OPT_PREFIX);
+ if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
+- print_error("Prefix too long.");
++ print_error("Prefix too long");
+ strcpy(loginfo->prefix, optarg);
+ break;
++
+ case LOG_LEVEL:
+ check_option(flags, OPT_LEVEL);
+ i = strtol(optarg, &end, 16);
+@@ -119,16 +120,19 @@
+ else
+ loginfo->loglevel = i;
+ if (loginfo->loglevel == 9)
+- print_error("Problem with the log-level.");
++ print_error("Problem with the log-level");
+ break;
++
+ case LOG_IP:
+ check_option(flags, OPT_IP);
+ loginfo->bitmask |= EBT_LOG_IP;
+ break;
++
+ case LOG_ARP:
+ check_option(flags, OPT_ARP);
+ loginfo->bitmask |= EBT_LOG_ARP;
+ break;
++
+ case LOG_LOG:
+ check_option(flags, OPT_LOG);
+ break;
+@@ -138,16 +142,18 @@
+ return 1;
+ }
+
+-static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_watcher *watcher, const char *name, unsigned int hook)
++static void final_check(const struct ebt_u_entry *entry,
++ const struct ebt_entry_watcher *watcher, const char *name, unsigned int hook)
+ {
+ return;
+ }
+
+-static void print(const struct ebt_u_entry *entry, const struct ebt_entry_watcher *watcher)
++static void print(const struct ebt_u_entry *entry,
++ const struct ebt_entry_watcher *watcher)
+ {
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)watcher->data;
+
+- printf("log: log-level = %s - log-prefix = '%s'",
++ printf("log: log-level = %s - log-prefix = \"%s\"",
+ eight_priority[loginfo->loglevel].c_name,
+ loginfo->prefix);
+ if (loginfo->bitmask & EBT_LOG_IP)
+@@ -157,7 +163,8 @@
+ printf(" ");
+ }
+
+-static int compare(const struct ebt_entry_watcher *w1, const struct ebt_entry_watcher *w2)
++static int compare(const struct ebt_entry_watcher *w1,
++ const struct ebt_entry_watcher *w2)
+ {
+ struct ebt_log_info *loginfo1 = (struct ebt_log_info *)w1->data;
+ struct ebt_log_info *loginfo2 = (struct ebt_log_info *)w2->data;
+--- ebtables-v2.0pre2.001/extensions/ebt_standard.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/extensions/ebt_standard.c Thu Apr 11 18:14:07 2002
+@@ -19,17 +19,19 @@
+ ((struct ebt_standard_target *)t)->verdict = EBT_CONTINUE;
+ }
+
+-static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags,
+- struct ebt_entry_target **target)
++static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
++ unsigned int *flags, struct ebt_entry_target **target)
+ {
+ return 0;
+ }
+
+-static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hook)
++static void final_check(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+ {
+ }
+
+-static void print(const struct ebt_u_entry *entry, const struct ebt_entry_target *target)
++static void print(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target)
+ {
+ __u8 verdict = ((struct ebt_standard_target *)target)->verdict;
+
+@@ -41,9 +43,11 @@
+ printf("Drop ");
+ }
+
+-static int compare(const struct ebt_entry_target *t1, const struct ebt_entry_target *t2)
++static int compare(const struct ebt_entry_target *t1,
++ const struct ebt_entry_target *t2)
+ {
+- return ((struct ebt_standard_target *)t1)->verdict == ((struct ebt_standard_target *)t2)->verdict;
++ return ((struct ebt_standard_target *)t1)->verdict ==
++ ((struct ebt_standard_target *)t2)->verdict;
+ }
+
+ static struct ebt_u_target standard =
+--- ebtables-v2.0pre2.001/extensions/ebtable_filter.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/extensions/ebtable_filter.c Thu Apr 11 18:14:40 2002
+@@ -3,7 +3,8 @@
+ #include <linux/netfilter_bridge/ebtables.h>
+ #include "../include/ebtables_u.h"
+
+-#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | (1 << NF_BR_LOCAL_OUT))
++#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
++ (1 << NF_BR_LOCAL_OUT))
+
+ static void print_help(char **hn)
+ {
+--- ebtables-v2.0pre2.001/extensions/ebtable_nat.c Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/extensions/ebtable_nat.c Thu Apr 11 18:14:57 2002
+@@ -2,7 +2,8 @@
+ #include <sys/socket.h>
+ #include "../include/ebtables_u.h"
+
+-#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_POST_ROUTING))
++#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
++ (1 << NF_BR_POST_ROUTING))
+
+ static void print_help(char **hn)
+ {
+--- ebtables-v2.0pre2.001/ChangeLog Wed Apr 3 16:56:37 2002
++++ ebtables-v2.0pre2.002/ChangeLog Thu Apr 11 18:26:21 2002
+@@ -1,3 +1,12 @@
++20020411
++ * -j standard no longer works, is this cryptic? good :)
++ * lots of beautification.
++ - made some code smaller
++ - made everything fit within 80 columns
++ * fix problems with -i and -o option
++ * print_memory now prints useful info
++ * trying to see the tables when ebtables is not loaded in kernel
++ no longer makes this be seen as a bug.
+ 20020403
+ ebtables v2.0 released, changes:
+ * A complete rewrite, made everything modular.
+--- ebtables-v2.0pre2.001/include/ebtables_u.h Thu Apr 11 18:27:45 2002
++++ ebtables-v2.0pre2.002/include/ebtables_u.h Wed Apr 10 22:29:01 2002
+@@ -38,20 +38,28 @@
+ {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+- unsigned int nentries; // nr of rules in the table
++ // nr of rules in the table
++ unsigned int nentries;
+ struct ebt_u_entries *hook_entry[NF_BR_NUMHOOKS];
+- unsigned int counter_entry[NF_BR_NUMHOOKS]; // how many counters in front of it?
+- unsigned int num_counters; // nr of counters the userspace expects back
+- struct ebt_counter *counters; // where the kernel will put the old counters
+- unsigned int flags; // can be used e.g. to know if a standard option has been specified twice
+- char command; // we stick the specified command (e.g. -A) in here
+- int selected_hook; // here we stick the hook to do our thing on (can be -1 if unspecified)
++ // how many counters in front of it?
++ unsigned int counter_entry[NF_BR_NUMHOOKS];
++ // nr of counters userspace expects back
++ unsigned int num_counters;
++ // where the kernel will put the old counters
++ struct ebt_counter *counters;
++ // can be used e.g. to know if a standard option
++ // has been specified twice
++ unsigned int flags;
++ // we stick the specified command (e.g. -A) in here
++ char command;
++ // here we stick the hook to do our thing on (can be -1 if unspecified)
++ int selected_hook;
+ };
+
+ struct ebt_u_table
+ {
+ char name[EBT_TABLE_MAXNAMELEN];
+- int (*check) (struct ebt_u_replace *repl);
++ int (*check)(struct ebt_u_replace *repl);
+ void (*help)(char **);
+ struct ebt_u_table *next;
+ };
+@@ -70,9 +78,9 @@
+
+ struct ebt_u_entry
+ {
+- __u32 bitmask; // this needs to be the first field
++ __u32 bitmask;
+ __u32 invflags;
+- __u16 ethproto; /* packet type ID field */
++ __u16 ethproto;
+ __u8 in[IFNAMSIZ];
+ __u8 out[IFNAMSIZ];
+ __u8 sourcemac[ETH_ALEN];
+@@ -86,35 +94,47 @@
+ struct ebt_u_match
+ {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+- unsigned int size;// size of the real match data
++ // size of the real match data + sizeof struct ebt_match
++ unsigned int size;
+ void (*help)(void);
+ void (*init)(struct ebt_entry_match *m);
+ int (*parse)(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_match **match);
+- void (*final_check)(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hook);
+- void (*print)(const struct ebt_u_entry *entry, const struct ebt_entry_match *match);
+- int (*compare)(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2);
++ void (*final_check)(const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match,
++ const char *name, unsigned int hook);
++ void (*print)(const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match);
++ int (*compare)(const struct ebt_entry_match *m1,
++ const struct ebt_entry_match *m2);
+ const struct option *extra_ops;
+- unsigned int flags;// can be used e.g. to check for multiple occurance of the same option
++ // can be used e.g. to check for multiple occurance of the same option
++ unsigned int flags;
+ unsigned int option_offset;
+ struct ebt_entry_match *m;
+- unsigned int used;// if used == 1 we no longer have to add it to the match chain of the new entry
++ // if used == 1 we no longer have to add it to
++ // the match chain of the new entry
++ unsigned int used;
+ struct ebt_u_match *next;
+ };
+
+ struct ebt_u_watcher
+ {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+- unsigned int size;// size of the real match data
++ unsigned int size;
+ void (*help)(void);
+ void (*init)(struct ebt_entry_watcher *w);
+ int (*parse)(int c, char **argv, int argc,
+- const struct ebt_u_entry *entry, unsigned int *flags,
+- struct ebt_entry_watcher **watcher);
+- void (*final_check)(const struct ebt_u_entry *entry, const struct ebt_entry_watcher *watch, const char *name, unsigned int hook);
+- void (*print)(const struct ebt_u_entry *entry, const struct ebt_entry_watcher *watcher);
+- int (*compare)(const struct ebt_entry_watcher *w1, const struct ebt_entry_watcher *w2);
++ const struct ebt_u_entry *entry, unsigned int *flags,
++ struct ebt_entry_watcher **watcher);
++ void (*final_check)(const struct ebt_u_entry *entry,
++ const struct ebt_entry_watcher *watch, const char *name,
++ unsigned int hook);
++ void (*print)(const struct ebt_u_entry *entry,
++ const struct ebt_entry_watcher *watcher);
++ int (*compare)(const struct ebt_entry_watcher *w1,
++ const struct ebt_entry_watcher *w2);
+ const struct option *extra_ops;
+ unsigned int flags;
+ unsigned int option_offset;
+@@ -126,14 +146,19 @@
+ struct ebt_u_target
+ {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+- unsigned int size;// size of the real match data
++ unsigned int size;
+ void (*help)(void);
+ void (*init)(struct ebt_entry_target *t);
+- int (*parse)(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags,
+- struct ebt_entry_target **target);
+- void (*final_check)(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hook);
+- void (*print)(const struct ebt_u_entry *entry, const struct ebt_entry_target *target);
+- int (*compare)(const struct ebt_entry_target *t1, const struct ebt_entry_target *t2);
++ int (*parse)(int c, char **argv, int argc,
++ const struct ebt_u_entry *entry, unsigned int *flags,
++ struct ebt_entry_target **target);
++ void (*final_check)(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target, const char *name,
++ unsigned int hook);
++ void (*print)(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target);
++ int (*compare)(const struct ebt_entry_target *t1,
++ const struct ebt_entry_target *t2);
+ const struct option *extra_ops;
+ unsigned int option_offset;
+ unsigned int flags;
+@@ -150,19 +175,21 @@
+ struct ebt_u_target *find_target(const char *name);
+ struct ebt_u_match *find_match(const char *name);
+ struct ebt_u_watcher *find_watcher(const char *name);
+-void deliver_counters(struct ebt_u_replace *repl, unsigned short * counterchanges);
++void deliver_counters(struct ebt_u_replace *repl,
++ unsigned short * counterchanges);
+ void deliver_table(struct ebt_u_replace *repl);
+-void get_sockfd();
+ void get_dbinfo(struct brdb_dbinfo *nr);
+ void get_db(int len, struct brdb_dbentry *db);
+ void deliver_allowdb(__u16 *decision);
+-void print_memory();
+-void init_extensions();
+ int getmac(char *from, char *to);
+ void check_option(unsigned int *flags, unsigned int mask);
+ int check_inverse(const char option[]);
+-#define print_bug(format, args...) {printf("BUG: "format"\n", ##args); exit(-1);}
+-#define print_error(format, args...) {printf(format"\n", ##args); exit(-1);}
++#define print_bug(format, args...) \
++ {printf("BUG: "format".\n", ##args); exit(-1);}
++#define print_error(format, args...) {printf(format".\n", ##args); exit(-1);}
++#define print_memory() {printf("Ebtables: " __FILE__ " " __FUNCTION__ \
++ " %d :Out of memory.\n", __LINE__); exit(-1);}
++
+
+
+ // used for keeping the rule counters right during rule adds or deletes
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre2.003.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre2.003.diff
new file mode 100644
index 0000000..aac6a6f
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre2.003.diff
@@ -0,0 +1,40 @@
+--- ebtables-v2.0pre2.002/Makefile Sat Apr 13 17:39:08 2002
++++ ebtables-v2.0pre2.003/Makefile Sat Apr 13 17:43:09 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre2.001 (April 2002)"
++PROGVERSION:="2.0pre2.003 (April 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+--- ebtables-v2.0pre2.002/ebtables.c Sat Apr 13 17:39:08 2002
++++ ebtables-v2.0pre2.003/ebtables.c Sat Apr 13 17:37:00 2002
+@@ -1490,7 +1490,7 @@
+ flush_chains();
+ else if (replace.command == 'A' || replace.command == 'I')
+ add_rule(rule_nr);
+- else
++ else if (replace.command == 'D')
+ delete_rule(rule_nr);
+
+ if (table->check)
+--- ebtables-v2.0pre2.002/THANKS Wed Apr 3 17:44:44 2002
++++ ebtables-v2.0pre2.003/THANKS Sat Apr 13 17:40:35 2002
+@@ -5,3 +5,5 @@
+ Harald Welte
+ Jason Lunz
+ Tim Gardner
++Loïc Minier
++
+--- ebtables-v2.0pre2.002/ebtables.8 Wed Apr 3 16:29:11 2002
++++ ebtables-v2.0pre2.003/ebtables.8 Sat Apr 13 17:32:23 2002
+@@ -128,6 +128,7 @@
+ Put the counters of the selected chain on zero. If no chain is selected, all the counters
+ are put on zero. This can be used in conjunction with the -L command (see above).
+ This will cause the rule counters to be printed on the screen before they are put on zero.
++.TP
+ .B "-P, --policy"
+ Set the policy for the chain to the given target. The policy is either
+ .B ACCEPT
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre2.004.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre2.004.diff
new file mode 100644
index 0000000..87ed4dc
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre2.004.diff
@@ -0,0 +1,50 @@
+--- ebtables-v2.0pre2.003/Makefile Sun Apr 14 15:01:46 2002
++++ ebtables-v2.0pre2.004/Makefile Sun Apr 14 15:03:11 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre2.003 (April 2002)"
++PROGVERSION:="2.0pre2 (April 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+--- ebtables-v2.0pre2.003/ChangeLog Sat Apr 13 17:39:08 2002
++++ ebtables-v2.0pre2.004/ChangeLog Sun Apr 14 14:15:59 2002
+@@ -1,3 +1,6 @@
++20020414
++ * fixed some things in the manual.
++ * fixed -P problem.
+ 20020411
+ * -j standard no longer works, is this cryptic? good :)
+ * lots of beautification.
+--- ebtables-v2.0pre2.003/ebtables.8 Sun Apr 14 15:01:46 2002
++++ ebtables-v2.0pre2.004/ebtables.8 Sun Apr 14 14:58:15 2002
+@@ -1,4 +1,4 @@
+-.TH EBTABLES 8 "03 April 2002"
++.TH EBTABLES 8 "14 April 2002"
+ .\"
+ .\" Man page written by Bart De Schuymer <bart.de.schuymer@pandora.be>
+ .\" It is based on the iptables man page.
+@@ -21,7 +21,7 @@
+ .\"
+ .\"
+ .SH NAME
+-ebtables(v.2) \- ethernet bridge packet table administration
++ebtables(v.2.0) \- ethernet bridge packet table administration
+ .SH SYNOPSIS
+ .BR "ebtables -[ADI] " "chain rule-specification [options]"
+ .br
+@@ -263,6 +263,12 @@
+ .BR "--arp-ptype " "[!] \fIprotocol type\fP"
+ The protocol type for which the (r)arp is used (hexadecimal or the string "IPv4").
+ This is normally IPv4 (0x0800).
++.TP
++.BR "--arp-ip-src " "[!] \fIaddress\fP[/\fImask\fP]"
++The ARP IP source address specification.
++.TP
++.BR "--arp-ip-dst " "[!] \fIaddress\fP[/\fImask\fP]"
++The ARP IP destination address specification.
+ .SH WATCHER EXTENSION(S)
+ Watchers are things that only look at frames passing by. These watchers only see the
+ frame if the frame passes all the matches of the rule.
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre3.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre3.001.diff
new file mode 100644
index 0000000..12c7a2b
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre3.001.diff
@@ -0,0 +1,245 @@
+Adjust to the kernel's wish that the size members represent the size
+of the actual data.
+
+Make a little note in the man page about the chain naming.
+
+--- ebtables-v2.0pre2/ebtables.c Sat Apr 13 17:37:00 2002
++++ ebtables-v2.0pre3.001/ebtables.c Fri Apr 19 19:44:33 2002
+@@ -253,14 +253,14 @@
+
+ void register_match(struct ebt_u_match *m)
+ {
+- int size = m->size;
++ int size = m->size + sizeof(struct ebt_entry_match);
+ struct ebt_u_match **i;
+
+ m->m = (struct ebt_entry_match *)malloc(size);
+ if (!m->m)
+ print_memory();
+ strcpy(m->m->u.name, m->name);
+- m->m->match_size = size;
++ m->m->match_size = m->size;
+ ebt_options = merge_options
+ (ebt_options, m->extra_ops, &(m->option_offset));
+ m->init(m->m);
+@@ -272,14 +272,14 @@
+
+ void register_watcher(struct ebt_u_watcher *w)
+ {
+- int size = w->size;
++ int size = w->size + sizeof(struct ebt_entry_watcher);
+ struct ebt_u_watcher **i;
+
+ w->w = (struct ebt_entry_watcher *)malloc(size);
+ if (!w->w)
+ print_memory();
+ strcpy(w->w->u.name, w->name);
+- w->w->watcher_size = size;
++ w->w->watcher_size = w->size;
+ ebt_options = merge_options
+ (ebt_options, w->extra_ops, &(w->option_offset));
+ w->init(w->w);
+@@ -291,14 +291,14 @@
+
+ void register_target(struct ebt_u_target *t)
+ {
+- int size = t->size;
++ int size = t->size + sizeof(struct ebt_entry_target);
+ struct ebt_u_target **i;
+
+ t->t = (struct ebt_entry_target *)malloc(size);
+ if (!t->t)
+ print_memory();
+ strcpy(t->t->u.name, t->name);
+- t->t->target_size = size;
++ t->t->target_size = t->size;
+ ebt_options = merge_options
+ (ebt_options, t->extra_ops, &(t->option_offset));
+ t->init(t->t);
+--- ebtables-v2.0pre2/communication.c Wed Apr 10 22:10:49 2002
++++ ebtables-v2.0pre3.001/communication.c Fri Apr 19 22:02:45 2002
+@@ -68,15 +68,18 @@
+ entries_size += sizeof(struct ebt_entry);
+ m_l = e->m_list;
+ while (m_l) {
+- entries_size += m_l->m->match_size;
++ entries_size += m_l->m->match_size +
++ sizeof(struct ebt_entry_match);
+ m_l = m_l->next;
+ }
+ w_l = e->w_list;
+ while (w_l) {
+- entries_size += w_l->w->watcher_size;
++ entries_size += w_l->w->watcher_size +
++ sizeof(struct ebt_entry_watcher);
+ w_l = w_l->next;
+ }
+- entries_size += e->t->target_size;
++ entries_size += e->t->target_size +
++ sizeof(struct ebt_entry_target);
+ e = e->next;
+ }
+ // a little sanity check
+@@ -120,20 +123,26 @@
+ p += sizeof(struct ebt_entry);
+ m_l = e->m_list;
+ while (m_l) {
+- memcpy(p, m_l->m, m_l->m->match_size);
+- p += m_l->m->match_size;
++ memcpy(p, m_l->m, m_l->m->match_size +
++ sizeof(struct ebt_entry_match));
++ p += m_l->m->match_size +
++ sizeof(struct ebt_entry_match);
+ m_l = m_l->next;
+ }
+ tmp->watchers_offset = p - base;
+ w_l = e->w_list;
+ while (w_l) {
+- memcpy(p, w_l->w, w_l->w->watcher_size);
+- p += w_l->w->watcher_size;
++ memcpy(p, w_l->w, w_l->w->watcher_size +
++ sizeof(struct ebt_entry_watcher));
++ p += w_l->w->watcher_size +
++ sizeof(struct ebt_entry_watcher);
+ w_l = w_l->next;
+ }
+ tmp->target_offset = p - base;
+- memcpy(p, e->t, e->t->target_size);
+- p += e->t->target_size;
++ memcpy(p, e->t, e->t->target_size +
++ sizeof(struct ebt_entry_target));
++ p += e->t->target_size +
++ sizeof(struct ebt_entry_target);
+ tmp->next_offset = p - base;
+ e = e->next;
+ }
+@@ -229,10 +238,11 @@
+ malloc(sizeof(struct ebt_u_match_list));
+ if (!new)
+ print_memory();
+- new->m = (struct ebt_entry_match *)malloc(m->match_size);
++ new->m = (struct ebt_entry_match *)
++ malloc(m->match_size + sizeof(struct ebt_entry_match));
+ if (!new->m)
+ print_memory();
+- memcpy(new->m, m, m->match_size);
++ memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
+ new->next = NULL;
+ **l = new;
+ *l = &new->next;
+@@ -248,13 +258,15 @@
+ {
+ struct ebt_u_watcher_list *new;
+
+- new = (struct ebt_u_watcher_list *)malloc(sizeof(struct ebt_u_watcher_list));
++ new = (struct ebt_u_watcher_list *)
++ malloc(sizeof(struct ebt_u_watcher_list));
+ if (!new)
+ print_memory();
+- new->w = (struct ebt_entry_watcher *)malloc(w->watcher_size);
++ new->w = (struct ebt_entry_watcher *)
++ malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
+ if (!new->w)
+ print_memory();
+- memcpy(new->w, w, w->watcher_size);
++ memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
+ new->next = NULL;
+ **l = new;
+ *l = &new->next;
+@@ -297,13 +309,15 @@
+ EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
+
+ t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
+- new->t = (struct ebt_entry_target *)malloc(t->target_size);
++ new->t = (struct ebt_entry_target *)
++ malloc(t->target_size + sizeof(struct ebt_entry_target));
+ if (!new->t)
+ print_memory();
+ if (find_target(t->u.name) == NULL)
+ print_error("Kernel target %s unsupported by "
+ "userspace tool", t->u.name);
+- memcpy(new->t, t, t->target_size);
++ memcpy(new->t, t, t->target_size +
++ sizeof(struct ebt_entry_target));
+
+ // I love pointers
+ **u_e = new;
+@@ -419,7 +433,8 @@
+
+ get_sockfd();
+
+- if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB, decision, optlen))
++ if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB,
++ decision, optlen))
+ print_error("Sorry, br_db code probably not in kernel, "
+ "try insmod br_db");
+ }
+--- ebtables-v2.0pre2/extensions/ebt_nat.c Thu Apr 11 18:12:55 2002
++++ ebtables-v2.0pre3.001/extensions/ebt_nat.c Fri Apr 19 19:41:04 2002
+@@ -161,7 +161,7 @@
+ static struct ebt_u_target dnat_target =
+ {
+ EBT_DNAT_TARGET,
+- sizeof(struct ebt_nat_info) + sizeof(struct ebt_entry_target),
++ sizeof(struct ebt_nat_info),
+ print_help_d,
+ init_d,
+ parse_d,
+--- ebtables-v2.0pre2/extensions/ebt_ip.c Wed Apr 10 23:28:40 2002
++++ ebtables-v2.0pre3.001/extensions/ebt_ip.c Fri Apr 19 19:40:18 2002
+@@ -301,7 +301,7 @@
+ static struct ebt_u_match ip_match =
+ {
+ EBT_IP_MATCH,
+- sizeof(struct ebt_ip_info) + sizeof(struct ebt_entry_match),
++ sizeof(struct ebt_ip_info),
+ print_help,
+ init,
+ parse,
+--- ebtables-v2.0pre2/extensions/ebt_arp.c Wed Apr 10 23:05:29 2002
++++ ebtables-v2.0pre3.001/extensions/ebt_arp.c Fri Apr 19 19:40:40 2002
+@@ -272,7 +272,7 @@
+ static struct ebt_u_match arp_match =
+ {
+ EBT_ARP_MATCH,
+- sizeof(struct ebt_arp_info) + sizeof(struct ebt_entry_match),
++ sizeof(struct ebt_arp_info),
+ print_help,
+ init,
+ parse,
+--- ebtables-v2.0pre2/extensions/ebt_log.c Wed Apr 10 23:51:18 2002
++++ ebtables-v2.0pre3.001/extensions/ebt_log.c Fri Apr 19 19:40:52 2002
+@@ -179,7 +179,7 @@
+ static struct ebt_u_watcher log_watcher =
+ {
+ EBT_LOG_WATCHER,
+- sizeof(struct ebt_log_info) + sizeof(struct ebt_entry_watcher),
++ sizeof(struct ebt_log_info),
+ print_help,
+ init,
+ parse,
+--- ebtables-v2.0pre2/extensions/ebt_standard.c Thu Apr 11 18:14:07 2002
++++ ebtables-v2.0pre3.001/extensions/ebt_standard.c Fri Apr 19 19:44:54 2002
+@@ -53,7 +53,7 @@
+ static struct ebt_u_target standard =
+ {
+ EBT_STANDARD_TARGET,
+- sizeof(struct ebt_standard_target),
++ sizeof(struct ebt_standard_target) - sizeof(struct ebt_entry_target),
+ print_help,
+ init,
+ parse,
+--- ebtables-v2.0pre2/ebtables.8 Sun Apr 14 14:58:15 2002
++++ ebtables-v2.0pre3.001/ebtables.8 Thu Apr 18 18:44:40 2002
+@@ -86,7 +86,10 @@
+ .B OUTPUT
+ (for altering locally generated frames before they are bridged) and
+ .B POSTROUTING
+-(for altering frames as they are about to go out).
++(for altering frames as they are about to go out). A small note on the naming
++of chains POSTROUTING and PREROUTING: it would be more accurate to call them
++PREFORWARDING and POSTFORWARDING, but for all those who come from the iptables
++world to ebtables it is easier to have the same names.
+ .SH OPTIONS
+ The options can be divided into several different groups.
+ .SS COMMANDS
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre3.002.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre3.002.diff
new file mode 100644
index 0000000..175f9df
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre3.002.diff
@@ -0,0 +1,194 @@
+--- ebtables-v2.0pre3.001/ebtables.c Fri Apr 19 22:07:46 2002
++++ ebtables-v2.0pre3.002/ebtables.c Fri Apr 19 23:43:05 2002
+@@ -62,6 +62,8 @@
+ { "policy" , required_argument, 0, 'P' },
+ { "in-interface" , required_argument, 0, 'i' },
+ { "in-if" , required_argument, 0, 'i' },
++ { "logical-in" , required_argument, 0, 1 },
++ { "logical-out" , required_argument, 0, 2 },
+ { "out-interface" , required_argument, 0, 'o' },
+ { "out-if" , required_argument, 0, 'o' },
+ { "version" , no_argument , 0, 'V' },
+@@ -481,6 +483,16 @@
+ printf("! ");
+ printf("in-if: %s, ", hlp->in);
+ }
++ if (hlp->logical_in[0] != '\0') {
++ if (hlp->invflags & EBT_ILOGICALIN)
++ printf("! ");
++ printf("logical in-if: %s, ", hlp->logical_in);
++ }
++ if (hlp->logical_out[0] != '\0') {
++ if (hlp->invflags & EBT_ILOGICALOUT)
++ printf("! ");
++ printf("logical out-if: %s, ", hlp->logical_out);
++ }
+ if (hlp->out[0] != '\0') {
+ if (hlp->invflags & EBT_IOUT)
+ printf("! ");
+@@ -560,6 +572,8 @@
+ "--dst -d [!] address : destination mac address\n"
+ "--in-if -i [!] name : network input interface name\n"
+ "--out-if -o [!] name : network output interface name\n"
++"--logical-in [!] name : logical bridge input interface name\n"
++"--logical-out [!] name : logical bridge output interface name\n"
+ "--version -V : print package version\n"
+ "\n" ,
+ prog_name,
+@@ -1095,15 +1109,17 @@
+ *flags |= mask;
+ }
+
+-#define OPT_COMMAND 0x01
+-#define OPT_TABLE 0x02
+-#define OPT_IN 0x04
+-#define OPT_OUT 0x08
+-#define OPT_JUMP 0x10
+-#define OPT_PROTOCOL 0x20
+-#define OPT_SOURCE 0x40
+-#define OPT_DEST 0x80
+-#define OPT_ZERO 0x100
++#define OPT_COMMAND 0x01
++#define OPT_TABLE 0x02
++#define OPT_IN 0x04
++#define OPT_OUT 0x08
++#define OPT_JUMP 0x10
++#define OPT_PROTOCOL 0x20
++#define OPT_SOURCE 0x40
++#define OPT_DEST 0x80
++#define OPT_ZERO 0x100
++#define OPT_LOGICALIN 0x200
++#define OPT_LOGICALOUT 0x400
+ // the main thing
+ int main(int argc, char *argv[])
+ {
+@@ -1261,7 +1277,9 @@
+ break;
+
+ case 'i': // input interface
++ case 1 : // logical input interface
+ case 'o': // output interface
++ case 2 : // logical output interface
+ case 'j': // target
+ case 'p': // net family protocol
+ case 's': // source mac
+@@ -1287,6 +1305,23 @@
+ strcpy(new_entry->in, argv[optind - 1]);
+ break;
+ }
++ if (c == 1) {
++ check_option(&replace.flags, OPT_LOGICALIN);
++ if (replace.selected_hook > 2)
++ print_error("Use logical in-interface "
++ "only in INPUT, FORWARD and "
++ "PREROUTING chains");
++ if (check_inverse(optarg))
++ new_entry->invflags |= EBT_ILOGICALIN;
++
++ if (optind > argc)
++ print_error("No logical in-interface "
++ "specified");
++ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
++ print_error("Illegal interfacelength");
++ strcpy(new_entry->logical_in, argv[optind - 1]);
++ break;
++ }
+ if (c == 'o') {
+ check_option(&replace.flags, OPT_OUT);
+ if (replace.selected_hook < 2)
+@@ -1304,6 +1339,26 @@
+ print_error("Illegal interface "
+ "length");
+ strcpy(new_entry->out, argv[optind - 1]);
++ break;
++ }
++ if (c == 2) {
++ check_option(&replace.flags, OPT_LOGICALOUT);
++ if (replace.selected_hook < 2)
++ print_error("Use logical out-interface "
++ "only in OUTPUT, FORWARD and "
++ "POSTROUTING chains");
++ if (check_inverse(optarg))
++ new_entry->invflags |= EBT_ILOGICALOUT;
++
++ if (optind > argc)
++ print_error("No logical out-interface "
++ "specified");
++
++ if (strlen(argv[optind - 1]) >= IFNAMSIZ)
++ print_error("Illegal interface "
++ "length");
++ strcpy(new_entry->logical_out,
++ argv[optind - 1]);
+ break;
+ }
+ if (c == 'j') {
+--- ebtables-v2.0pre3.001/communication.c Fri Apr 19 22:07:46 2002
++++ ebtables-v2.0pre3.002/communication.c Fri Apr 19 22:57:13 2002
+@@ -115,6 +115,10 @@
+ tmp->ethproto = e->ethproto;
+ memcpy(tmp->in, e->in, sizeof(tmp->in));
+ memcpy(tmp->out, e->out, sizeof(tmp->out));
++ memcpy(tmp->logical_in, e->logical_in,
++ sizeof(tmp->logical_in));
++ memcpy(tmp->logical_out, e->logical_out,
++ sizeof(tmp->logical_out));
+ memcpy(tmp->sourcemac, e->sourcemac,
+ sizeof(tmp->sourcemac));
+ memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
+@@ -298,6 +302,10 @@
+ new->ethproto = e->ethproto;
+ memcpy(new->in, e->in, sizeof(new->in));
+ memcpy(new->out, e->out, sizeof(new->out));
++ memcpy(new->logical_in, e->logical_in,
++ sizeof(new->logical_in));
++ memcpy(new->logical_out, e->logical_out,
++ sizeof(new->logical_out));
+ memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
+ memcpy(new->destmac, e->destmac, sizeof(new->destmac));
+ new->m_list = NULL;
+--- ebtables-v2.0pre3.001/ebtables.8 Fri Apr 19 22:07:46 2002
++++ ebtables-v2.0pre3.002/ebtables.8 Fri Apr 19 23:28:06 2002
+@@ -184,6 +184,14 @@
+ .B --in-if
+ is an alias for this option.
+ .TP
++.BR "--logical-in " "[!] \fIname\fP"
++The (logical) bridge interface via which a frame is received (for the
++.BR INPUT ,
++.B FORWARD
++and
++.B PREROUTING
++chains).
++.TP
+ .BR "-o, --out-interface " "[!] \fIname\fP"
+ The interface via which a frame is going to be sent (for the
+ .BR OUTPUT ,
+@@ -193,6 +201,15 @@
+ chains). The flag
+ .B --out-if
+ is an alias for this option.
++.TP
++.BR "--logical-out " "[!] \fIname\fP"
++The (logical) bridge interface via which a frame is going to be sent (for
++the
++.BR OUTPUT ,
++.B FORWARD
++and
++.B POSTROUTING
++chains).
+ .TP
+ .BR "-s, --source " "[!] \fIaddress\fP"
+ The source mac address. The flag
+--- ebtables-v2.0pre3.001/include/ebtables_u.h Wed Apr 10 22:29:01 2002
++++ ebtables-v2.0pre3.002/include/ebtables_u.h Fri Apr 19 22:55:15 2002
+@@ -82,7 +82,9 @@
+ __u32 invflags;
+ __u16 ethproto;
+ __u8 in[IFNAMSIZ];
++ __u8 logical_in[IFNAMSIZ];
+ __u8 out[IFNAMSIZ];
++ __u8 logical_out[IFNAMSIZ];
+ __u8 sourcemac[ETH_ALEN];
+ __u8 destmac[ETH_ALEN];
+ struct ebt_u_match_list *m_list;
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre3.003.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre3.003.diff
new file mode 100644
index 0000000..1a80a01
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre3.003.diff
@@ -0,0 +1,66 @@
+* Add brouter support
+* Give better advice when a table is not found by the kernel
+
+--- ebtables-v2.0pre3.002/Makefile Sun Apr 14 15:03:11 2002
++++ ebtables-v2.0pre3.003/Makefile Mon Apr 22 20:05:21 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre2 (April 2002)"
++PROGVERSION:="2.0pre3 (April 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+--- ebtables-v2.0pre3.002/ebtables.c Mon Apr 22 20:08:03 2002
++++ ebtables-v2.0pre3.003/ebtables.c Sat Apr 20 20:07:42 2002
+@@ -48,7 +48,8 @@
+ [NF_BR_LOCAL_IN]"INPUT",
+ [NF_BR_FORWARD]"FORWARD",
+ [NF_BR_LOCAL_OUT]"OUTPUT",
+- [NF_BR_POST_ROUTING]"POSTROUTING"
++ [NF_BR_POST_ROUTING]"POSTROUTING",
++ [NF_BR_BROUTING]"BROUTING"
+ };
+
+ // default command line options
+--- ebtables-v2.0pre3.002/communication.c Mon Apr 22 20:08:03 2002
++++ ebtables-v2.0pre3.003/communication.c Sun Apr 21 15:38:38 2002
+@@ -375,7 +375,8 @@
+ strcpy(repl.name, u_repl->name);
+ if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_INFO, &repl, &optlen))
+ print_error("A kernel module needed by your command is probably"
+- " not loaded. Try insmod ebtables or the like");
++ " not loaded. Try insmod ebtables or"
++ " insmod ebtable_%s", repl.name);
+
+ if ( !(repl.entries = (char *) malloc(repl.entries_size)) )
+ print_memory();
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebtables-v2.0pre3.003/extensions/ebtable_broute.c Sat Apr 20 20:12:26 2002
+@@ -0,0 +1,25 @@
++#include <stdio.h>
++#include <sys/socket.h>
++#include "../include/ebtables_u.h"
++
++
++static void print_help(char **hn)
++{
++ printf("Supported chain for the nat table:\n");
++ printf("%s\n",hn[NF_BR_BROUTING]);
++}
++
++static struct
++ebt_u_table table =
++{
++ "broute",
++ NULL,
++ print_help,
++ NULL
++};
++
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
++{
++ register_table(&table);
++}
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre3.004.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre3.004.diff
new file mode 100644
index 0000000..9a3bc67
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre3.004.diff
@@ -0,0 +1,483 @@
+--- ebtables-v2.0pre3.003/ebtables.c Sat Apr 27 16:57:47 2002
++++ ebtables-v2.0pre3.004/ebtables.c Wed Apr 24 19:47:02 2002
+@@ -63,8 +63,8 @@
+ { "policy" , required_argument, 0, 'P' },
+ { "in-interface" , required_argument, 0, 'i' },
+ { "in-if" , required_argument, 0, 'i' },
+- { "logical-in" , required_argument, 0, 1 },
+- { "logical-out" , required_argument, 0, 2 },
++ { "logical-in" , required_argument, 0, 2 },
++ { "logical-out" , required_argument, 0, 3 },
+ { "out-interface" , required_argument, 0, 'o' },
+ { "out-if" , required_argument, 0, 'o' },
+ { "version" , no_argument , 0, 'V' },
+@@ -155,6 +155,8 @@
+ e->ethproto = 0;
+ strcpy(e->in, "");
+ strcpy(e->out, "");
++ strcpy(e->logical_in, "");
++ strcpy(e->logical_out, "");
+ e->m_list = NULL;
+ e->w_list = NULL;
+ // the init function of the standard target should have put the verdict
+@@ -1278,9 +1280,9 @@
+ break;
+
+ case 'i': // input interface
+- case 1 : // logical input interface
++ case 2 : // logical input interface
+ case 'o': // output interface
+- case 2 : // logical output interface
++ case 3 : // logical output interface
+ case 'j': // target
+ case 'p': // net family protocol
+ case 's': // source mac
+@@ -1306,7 +1308,7 @@
+ strcpy(new_entry->in, argv[optind - 1]);
+ break;
+ }
+- if (c == 1) {
++ if (c == 2) {
+ check_option(&replace.flags, OPT_LOGICALIN);
+ if (replace.selected_hook > 2)
+ print_error("Use logical in-interface "
+@@ -1342,7 +1344,7 @@
+ strcpy(new_entry->out, argv[optind - 1]);
+ break;
+ }
+- if (c == 2) {
++ if (c == 3) {
+ check_option(&replace.flags, OPT_LOGICALOUT);
+ if (replace.selected_hook < 2)
+ print_error("Use logical out-interface "
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebtables-v2.0pre3.004/extensions/ebt_redirect.c Sat Apr 27 17:18:16 2002
+@@ -0,0 +1,109 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <linux/netfilter_bridge/ebtables.h>
++#include <getopt.h>
++#include "../include/ebtables_u.h"
++#include <linux/netfilter_bridge/ebt_redirect.h>
++
++extern char *standard_targets[NUM_STANDARD_TARGETS];
++
++#define REDIRECT_TARGET '1'
++static struct option opts[] =
++{
++ { "redirect-target" , required_argument, 0, REDIRECT_TARGET },
++ { 0 }
++};
++
++static void print_help()
++{
++ printf(
++ "redirect option:\n"
++ " --redirect-target target : ACCEPT, DROP or CONTINUE\n");
++}
++
++static void init(struct ebt_entry_target *target)
++{
++ struct ebt_redirect_info *redirectinfo =
++ (struct ebt_redirect_info *)target->data;
++
++ redirectinfo->target = EBT_ACCEPT;
++ return;
++}
++
++
++#define OPT_REDIRECT_TARGET 0x01
++static int parse(int c, char **argv, int argc,
++ const struct ebt_u_entry *entry, unsigned int *flags,
++ struct ebt_entry_target **target)
++{
++ int i;
++ struct ebt_redirect_info *redirectinfo =
++ (struct ebt_redirect_info *)(*target)->data;
++
++ switch (c) {
++ case REDIRECT_TARGET:
++ check_option(flags, OPT_REDIRECT_TARGET);
++ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
++ if (!strcmp(optarg, standard_targets[i])) {
++ redirectinfo->target = i;
++ break;
++ }
++ if (i == NUM_STANDARD_TARGETS)
++ print_error("Illegal --redirect-target target");
++ break;
++ default:
++ return 0;
++ }
++ return 1;
++}
++
++static void final_check(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target, const char *name, unsigned int hook)
++{
++ if ( (hook != NF_BR_PRE_ROUTING || strcmp(name, "nat")) &&
++ (hook != NF_BR_BROUTING || strcmp(name, "broute")) )
++ print_error("Wrong chain for redirect");
++}
++
++static void print(const struct ebt_u_entry *entry,
++ const struct ebt_entry_target *target)
++{
++ struct ebt_redirect_info *redirectinfo =
++ (struct ebt_redirect_info *)target->data;
++
++ printf("redirect");
++ printf(" --redirect-target %s", standard_targets[redirectinfo->target]);
++}
++
++static int compare(const struct ebt_entry_target *t1,
++ const struct ebt_entry_target *t2)
++{
++ struct ebt_redirect_info *redirectinfo1 =
++ (struct ebt_redirect_info *)t1->data;
++ struct ebt_redirect_info *redirectinfo2 =
++ (struct ebt_redirect_info *)t2->data;
++
++ return redirectinfo1->target == redirectinfo2->target;
++}
++
++static struct ebt_u_target redirect_target =
++{
++ EBT_REDIRECT_TARGET,
++ sizeof(struct ebt_redirect_info),
++ print_help,
++ init,
++ parse,
++ final_check,
++ print,
++ compare,
++ opts,
++};
++
++static void _init(void) __attribute__ ((constructor));
++static void _init(void)
++{
++ register_target(&redirect_target);
++}
+--- ebtables-v2.0pre3.003/extensions/ebt_nat.c Sat Apr 27 16:57:41 2002
++++ ebtables-v2.0pre3.004/extensions/ebt_nat.c Sat Apr 27 17:16:19 2002
+@@ -8,54 +8,71 @@
+ #include "../include/ebtables_u.h"
+ #include <linux/netfilter_bridge/ebt_nat.h>
+
++extern char *standard_targets[NUM_STANDARD_TARGETS];
++
+ int to_source_supplied, to_dest_supplied;
+
+ #define NAT_S '1'
+ #define NAT_D '1'
++#define NAT_S_TARGET '2'
++#define NAT_D_TARGET '2'
+ static struct option opts_s[] =
+ {
+ { "to-source" , required_argument, 0, NAT_S },
+ { "to-src" , required_argument, 0, NAT_S },
+- { 0 },
++ { "snat-target" , required_argument, 0, NAT_S_TARGET },
++ { 0 }
+ };
+
+ static struct option opts_d[] =
+ {
+ { "to-destination", required_argument, 0, NAT_D },
+ { "to-dst" , required_argument, 0, NAT_D },
++ { "dnat-target" , required_argument, 0, NAT_D_TARGET },
+ { 0 }
+ };
+
+ static void print_help_s()
+ {
+ printf(
+- "snat option:\n"
+- " --to-src address : MAC address to map source to\n");
++ "snat options:\n"
++ " --to-src address : MAC address to map source to\n"
++ " --snat-target target : ACCEPT, DROP or CONTINUE\n");
+ }
+
+ static void print_help_d()
+ {
+ printf(
+- "dnat option:\n"
+- " --to-dst address : MAC address to map destination to\n");
++ "dnat options:\n"
++ " --to-dst address : MAC address to map destination to\n"
++ " --dnat-target target : ACCEPT, DROP or CONTINUE\n");
+ }
+
+ static void init_s(struct ebt_entry_target *target)
+ {
++ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
++
+ to_source_supplied = 0;
++ natinfo->target = EBT_ACCEPT;
+ return;
+ }
+
+ static void init_d(struct ebt_entry_target *target)
+ {
++ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data;
++
+ to_dest_supplied = 0;
++ natinfo->target = EBT_ACCEPT;
++ return;
+ }
+
+-#define OPT_SNAT 0x01
++#define OPT_SNAT 0x01
++#define OPT_SNAT_TARGET 0x02
+ static int parse_s(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_target **target)
+ {
++ int i;
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
+
+ switch (c) {
+@@ -65,17 +82,29 @@
+ if (getmac(optarg, natinfo->mac))
+ print_error("Problem with specified to-source mac");
+ break;
++ case NAT_S_TARGET:
++ check_option(flags, OPT_SNAT_TARGET);
++ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
++ if (!strcmp(optarg, standard_targets[i])) {
++ natinfo->target = i;
++ break;
++ }
++ if (i == NUM_STANDARD_TARGETS)
++ print_error("Illegal --snat-target target");
++ break;
+ default:
+- return 0;
++ return 0;
+ }
+ return 1;
+ }
+
+-#define OPT_DNAT 0x01
++#define OPT_DNAT 0x01
++#define OPT_DNAT_TARGET 0x02
+ static int parse_d(int c, char **argv, int argc,
+ const struct ebt_u_entry *entry, unsigned int *flags,
+ struct ebt_entry_target **target)
+ {
++ int i;
+ struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
+
+ switch (c) {
+@@ -86,8 +115,18 @@
+ print_error("Problem with specified "
+ "to-destination mac");
+ break;
++ case NAT_D_TARGET:
++ check_option(flags, OPT_DNAT_TARGET);
++ for (i = 0; i < NUM_STANDARD_TARGETS; i++)
++ if (!strcmp(optarg, standard_targets[i])) {
++ natinfo->target = i;
++ break;
++ }
++ if (i == NUM_STANDARD_TARGETS)
++ print_error("Illegal --dnat-target target");
++ break;
+ default:
+- return 0;
++ return 0;
+ }
+ return 1;
+ }
+@@ -96,18 +135,18 @@
+ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+ {
+ if (hook != NF_BR_POST_ROUTING || strcmp(name, "nat"))
+- print_error("Wrong chain for SNAT");
++ print_error("Wrong chain for snat");
+ if (to_source_supplied == 0)
+ print_error("No snat address supplied");
+-
+ }
+
+ static void final_check_d(const struct ebt_u_entry *entry,
+ const struct ebt_entry_target *target, const char *name, unsigned int hook)
+ {
+- if ( (hook != NF_BR_PRE_ROUTING && hook != NF_BR_LOCAL_OUT) ||
+- strcmp(name, "nat") )
+- print_error("Wrong chain for DNAT");
++ if ( ((hook != NF_BR_PRE_ROUTING && hook != NF_BR_LOCAL_OUT) ||
++ strcmp(name, "nat")) &&
++ (hook != NF_BR_BROUTING || strcmp(name, "broute")) )
++ print_error("Wrong chain for dnat");
+ if (to_dest_supplied == 0)
+ print_error("No dnat address supplied");
+ }
+@@ -122,6 +161,7 @@
+ for (i = 0; i < ETH_ALEN; i++)
+ printf("%02x%s",
+ natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
++ printf(" --snat-target %s", standard_targets[natinfo->target]);
+ }
+
+ static void print_d(const struct ebt_u_entry *entry,
+@@ -134,6 +174,7 @@
+ for (i = 0; i < ETH_ALEN; i++)
+ printf("%02x%s",
+ natinfo->mac[i], (i == ETH_ALEN - 1) ? "" : ":");
++ printf(" --dnat-target %s", standard_targets[natinfo->target]);
+ }
+
+ static int compare(const struct ebt_entry_target *t1,
+@@ -142,13 +183,15 @@
+ struct ebt_nat_info *natinfo1 = (struct ebt_nat_info *)t1->data;
+ struct ebt_nat_info *natinfo2 = (struct ebt_nat_info *)t2->data;
+
+- return !memcmp(natinfo1->mac, natinfo2->mac, sizeof(natinfo1->mac));
++
++ return !memcmp(natinfo1->mac, natinfo2->mac, sizeof(natinfo1->mac)) &&
++ natinfo1->target == natinfo2->target;
+ }
+
+ static struct ebt_u_target snat_target =
+ {
+ EBT_SNAT_TARGET,
+- sizeof(struct ebt_nat_info) + sizeof(struct ebt_entry_target),
++ sizeof(struct ebt_nat_info),
+ print_help_s,
+ init_s,
+ parse_s,
+--- ebtables-v2.0pre3.003/extensions/Makefile Sat Apr 6 21:56:53 2002
++++ ebtables-v2.0pre3.004/extensions/Makefile Tue Apr 23 22:46:21 2002
+@@ -1,7 +1,7 @@
+ #! /usr/bin/make
+
+-EXT_FUNC+=nat arp ip standard log
+-EXT_TABLES+=filter nat
++EXT_FUNC+=nat arp ip standard log redirect
++EXT_TABLES+=filter nat broute
+ EXT_OBJS+=$(foreach T,$(EXT_FUNC), extensions/ebt_$(T).o)
+ EXT_OBJS+=$(foreach T,$(EXT_TABLES), extensions/ebtable_$(T).o)
+
+--- ebtables-v2.0pre3.003/ChangeLog Sun Apr 14 14:15:59 2002
++++ ebtables-v2.0pre3.004/ChangeLog Sat Apr 27 17:24:26 2002
+@@ -1,3 +1,9 @@
++20020427
++ * added broute table.
++ * added redirect target.
++ * added --redirect-target, --snat-target and --dnat-target options.
++ * added logical_out and logical_in
++ * snat bugfix (->size)
+ 20020414
+ * fixed some things in the manual.
+ * fixed -P problem.
+--- ebtables-v2.0pre3.003/ebtables.8 Sat Apr 27 16:57:44 2002
++++ ebtables-v2.0pre3.004/ebtables.8 Sat Apr 27 13:33:37 2002
+@@ -1,4 +1,4 @@
+-.TH EBTABLES 8 "14 April 2002"
++.TH EBTABLES 8 "27 April 2002"
+ .\"
+ .\" Man page written by Bart De Schuymer <bart.de.schuymer@pandora.be>
+ .\" It is based on the iptables man page.
+@@ -40,7 +40,7 @@
+ complicated. This man page is written with the man page of iptables
+ next to it, so don't be surprised to see copied sentences and structure.
+
+-There are two tables with each three built-in chains. Each chain is a list
++There are three tables with built-in chains. Each chain is a list
+ of rules which can match frames: each rule specifies what to do with a
+ frame which matches. This is called a 'target'. The tables are used to
+ divide functionality into different sets of chains.
+@@ -66,7 +66,7 @@
+ .B "TARGET EXTENSIONS"
+ section.
+ .SS TABLES
+-There are two tables.
++There are three tables.
+ .TP
+ .B "-t, --table"
+ This option specifies the frame matching table which the command should
+@@ -90,6 +90,22 @@
+ of chains POSTROUTING and PREROUTING: it would be more accurate to call them
+ PREFORWARDING and POSTFORWARDING, but for all those who come from the iptables
+ world to ebtables it is easier to have the same names.
++.BR broute ,
++this table is used to make a brouter, it has one chain:
++.BR BROUTING .
++The targets
++.BR DROP and ACCEPT
++have special meaning in this table.
++.B DROP
++actually means the frame has to be routed, while
++.B ACCEPT
++means the frame has to be bridged. The
++.B BROUTING
++chain is traversed very early. It is only traversed by frames entering on
++a bridge enslaved nic that is in forwarding state. Normally those frames
++would be bridged, but you can decide otherwise here. The
++.B redirect
++target is very handy here.
+ .SH OPTIONS
+ The options can be divided into several different groups.
+ .SS COMMANDS
+@@ -334,13 +350,21 @@
+ The flag
+ .B --to-src
+ is an alias for this option.
++.br
++.BR "--snat-target " "\fItarget\fP"
++.br
++Specifies the standard target. After doing the snat, the rule still has
++to give a standard target so ebtables knows what to do.
++The default target is ACCEPT. Making it CONTINUE could let you use
++multiple target extensions on the same frame. Making it DROP doesn't
++make sense, but you could do that too.
+ .TP
+ .B dnat
+ The
+ .B dnat
+ target can only be used in the
+-.BR PREROUTING " and the
+-.BR OUTPUT " chains of the " nat " table."
++.BR BROUTING " chain of the " broute " table and the "
++.BR PREROUTING " and " OUTPUT " chains of the " nat " table."
+ It specifies that the destination mac address has to be changed.
+ .br
+ .BR "--to-destination " "\fIaddress\fP"
+@@ -348,6 +372,31 @@
+ The flag
+ .B --to-dst
+ is an alias for this option.
++.br
++.BR "--dnat-target " "\fItarget\fP"
++.br
++Specifies the standard target. After doing the dnat, the rule still has to
++give a standard target so ebtables knows what to do.
++The default target is ACCEPT. Making it CONTINUE could let you use
++multiple target extensions on the same frame. Making it DROP only makes
++sense in the BROUTING chain but using the redirect target is more logical
++there.
++.TP
++.B redirect
++The
++.B redirect
++target will change the MAC target address to that of the physical nic the
++frame arrived on. This target can only be used in the
++.BR BROUTING " chain of the " broute " table and the "
++.BR PREROUTING " chain of the " nat " table."
++.br
++.BR "--redirect-target " "\fItarget\fP"
++.br
++Specifies the standard target. After doing the MAC redirect, the rule
++still has to give a standard target so ebtables knows what to do.
++The default target is ACCEPT. Making it CONTINUE could let you use
++multiple target extensions on the same frame. Making it DROP in the
++BROUTING chain will let the frames be routed.
+ .SH FILES
+ .I /etc/etherproto
+ .SH BUGS
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre4.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre4.001.diff
new file mode 100644
index 0000000..c4a9e39
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre4.001.diff
@@ -0,0 +1,522 @@
+--- ebtables-v2.0pre3/Makefile Sat Apr 27 22:31:19 2002
++++ ebtables-v2.0pre4.001/Makefile Thu May 2 19:02:44 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre3 (April 2002)"
++PROGVERSION:="2.0pre4 (April 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+@@ -32,12 +32,12 @@
+ mkdir -p $(@D)
+ install -m 0644 -o root -g root $< $@
+
+-/etc/etherproto: etherproto
++/etc/ethertypes: ethertypes
+ mkdir -p $(@D)
+ install -m 0644 -o root -g root $< $@
+
+ install: $(MANDIR)/man8/ebtables.8 headers \
+- ebtables /etc/etherproto
++ ebtables /etc/ethertypes
+
+ clean:
+ -rm -f ebtables
+--- ebtables-v2.0pre3/ebtables.c Sat Apr 27 22:31:21 2002
++++ ebtables-v2.0pre4.001/ebtables.c Fri May 3 20:56:14 2002
+@@ -36,7 +36,7 @@
+
+ // here are the number-name correspondences kept for the ethernet
+ // frame type field
+-#define PROTOCOLFILE "/etc/etherproto"
++#define PROTOCOLFILE "/etc/ethertypes"
+
+ #define DATABASEHOOKNR NF_BR_NUMHOOKS
+ #define DATABASEHOOKNAME "DB"
+@@ -90,6 +90,13 @@
+ "CONTINUE",
+ };
+
++unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
++unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
++unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
++unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
++unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
++unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
++
+ // tells what happened to the old rules
+ static unsigned short *counterchanges;
+ // holds all the data
+@@ -466,20 +473,70 @@
+ }
+ }
+ if (hlp->bitmask & EBT_SOURCEMAC) {
++ char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
++
+ printf("source mac: ");
+ if (hlp->invflags & EBT_ISOURCE)
+ printf("! ");
++ if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) &&
++ !memcmp(hlp->sourcemsk, msk_type_unicast, 6)) {
++ printf("Unicast");
++ goto endsrc;
++ }
++ if (!memcmp(hlp->sourcemac, mac_type_multicast, 6) &&
++ !memcmp(hlp->sourcemsk, msk_type_multicast, 6)) {
++ printf("Multicast");
++ goto endsrc;
++ }
++ if (!memcmp(hlp->sourcemac, mac_type_broadcast, 6) &&
++ !memcmp(hlp->sourcemsk, msk_type_broadcast, 6)) {
++ printf("Broadcast");
++ goto endsrc;
++ }
+ for (j = 0; j < ETH_ALEN; j++)
+ printf("%02x%s", hlp->sourcemac[j],
+- (j == ETH_ALEN - 1) ? ", " : ":");
++ (j == ETH_ALEN - 1) ? "" : ":");
++ if (memcmp(hlp->sourcemsk, hlpmsk, 6)) {
++ printf("/");
++ for (j = 0; j < ETH_ALEN; j++)
++ printf("%02x%s", hlp->sourcemsk[j],
++ (j == ETH_ALEN - 1) ? "" : ":");
++ }
++endsrc:
++ printf(", ");
+ }
+ if (hlp->bitmask & EBT_DESTMAC) {
++ char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
++
+ printf("dest mac: ");
+ if (hlp->invflags & EBT_IDEST)
+ printf("! ");
++ if (!memcmp(hlp->destmac, mac_type_unicast, 6) &&
++ !memcmp(hlp->destmsk, msk_type_unicast, 6)) {
++ printf("Unicast");
++ goto enddst;
++ }
++ if (!memcmp(hlp->destmac, mac_type_multicast, 6) &&
++ !memcmp(hlp->destmsk, msk_type_multicast, 6)) {
++ printf("Multicast");
++ goto enddst;
++ }
++ if (!memcmp(hlp->destmac, mac_type_broadcast, 6) &&
++ !memcmp(hlp->destmsk, msk_type_broadcast, 6)) {
++ printf("Broadcast");
++ goto enddst;
++ }
+ for (j = 0; j < ETH_ALEN; j++)
+ printf("%02x%s", hlp->destmac[j],
+- (j == ETH_ALEN - 1) ? ", " : ":");
++ (j == ETH_ALEN - 1) ? "" : ":");
++ if (memcmp(hlp->destmsk, hlpmsk, 6)) {
++ printf("/");
++ for (j = 0; j < ETH_ALEN; j++)
++ printf("%02x%s", hlp->destmsk[j],
++ (j == ETH_ALEN - 1) ? "" : ":");
++ }
++enddst:
++ printf(", ");
+ }
+ if (hlp->in[0] != '\0') {
+ if (hlp->invflags & EBT_IIN)
+@@ -1096,6 +1153,39 @@
+ return 0;
+ }
+
++int getmac_and_mask(char *from, char *to, char *mask)
++{
++ char *p;
++ int i;
++
++ if (strcasecmp(from, "Unicast") == 0) {
++ memcpy(to, mac_type_unicast, ETH_ALEN);
++ memcpy(mask, msk_type_unicast, ETH_ALEN);
++ return 0;
++ }
++ if (strcasecmp(from, "Multicast") == 0) {
++ memcpy(to, mac_type_multicast, ETH_ALEN);
++ memcpy(mask, msk_type_multicast, ETH_ALEN);
++ return 0;
++ }
++ if (strcasecmp(from, "Broadcast") == 0) {
++ memcpy(to, mac_type_broadcast, ETH_ALEN);
++ memcpy(mask, msk_type_broadcast, ETH_ALEN);
++ return 0;
++ }
++ if ( (p = strrchr(from, '/')) != NULL) {
++ *p = '\0';
++ if (getmac(p + 1, mask))
++ return -1;
++ } else
++ memset(mask, 0xff, ETH_ALEN);
++ if (getmac(from, to))
++ return -1;
++ for (i = 0; i < ETH_ALEN; i++)
++ to[i] &= mask[i];
++ return 0;
++}
++
+ int check_inverse(const char option[])
+ {
+ if (strcmp(option, "!") == 0) {
+@@ -1294,9 +1384,11 @@
+ print_error("Command and option do not match");
+ if (c == 'i') {
+ check_option(&replace.flags, OPT_IN);
+- if (replace.selected_hook > 2)
++ if (replace.selected_hook > 2 &&
++ replace.selected_hook < NF_BR_BROUTING)
+ print_error("Use in-interface only in "
+- "INPUT, FORWARD and PREROUTING chains");
++ "INPUT, FORWARD, PREROUTING and"
++ "BROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_IIN;
+
+@@ -1310,10 +1402,11 @@
+ }
+ if (c == 2) {
+ check_option(&replace.flags, OPT_LOGICALIN);
+- if (replace.selected_hook > 2)
++ if (replace.selected_hook > 2 &&
++ replace.selected_hook < NF_BR_BROUTING)
+ print_error("Use logical in-interface "
+- "only in INPUT, FORWARD and "
+- "PREROUTING chains");
++ "only in INPUT, FORWARD, "
++ "PREROUTING and BROUTING chains");
+ if (check_inverse(optarg))
+ new_entry->invflags |= EBT_ILOGICALIN;
+
+@@ -1398,8 +1491,8 @@
+ if (optind > argc)
+ print_error("No source mac "
+ "specified");
+- if (getmac(argv[optind - 1],
+- new_entry->sourcemac))
++ if (getmac_and_mask(argv[optind - 1],
++ new_entry->sourcemac, new_entry->sourcemsk))
+ print_error("Problem with specified "
+ "source mac");
+ new_entry->bitmask |= EBT_SOURCEMAC;
+@@ -1413,8 +1506,8 @@
+ if (optind > argc)
+ print_error("No destination mac "
+ "specified");
+- if (getmac(argv[optind - 1],
+- new_entry->destmac))
++ if (getmac_and_mask(argv[optind - 1],
++ new_entry->destmac, new_entry->destmsk))
+ print_error("Problem with specified "
+ "destination mac");
+ new_entry->bitmask |= EBT_DESTMAC;
+--- ebtables-v2.0pre3/communication.c Sat Apr 27 22:31:19 2002
++++ ebtables-v2.0pre4.001/communication.c Thu May 2 19:02:44 2002
+@@ -121,7 +121,10 @@
+ sizeof(tmp->logical_out));
+ memcpy(tmp->sourcemac, e->sourcemac,
+ sizeof(tmp->sourcemac));
++ memcpy(tmp->sourcemsk, e->sourcemsk,
++ sizeof(tmp->sourcemsk));
+ memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
++ memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
+
+ base = p;
+ p += sizeof(struct ebt_entry);
+@@ -307,7 +310,9 @@
+ memcpy(new->logical_out, e->logical_out,
+ sizeof(new->logical_out));
+ memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
++ memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
+ memcpy(new->destmac, e->destmac, sizeof(new->destmac));
++ memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
+ new->m_list = NULL;
+ new->w_list = NULL;
+ new->next = NULL;
+--- ebtables-v2.0pre3/ChangeLog Sat Apr 27 22:31:21 2002
++++ ebtables-v2.0pre4.001/ChangeLog Thu May 2 19:02:44 2002
+@@ -1,3 +1,11 @@
++20020501
++ * allow -i and --logical-in in BROUTING
++ * update the manual page
++ * rename /etc/etherproto into /etc/ethertypes (seems to be a more
++ standard name)
++ * add MAC mask for -s and -d, also added Unicast, Multicast and
++ Broadcast specification for specifying a (family of) MAC
++ addresses.
+ 20020427
+ * added broute table.
+ * added redirect target.
+--- ebtables-v2.0pre3/ebtables.8 Sat Apr 27 22:31:21 2002
++++ ebtables-v2.0pre4.001/ebtables.8 Thu May 2 19:02:44 2002
+@@ -1,4 +1,4 @@
+-.TH EBTABLES 8 "27 April 2002"
++.TH EBTABLES 8 "01 May 2002"
+ .\"
+ .\" Man page written by Bart De Schuymer <bart.de.schuymer@pandora.be>
+ .\" It is based on the iptables man page.
+@@ -31,7 +31,7 @@
+ .br
+ .B "ebtables -L DB"
+ .br
+-.BR "ebtables -[cb] [" "y/n" "]"
++.BR "ebtables -[b] [" "y/n" "]"
+ .br
+ .SH DESCRIPTION
+ .B ebtables
+@@ -88,13 +88,14 @@
+ .B POSTROUTING
+ (for altering frames as they are about to go out). A small note on the naming
+ of chains POSTROUTING and PREROUTING: it would be more accurate to call them
+-PREFORWARDING and POSTFORWARDING, but for all those who come from the iptables
+-world to ebtables it is easier to have the same names.
++PREFORWARDING and POSTFORWARDING, but for all those who come from the
++.BR iptables " world to " ebtables
++it is easier to have the same names.
+ .BR broute ,
+ this table is used to make a brouter, it has one chain:
+ .BR BROUTING .
+ The targets
+-.BR DROP and ACCEPT
++.BR DROP " and " ACCEPT
+ have special meaning in this table.
+ .B DROP
+ actually means the frame has to be routed, while
+@@ -178,8 +179,9 @@
+ .B ebtables
+ for these frames is
+ .BR LENGTH .
++.br
+ The file
+-.B /etc/etherproto
++.B /etc/ethertypes
+ can be used to show readable
+ characters instead of hexadecimal numbers for the protocols. For example,
+ .I 0x0800
+@@ -193,9 +195,8 @@
+ .BR "-i, --in-interface " "[!] \fIname\fP"
+ The interface via which a frame is received (for the
+ .BR INPUT ,
+-.B FORWARD
+-and
+-.B PREROUTING
++.BR FORWARD ,
++.BR PREROUTING " and " BROUTING
+ chains). The flag
+ .B --in-if
+ is an alias for this option.
+@@ -203,9 +204,8 @@
+ .BR "--logical-in " "[!] \fIname\fP"
+ The (logical) bridge interface via which a frame is received (for the
+ .BR INPUT ,
+-.B FORWARD
+-and
+-.B PREROUTING
++.BR FORWARD ,
++.BR PREROUTING " and " BROUTING
+ chains).
+ .TP
+ .BR "-o, --out-interface " "[!] \fIname\fP"
+@@ -227,23 +227,31 @@
+ .B POSTROUTING
+ chains).
+ .TP
+-.BR "-s, --source " "[!] \fIaddress\fP"
+-The source mac address. The flag
++.BR "-s, --source " "[!] \fIaddress\fP[/\fImask\fP]"
++The source mac address. Both mask and address are written as 6 hexadecimal
++numbers seperated by colons. Alternatively one can specify Unicast,
++Multicast or Broadcast.
++.br
++Unicast=00:00:00:00:00:00/01:00:00:00:00:00,
++Multicast=01:00:00:00:00:00/01:00:00:00:00:00 and
++Broadcast=ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff. Note that a broadcast
++address will also match the multicast specification. The flag
+ .B --src
+ is an alias for this option.
+ .TP
+-.BR "-d, --destination " "[!] \fIaddress\fP"
+-The destination mac address. The flag
++.BR "-d, --destination " "[!] \fIaddress\fP[/\fImask\fP]"
++The destination mac address. See -s (above) for more details. The flag
+ .B --dst
+ is an alias for this option.
+
+ .SS OTHER OPTIONS
++.TP
+ .B "-V, --version"
+ Show the version of the userprogram.
+ .TP
+ .B "-h, --help"
+-Give a brief description of the command syntax. Here you can specify names of
+-extensions and
++Give a brief description of the command syntax. Here you can also specify
++names of extensions and
+ .B ebtables
+ will try to write help about those extensions. E.g. ebtables -h snat log ip arp.
+ .TP
+@@ -258,7 +266,8 @@
+ or a target extension, see
+ .BR "TARGET EXTENSIONS" .
+ .SH MATCH EXTENSIONS
+-ebtables extensions are precompiled into the userspace tool. So there is no need
++.B ebtables
++extensions are precompiled into the userspace tool. So there is no need
+ to explicitly load them with a -m option like in iptables. However, these
+ extensions deal with functionality supported by supplemental kernel modules.
+ .SS ip
+@@ -291,10 +300,11 @@
+ .BR ARP " or " RARP .
+ .TP
+ .BR "--arp-opcode " "[!] \fIopcode\fP"
+-The (r)arp opcode (decimal or a string, see ebtables help).
++The (r)arp opcode (decimal or a string, for more details see ebtables -h arp).
+ .TP
+ .BR "--arp-htype " "[!] \fIhardware type\fP"
+-The hardware type (decimal or the string "Ethernet"). This is normally Ethernet (value 1).
++The hardware type, this can be a decimal or the string "Ethernet". This
++is normally Ethernet (value 1).
+ .TP
+ .BR "--arp-ptype " "[!] \fIprotocol type\fP"
+ The protocol type for which the (r)arp is used (hexadecimal or the string "IPv4").
+@@ -354,7 +364,9 @@
+ .BR "--snat-target " "\fItarget\fP"
+ .br
+ Specifies the standard target. After doing the snat, the rule still has
+-to give a standard target so ebtables knows what to do.
++to give a standard target so
++.B ebtables
++knows what to do.
+ The default target is ACCEPT. Making it CONTINUE could let you use
+ multiple target extensions on the same frame. Making it DROP doesn't
+ make sense, but you could do that too.
+@@ -376,7 +388,9 @@
+ .BR "--dnat-target " "\fItarget\fP"
+ .br
+ Specifies the standard target. After doing the dnat, the rule still has to
+-give a standard target so ebtables knows what to do.
++give a standard target so
++.B ebtables
++knows what to do.
+ The default target is ACCEPT. Making it CONTINUE could let you use
+ multiple target extensions on the same frame. Making it DROP only makes
+ sense in the BROUTING chain but using the redirect target is more logical
+@@ -385,7 +399,7 @@
+ .B redirect
+ The
+ .B redirect
+-target will change the MAC target address to that of the physical nic the
++target will change the MAC target address to that of the bridge device the
+ frame arrived on. This target can only be used in the
+ .BR BROUTING " chain of the " broute " table and the "
+ .BR PREROUTING " chain of the " nat " table."
+@@ -393,12 +407,14 @@
+ .BR "--redirect-target " "\fItarget\fP"
+ .br
+ Specifies the standard target. After doing the MAC redirect, the rule
+-still has to give a standard target so ebtables knows what to do.
++still has to give a standard target so
++.B ebtables
++knows what to do.
+ The default target is ACCEPT. Making it CONTINUE could let you use
+ multiple target extensions on the same frame. Making it DROP in the
+ BROUTING chain will let the frames be routed.
+ .SH FILES
+-.I /etc/etherproto
++.I /etc/ethertypes
+ .SH BUGS
+ This won't work on an architecture with a user32/kernel64 situation like the Sparc64.
+ .SH AUTHOR
+--- ebtables-v2.0pre3/etherproto Wed Apr 3 13:16:59 2002
++++ /dev/null Thu Aug 24 11:00:32 2000
+@@ -1,36 +0,0 @@
+- # all whitespace is ignored
+- # comment lines must have a '#' as the first character
+- # all protocol numbers are in hexadecimal form
+- # maximum namesize = 20 characters
+- # always put tabs or spaces between the name and the protocol number
+-# don't use more than 4 digits for the protocol number
+-# programs using this file should not be case sensitive
+-# that's all :-))
+-IPV4 0800 put your comments behind, on the same line, after a tab
+-X25 0800 or whitespace
+-ARP 0806
+-IPX 8137
+-IPV6 86DD
+-NetBEUI 8191
+-
+-# some definitions from the kernel (/include/linux/if_ether.h)
+-
+-BPQ 08FF G8BPQ AX.25 Ethernet Packet
+-DEC 6000 DEC Assigned proto
+-DNA_DL 6001 DEC DNA Dump/Load
+-DNA_RC 6002 DEC DNA Remote Console
+-DNA_RT 6003 DEC DNA Routing
+-LAT 6004 DEC LAT
+-DIAG 6005 DEC Diagnostics
+-CUST 6006 DEC Customer use
+-SCA 6007 DEC Systems Comms Arch
+-RARP 8035 Reverse Addr Res packet
+-ATALK 809B Appletalk DDP
+-AARP 80F3 Appletalk AARP
+-IPX 8137 IPX over DIX
+-PPP_DISC 8863 PPPoE discovery messages
+-PPP_SES 8864 PPPoE session messages
+-ATMMPOA 884C MultiProtocol over ATM
+-ATMFATE 8884 Frame-based ATM Transport over Ethernet
+-
+-
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebtables-v2.0pre4.001/ethertypes Thu May 2 19:02:44 2002
+@@ -0,0 +1,36 @@
++ # all whitespace is ignored
++ # comment lines must have a '#' as the first character
++ # all protocol numbers are in hexadecimal form
++ # maximum namesize = 20 characters
++ # always put tabs or spaces between the name and the protocol number
++# don't use more than 4 digits for the protocol number
++# programs using this file should not be case sensitive
++# that's all :-))
++IPV4 0800 put your comments behind, on the same line, after a tab
++X25 0800 or whitespace
++ARP 0806
++IPX 8137
++IPV6 86DD
++NetBEUI 8191
++
++# some definitions from the kernel (/include/linux/if_ether.h)
++
++BPQ 08FF G8BPQ AX.25 Ethernet Packet
++DEC 6000 DEC Assigned proto
++DNA_DL 6001 DEC DNA Dump/Load
++DNA_RC 6002 DEC DNA Remote Console
++DNA_RT 6003 DEC DNA Routing
++LAT 6004 DEC LAT
++DIAG 6005 DEC Diagnostics
++CUST 6006 DEC Customer use
++SCA 6007 DEC Systems Comms Arch
++RARP 8035 Reverse Addr Res packet
++ATALK 809B Appletalk DDP
++AARP 80F3 Appletalk AARP
++IPX 8137 IPX over DIX
++PPP_DISC 8863 PPPoE discovery messages
++PPP_SES 8864 PPPoE session messages
++ATMMPOA 884C MultiProtocol over ATM
++ATMFATE 8884 Frame-based ATM Transport over Ethernet
++
++
+--- ebtables-v2.0pre3/include/ebtables_u.h Sat Apr 27 22:31:16 2002
++++ ebtables-v2.0pre4.001/include/ebtables_u.h Thu May 2 19:02:44 2002
+@@ -86,7 +86,9 @@
+ __u8 out[IFNAMSIZ];
+ __u8 logical_out[IFNAMSIZ];
+ __u8 sourcemac[ETH_ALEN];
++ __u8 sourcemsk[ETH_ALEN];
+ __u8 destmac[ETH_ALEN];
++ __u8 destmsk[ETH_ALEN];
+ struct ebt_u_match_list *m_list;
+ struct ebt_u_watcher_list *w_list;
+ struct ebt_entry_target *t;
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre5.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre5.001.diff
new file mode 100644
index 0000000..42202a4
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre5.001.diff
@@ -0,0 +1,50 @@
+update help and VLAN ethertype in /etc/ethertypes
+
+--- ebtables-v2.0pre4/Makefile Fri May 3 21:08:24 2002
++++ ebtables-v2.0pre5.001/Makefile Fri May 3 21:34:23 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre4 (April 2002)"
++PROGVERSION:="2.0pre5 (April 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+--- ebtables-v2.0pre4/ebtables.c Fri May 3 21:08:24 2002
++++ ebtables-v2.0pre5.001/ebtables.c Fri May 3 21:33:55 2002
+@@ -628,8 +628,8 @@
+ "--policy -P chain target : Change policy on chain to target\n"
+ "Options:\n"
+ "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
+-"--src -s [!] address : source mac address\n"
+-"--dst -d [!] address : destination mac address\n"
++"--src -s [!] address[/mask]: source mac address\n"
++"--dst -d [!] address[/mask]: destination mac address\n"
+ "--in-if -i [!] name : network input interface name\n"
+ "--out-if -o [!] name : network output interface name\n"
+ "--logical-in [!] name : logical bridge input interface name\n"
+--- ebtables-v2.0pre4/ChangeLog Fri May 3 21:08:25 2002
++++ ebtables-v2.0pre5.001/ChangeLog Sat May 18 10:30:44 2002
+@@ -1,3 +1,5 @@
++ * update help for -s and -d
++ * add VLAN in ethertypes
+ 20020501
+ * allow -i and --logical-in in BROUTING
+ * update the manual page
+--- ebtables-v2.0pre4/ethertypes Fri May 3 21:08:25 2002
++++ ebtables-v2.0pre5.001/ethertypes Sat May 18 10:30:10 2002
+@@ -9,12 +9,10 @@
+ IPV4 0800 put your comments behind, on the same line, after a tab
+ X25 0800 or whitespace
+ ARP 0806
++VLAN 8100
+ IPX 8137
+ IPV6 86DD
+ NetBEUI 8191
+-
+-# some definitions from the kernel (/include/linux/if_ether.h)
+-
+ BPQ 08FF G8BPQ AX.25 Ethernet Packet
+ DEC 6000 DEC Assigned proto
+ DNA_DL 6001 DEC DNA Dump/Load
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre5.002.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre5.002.diff
new file mode 100644
index 0000000..5b2d037
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre5.002.diff
@@ -0,0 +1,61 @@
+--- ebtables-v2.0pre5.001/Makefile Mon May 20 13:59:48 2002
++++ ebtables-v2.0pre5.002/Makefile Mon May 20 14:06:38 2002
+@@ -2,12 +2,19 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre5 (April 2002)"
++PROGVERSION:="2.0pre5 (May 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+ include extensions/Makefile
+
++# Some kernel testers prefer to use a symlink for /usr/include/linux
++ifeq ($(SYMLINK), y)
++KERNEL_INCLUDES=symlink
++else
++KERNEL_INCLUDES=headers
++endif
++
+ .PHONY: headers
+ headers:
+ mkdir -p /usr/include/linux/netfilter_bridge
+@@ -18,6 +25,10 @@
+ cp -f $(KERNEL_DIR)/include/linux/netfilter_bridge.h \
+ /usr/include/linux/netfilter_bridge.h
+
++.PHONY: symlink
++symlink:
++ ln -fs $(KERNEL_DIR)/include/linux /usr/include/linux
++
+ communication.o: communication.c include/ebtables_u.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+@@ -36,7 +47,7 @@
+ mkdir -p $(@D)
+ install -m 0644 -o root -g root $< $@
+
+-install: $(MANDIR)/man8/ebtables.8 headers \
++install: $(MANDIR)/man8/ebtables.8 $(KERNEL_INCLUDES) \
+ ebtables /etc/ethertypes
+
+ clean:
+--- ebtables-v2.0pre5.001/THANKS Sat Apr 13 17:40:35 2002
++++ ebtables-v2.0pre5.002/THANKS Mon May 20 13:49:50 2002
+@@ -6,4 +6,4 @@
+ Jason Lunz
+ Tim Gardner
+ Loïc Minier
+-
++Nick Fedchik
+--- ebtables-v2.0pre5.001/ChangeLog Mon May 20 13:59:48 2002
++++ ebtables-v2.0pre5.002/ChangeLog Mon May 20 13:49:27 2002
+@@ -1,5 +1,7 @@
++20020520
+ * update help for -s and -d
+ * add VLAN in ethertypes
++ * add SYMLINK option for compiling
+ 20020501
+ * allow -i and --logical-in in BROUTING
+ * update the manual page
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre6.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre6.001.diff
new file mode 100644
index 0000000..a143d62
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre6.001.diff
@@ -0,0 +1,314 @@
+--- ebtables-v2.0pre5/Makefile Mon May 20 14:06:38 2002
++++ ebtables-v2.0pre6.001/Makefile Thu May 30 18:39:04 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre5 (May 2002)"
++PROGVERSION:="2.0pre6 (May 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+@@ -15,6 +15,8 @@
+ KERNEL_INCLUDES=headers
+ endif
+
++all: ebtables
++
+ .PHONY: headers
+ headers:
+ mkdir -p /usr/include/linux/netfilter_bridge
+@@ -52,3 +54,5 @@
+
+ clean:
+ -rm -f ebtables
++ rm -f *.o *.c~
++ rm -f extensions/*.o extensions/*.c~
+--- /dev/null Thu Aug 24 11:00:32 2000
++++ ebtables-v2.0pre6.001/extensions/ebt_vlan.c Thu May 30 18:38:44 2002
+@@ -0,0 +1,231 @@
++/*
++ * Summary: ebt_vlan userspace module
++ *
++ * Description: 802.1Q Virtual LAN match support module for ebtables project.
++ * Enable to match 802.1Q VLAN tagged frames by VLAN numeric
++ * identifier (12-bites field) and frame priority (3-bites field)
++ *
++ * Authors:
++ * Bart De Schuymer <bart.de.schuymer@pandora.be>
++ * Nick Fedchik <nick@fedchik.org.ua>
++ *
++ * May, 2002
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <linux/netfilter_bridge/ebtables.h>
++#include <getopt.h>
++#include "../include/ebtables_u.h"
++#include <linux/netfilter_bridge/ebt_vlan.h>
++
++#define VLAN_ID '1'
++#define VLAN_PRIO '2'
++
++static struct option opts[] = {
++ {"vlan-id", required_argument, 0, VLAN_ID},
++ {"vlan-prio", required_argument, 0, VLAN_PRIO},
++ {0}
++};
++
++/*
++ * Print out help for ebtables -h vlan
++ */
++static void print_help ()
++{
++ printf ("802.1Q VLAN options:\n"
++ "--vlan-id [!] id : VLAN ID 1-4095 (integer)\n"
++ "--vlan-prio [!] prio : VLAN Priority 0-7 (integer)\n");
++}
++
++/*
++ * Initialization function
++ */
++static void init (struct ebt_entry_match *match)
++{
++ struct ebt_vlan_info *vlaninfo =
++ (struct ebt_vlan_info *) match->data;
++ /*
++ * Just clean initial values
++ */
++ vlaninfo->id = 0;
++ vlaninfo->prio = 0;
++ vlaninfo->invflags = 0;
++ vlaninfo->bitmask = 0;
++}
++
++#define OPT_VLAN_ID 0x01
++#define OPT_VLAN_PRIO 0x02
++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_vlan_info *vlaninfo =
++ (struct ebt_vlan_info *) (*match)->data;
++ unsigned short i;
++ char *end;
++
++ switch (c) {
++ case VLAN_ID:
++ check_option (flags, OPT_VLAN_ID);
++ /*
++ * Check If we got inversed arg for VID,
++ * otherwise unset inversion flag
++ */
++ if (check_inverse (optarg))
++ vlaninfo->invflags |= EBT_VLAN_ID;
++ /*
++ * Check arg value presense
++ */
++ if (optind > argc)
++ print_error ("Missing VLAN ID argument\n");
++ /*
++ * Convert argv to long int,
++ * set *end to end of argv string,
++ * base set 10 for decimal only
++ */
++ (unsigned short) i = strtol (argv[optind - 1], &end, 10);
++ /*
++ * Check arg val range
++ */
++ if (i < 1 || i >= 4096 || *end != '\0') {
++ i = 0;
++ print_error
++ ("Problem with specified VLAN ID range\n");
++ }
++ vlaninfo->id = i;
++ vlaninfo->bitmask|=EBT_VLAN_ID;
++ break;
++
++ case VLAN_PRIO:
++ check_option (flags, OPT_VLAN_PRIO);
++ if (check_inverse (optarg))
++ vlaninfo->invflags |= EBT_VLAN_PRIO;
++ if (optind > argc)
++ print_error
++ ("Missing VLAN Priority level argument\n");
++ /*
++ * Convert argv to long int,
++ * set *end to end of argv string,
++ * base set 10 for decimal only
++ */
++ (unsigned short) i = strtol (argv[optind - 1], &end, 10);
++ /*
++ * Check arg val range
++ */
++ if (i >= 8 || *end != '\0') {
++ i = 0;
++ print_error
++ ("Problem with specified VLAN Priority range\n");
++ }
++ vlaninfo->prio = i;
++ vlaninfo->bitmask|=EBT_VLAN_PRIO;
++ break;
++
++ default:
++ return 0;
++ }
++ return 1;
++}
++
++/*
++ * Final check
++ */
++static void
++final_check (const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match,
++ const char *name, unsigned int hook)
++{
++ /*
++ * Is any proto supplied there? Or specified proto isn't 802.1Q?
++ */
++ if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q)
++ print_error
++ ("For matching 802.1Q VLAN the protocol must be specified as 802_1Q\n");
++}
++
++/*
++ * Print line when listing rules by ebtables -L
++ */
++static void
++print (const struct ebt_u_entry *entry,
++ const struct ebt_entry_match *match)
++{
++ struct ebt_vlan_info *vlaninfo =
++ (struct ebt_vlan_info *) match->data;
++
++ /*
++ * Print VLAN ID if they are specified
++ */
++ if (vlaninfo->bitmask & EBT_VLAN_ID) {
++ printf ("vlan id: %s%d, ",
++ vlaninfo->invflags & EBT_VLAN_ID ? "!" : "",
++ vlaninfo->id);
++ }
++ /*
++ * Print VLAN priority if they are specified
++ */
++ if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
++ printf ("vlan prio: %s%d, ",
++ vlaninfo->invflags & EBT_VLAN_PRIO ? "!" : "",
++ vlaninfo->prio);
++ }
++}
++
++
++static int
++compare (const struct ebt_entry_match *vlan1,
++ const struct ebt_entry_match *vlan2)
++{
++ struct ebt_vlan_info *vlaninfo1 =
++ (struct ebt_vlan_info *) vlan1->data;
++ struct ebt_vlan_info *vlaninfo2 =
++ (struct ebt_vlan_info *) vlan2->data;
++ /*
++ * Compare argc
++ */
++ if (vlaninfo1->bitmask != vlaninfo2->bitmask)
++ return 0;
++ /*
++ * Compare inv flags
++ */
++ if (vlaninfo1->invflags != vlaninfo2->invflags)
++ return 0;
++ /*
++ * Compare VLAN ID if they are present
++ */
++ if (vlaninfo1->bitmask & EBT_VLAN_ID) {
++ if (vlaninfo1->id != vlaninfo2->id)
++ return 0;
++ };
++ /*
++ * Compare VLAN Prio if they are present
++ */
++ if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
++ if (vlaninfo1->prio != vlaninfo2->prio)
++ return 0;
++ };
++ return 1;
++}
++
++static struct ebt_u_match vlan_match = {
++ EBT_VLAN_MATCH,
++ sizeof (struct ebt_vlan_info),
++ print_help,
++ init,
++ parse,
++ final_check,
++ print,
++ compare,
++ opts,
++};
++
++static void _init (void) __attribute__ ((constructor));
++static void _init (void)
++{
++ register_match (&vlan_match);
++}
+--- ebtables-v2.0pre5/extensions/Makefile Sat Apr 27 22:31:21 2002
++++ ebtables-v2.0pre6.001/extensions/Makefile Thu May 30 18:38:44 2002
+@@ -1,6 +1,6 @@
+ #! /usr/bin/make
+
+-EXT_FUNC+=nat arp ip standard log redirect
++EXT_FUNC+=nat arp ip standard log redirect vlan
+ EXT_TABLES+=filter nat broute
+ EXT_OBJS+=$(foreach T,$(EXT_FUNC), extensions/ebt_$(T).o)
+ EXT_OBJS+=$(foreach T,$(EXT_TABLES), extensions/ebtable_$(T).o)
+--- ebtables-v2.0pre5/ebtables.8 Fri May 3 21:08:25 2002
++++ ebtables-v2.0pre6.001/ebtables.8 Thu May 30 18:43:19 2002
+@@ -315,6 +315,17 @@
+ .TP
+ .BR "--arp-ip-dst " "[!] \fIaddress\fP[/\fImask\fP]"
+ The ARP IP destination address specification.
++.SS vlan
++Specify 802.1Q VLAN specific fields. These will only work if the protocol equals
++.BR 802_1Q .
++For more details see
++.BR "ebtables -h vlan" .
++.TP
++.BR "--vlan-id " "[!] \fIid\fP"
++The VLAN identifier (decimal number from 0 to 4095).
++.TP
++.BR "--vlan-prio " "[!] \fIprio\fP"
++The VLAN priority type, this can be a decimal number from 0 to 7. The default value is 0.
+ .SH WATCHER EXTENSION(S)
+ Watchers are things that only look at frames passing by. These watchers only see the
+ frame if the frame passes all the matches of the rule.
+--- ebtables-v2.0pre5/ethertypes Sat May 18 10:30:10 2002
++++ ebtables-v2.0pre6.001/ethertypes Thu May 30 18:38:44 2002
+@@ -1,15 +1,15 @@
+- # all whitespace is ignored
+- # comment lines must have a '#' as the first character
+- # all protocol numbers are in hexadecimal form
+- # maximum namesize = 20 characters
+- # always put tabs or spaces between the name and the protocol number
++# all whitespace is ignored
++# comment lines must have a '#' as the first character
++# all protocol numbers are in hexadecimal form
++# maximum namesize = 20 characters
++# always put tabs or spaces between the name and the protocol number
+ # don't use more than 4 digits for the protocol number
+ # programs using this file should not be case sensitive
+ # that's all :-))
+ IPV4 0800 put your comments behind, on the same line, after a tab
+ X25 0800 or whitespace
+ ARP 0806
+-VLAN 8100
++802_1Q 8100 802.1Q Virtual LAN tagged frame
+ IPX 8137
+ IPV6 86DD
+ NetBEUI 8191
diff --git a/userspace/patches/zipped/ebtables-v2.0pre1.tar.gz b/userspace/patches/zipped/ebtables-v2.0pre1.tar.gz
new file mode 100644
index 0000000..52322df
--- /dev/null
+++ b/userspace/patches/zipped/ebtables-v2.0pre1.tar.gz
Binary files differ
diff --git a/userspace/patches/zipped/ebtables-v2.0pre2.tar.gz b/userspace/patches/zipped/ebtables-v2.0pre2.tar.gz
new file mode 100644
index 0000000..e398d7c
--- /dev/null
+++ b/userspace/patches/zipped/ebtables-v2.0pre2.tar.gz
Binary files differ
diff --git a/userspace/patches/zipped/ebtables-v2.0pre3.tar.gz b/userspace/patches/zipped/ebtables-v2.0pre3.tar.gz
new file mode 100644
index 0000000..d27fac2
--- /dev/null
+++ b/userspace/patches/zipped/ebtables-v2.0pre3.tar.gz
Binary files differ
diff --git a/userspace/patches/zipped/ebtables-v2.0pre4.tar.gz b/userspace/patches/zipped/ebtables-v2.0pre4.tar.gz
new file mode 100644
index 0000000..7fc57ce
--- /dev/null
+++ b/userspace/patches/zipped/ebtables-v2.0pre4.tar.gz
Binary files differ
diff --git a/userspace/patches/zipped/ebtables-v2.0pre5.tar.gz b/userspace/patches/zipped/ebtables-v2.0pre5.tar.gz
new file mode 100644
index 0000000..c09e318
--- /dev/null
+++ b/userspace/patches/zipped/ebtables-v2.0pre5.tar.gz
Binary files differ
diff --git a/userspace/patches/zipped/ebtables-v2.0pre6.tar.gz b/userspace/patches/zipped/ebtables-v2.0pre6.tar.gz
new file mode 100644
index 0000000..dd0fedc
--- /dev/null
+++ b/userspace/patches/zipped/ebtables-v2.0pre6.tar.gz
Binary files differ