From d891e9e5bc309d5aeb2ab774c76b34a92085b3e7 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Sat, 1 Jun 2002 19:23:47 +0000 Subject: Initial revision --- userspace/ebtables2/COPYING | 339 +++ userspace/ebtables2/ChangeLog | 51 + userspace/ebtables2/INSTALL | 27 + userspace/ebtables2/Makefile | 58 + userspace/ebtables2/THANKS | 9 + userspace/ebtables2/communication.c | 454 ++++ userspace/ebtables2/ebtables.8 | 434 ++++ userspace/ebtables2/ebtables.c | 1655 +++++++++++++++ userspace/ebtables2/ethertypes | 34 + userspace/ebtables2/extensions/Makefile | 12 + userspace/ebtables2/extensions/ebt_arp.c | 289 +++ userspace/ebtables2/extensions/ebt_ip.c | 318 +++ userspace/ebtables2/extensions/ebt_log.c | 197 ++ userspace/ebtables2/extensions/ebt_nat.c | 222 ++ userspace/ebtables2/extensions/ebt_redirect.c | 109 + userspace/ebtables2/extensions/ebt_standard.c | 70 + userspace/ebtables2/extensions/ebt_vlan.c | 231 ++ userspace/ebtables2/extensions/ebtable_broute.c | 25 + userspace/ebtables2/extensions/ebtable_filter.c | 32 + userspace/ebtables2/extensions/ebtable_nat.c | 32 + userspace/ebtables2/include/ebtables_u.h | 206 ++ .../incremental-patches/ebtables-v2.0pre2.001.diff | 121 ++ .../incremental-patches/ebtables-v2.0pre2.002.diff | 2204 ++++++++++++++++++++ .../incremental-patches/ebtables-v2.0pre2.003.diff | 40 + .../incremental-patches/ebtables-v2.0pre2.004.diff | 50 + .../incremental-patches/ebtables-v2.0pre3.001.diff | 245 +++ .../incremental-patches/ebtables-v2.0pre3.002.diff | 194 ++ .../incremental-patches/ebtables-v2.0pre3.003.diff | 66 + .../incremental-patches/ebtables-v2.0pre3.004.diff | 483 +++++ .../incremental-patches/ebtables-v2.0pre4.001.diff | 522 +++++ .../incremental-patches/ebtables-v2.0pre5.001.diff | 50 + .../incremental-patches/ebtables-v2.0pre5.002.diff | 61 + .../incremental-patches/ebtables-v2.0pre6.001.diff | 314 +++ userspace/patches/zipped/ebtables-v2.0pre1.tar.gz | Bin 0 -> 32529 bytes userspace/patches/zipped/ebtables-v2.0pre2.tar.gz | Bin 0 -> 49417 bytes userspace/patches/zipped/ebtables-v2.0pre3.tar.gz | Bin 0 -> 51235 bytes userspace/patches/zipped/ebtables-v2.0pre4.tar.gz | Bin 0 -> 52135 bytes userspace/patches/zipped/ebtables-v2.0pre5.tar.gz | Bin 0 -> 35558 bytes userspace/patches/zipped/ebtables-v2.0pre6.tar.gz | Bin 0 -> 36908 bytes 39 files changed, 9154 insertions(+) create mode 100644 userspace/ebtables2/COPYING create mode 100644 userspace/ebtables2/ChangeLog create mode 100644 userspace/ebtables2/INSTALL create mode 100644 userspace/ebtables2/Makefile create mode 100644 userspace/ebtables2/THANKS create mode 100644 userspace/ebtables2/communication.c create mode 100644 userspace/ebtables2/ebtables.8 create mode 100644 userspace/ebtables2/ebtables.c create mode 100644 userspace/ebtables2/ethertypes create mode 100644 userspace/ebtables2/extensions/Makefile create mode 100644 userspace/ebtables2/extensions/ebt_arp.c create mode 100644 userspace/ebtables2/extensions/ebt_ip.c create mode 100644 userspace/ebtables2/extensions/ebt_log.c create mode 100644 userspace/ebtables2/extensions/ebt_nat.c create mode 100644 userspace/ebtables2/extensions/ebt_redirect.c create mode 100644 userspace/ebtables2/extensions/ebt_standard.c create mode 100644 userspace/ebtables2/extensions/ebt_vlan.c create mode 100644 userspace/ebtables2/extensions/ebtable_broute.c create mode 100644 userspace/ebtables2/extensions/ebtable_filter.c create mode 100644 userspace/ebtables2/extensions/ebtable_nat.c create mode 100644 userspace/ebtables2/include/ebtables_u.h create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre2.001.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre2.002.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre2.003.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre2.004.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre3.001.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre3.002.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre3.003.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre3.004.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre4.001.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre5.001.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre5.002.diff create mode 100644 userspace/patches/incremental-patches/ebtables-v2.0pre6.001.diff create mode 100644 userspace/patches/zipped/ebtables-v2.0pre1.tar.gz create mode 100644 userspace/patches/zipped/ebtables-v2.0pre2.tar.gz create mode 100644 userspace/patches/zipped/ebtables-v2.0pre3.tar.gz create mode 100644 userspace/patches/zipped/ebtables-v2.0pre4.tar.gz create mode 100644 userspace/patches/zipped/ebtables-v2.0pre5.tar.gz create mode 100644 userspace/patches/zipped/ebtables-v2.0pre6.tar.gz (limited to 'userspace') 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. + + + Copyright (C) 19yy + + 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. + + , 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=<> 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=<> 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 +#include +#include +#include +#include +#include +#include +#include // the database +#include // IPPROTO_IP +#include +#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 +.\" 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 +#include +#include +#include +#include +#include +#include +#include +#include // the database +#include +#include +#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 -L ) + 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 +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +#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 +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +#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 +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +// 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 +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +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 +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +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 +#include +#include +#include +#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 + * Nick Fedchik + * + * May, 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + +#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 +#include +#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 +#include +#include +#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 +#include +#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 +#include + +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 + #include +-#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 + #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 -L ) ++ // this special one for the -Z option (we can have -Z -L ) ++ 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 + #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 + #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 + .\" 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 ++#include ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../include/ebtables_u.h" ++#include ++ ++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 + ++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 + .\" 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 + .\" 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 ++ * Nick Fedchik ++ * ++ * May, 2002 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../include/ebtables_u.h" ++#include ++ ++#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 Binary files /dev/null and b/userspace/patches/zipped/ebtables-v2.0pre1.tar.gz 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 Binary files /dev/null and b/userspace/patches/zipped/ebtables-v2.0pre2.tar.gz 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 Binary files /dev/null and b/userspace/patches/zipped/ebtables-v2.0pre3.tar.gz 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 Binary files /dev/null and b/userspace/patches/zipped/ebtables-v2.0pre4.tar.gz 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 Binary files /dev/null and b/userspace/patches/zipped/ebtables-v2.0pre5.tar.gz 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 Binary files /dev/null and b/userspace/patches/zipped/ebtables-v2.0pre6.tar.gz differ -- cgit v1.2.3