Permalink
Browse files

Initial import of L3DSR sources from Yahoo!

  • Loading branch information...
0 parents commit 4096f817009336e45ffea7ac1883dc1a082d7eb1 @jschauma jschauma committed Mar 8, 2011
32 README
@@ -0,0 +1,32 @@
+Direct Server Return (DSR) load balancing is a common way to distribute
+network traffic using an approach that currently requires the load
+balancer and all hosts behind the Virtual IP (VIP) to be within the same
+Layer 2 network. This is a severe limitation that hinders scaling VIPs
+beyond a single contiguous subnet. To overcome this limitation, we
+present a method to perform DSR load balancing across Layer 3 boundaries
+(``L3DSR''), a solution that allows Yahoo! to serve up to ten times as
+many VIPs on a single hardware Load Balancer compared to other Layer 3
+load balancing methods.
+
+In order to overcome Layer 2 limitations, we use the 6-bit bit
+Differentiated Services Code Point (DSCP) field of the IPv4 header used
+for packet classification to relay information to the server. The server
+inspects the header and rewrites the destination address based on the
+value of the DSCP field and according to its own mapping of DSCP values to
+destination addresses.
+
+L3DSR is currently supported by:
+ - A10 AX3200 >= 2.2.5
+ - Brocade ADX Series >= 12.1d
+ - Brocade/Foundry ServerIron 450
+ - M7 and JetCore blades
+ - >= 12.2.01p
+ - Citrix Netscaler running 8.x, 9.x
+
+On the server, L3DSR is currently supported by:
+ - FreeBSD >= 6.x
+ - RHEL >= 5.x
+
+L3DSR was developed at Yahoo! Inc. If you have questions or comments,
+please contact Jan Schaumann <jschauma@yahoo-inc.com> or Carl Stanley
+<cstan@yahoo-inc.com>.
BIN docs/nanog51.pdf
Binary file not shown.
35 freebsd/CHANGES
@@ -0,0 +1,35 @@
+Version 1.0.9 (2011-02-17)
+ * fix version restriction introduced in 1.0.6 that made
+ this package fail on FreeBSD 6.x
+
+Version 1.0.8 (2010-11-09)
+ * move unload-busy test to a point where we know the module was actually
+ loaded
+
+Version 1.0.7 (2010-11-08)
+ * prevent unloading of the kernel module if any vips are
+ configured
+
+Version 1.0.6 (2010-10-05):
+ * make this package available for FreeBSD7 by making it os
+ version independent and bailing out in the install script if the major
+ version is too low
+
+Version 1.0.5
+ * Bug 3149934
+
+Version 1.0.4
+ * Build in a temporary directory to avoid confusing yinst or
+ leaving stale files.
+
+Version 1.0.3
+ * Guess again at bugzilla component specification
+
+Version 1.0.2
+ * Bugzilla component
+
+Version 1.0.1
+ * Cosmetic packaging tweaks
+
+Version 1.0.0
+ * Initial release
29 freebsd/LICENSE
@@ -0,0 +1,29 @@
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5 freebsd/README
@@ -0,0 +1,5 @@
+The software in this directory comprises a very simple packet filter that
+is able to rewrite the source address of IP packets by using the DSCP/TOS
+field as an index into a configurable sysctl table.
+
+It is licensed under a 3-clause BSD license.
120 freebsd/dscp_rewrite-install
@@ -0,0 +1,120 @@
+#!/usr/local/bin/perl -w
+#
+# Copyright (c) 2008,2009,2010,2011 Yahoo! Inc. All rights reserved.
+#
+# Originally written by John Baldwin in July 2008.
+
+# Redistribution and use of this software in source and binary forms,
+# with or without modification, are permitted provided that the following
+# conditions are met:
+#
+# * Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the
+# following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the
+# following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# * Neither the name of Yahoo! Inc. nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior
+# written permission of Yahoo! Inc.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+$PROG = "dscp_rewrite-install";
+if (@ARGV != 2) {
+ error_exit("Usage: $PROG <operation> <srcdir>");
+}
+my $os = `uname`;
+my $osmaj = `uname -r`;
+chomp($os,$osmaj);
+$os = lc($os);
+$osmaj =~ s/[^\d].*//;
+my($op,$srcdir) = @ARGV;
+$MOD = "dscp_rewrite";
+if ($os eq "freebsd") {
+ if ($osmaj < 6) {
+ error_exit("Unsupported FreeBSD Version: $osmaj");
+ }
+ my $KERNEL = `/sbin/sysctl -n kern.bootfile`;
+ chomp($KERNEL);
+ $KERNEL_SOURCE = "/usr/src/sys";
+ $KERNEL_SOURCE_FILE = "$KERNEL_SOURCE/Makefile";
+ $MODF = "$MOD.ko";
+ $MODDIR = '';
+ my $modpath = `/sbin/sysctl -n kern.module_path`;
+ chomp($modpath);
+ for (split(/;/,$modpath)) {
+ if (/\/modules\/?$/) {
+ $MODDIR = $_;
+ last;
+ }
+ }
+ if (!-d $MODDIR) {
+ error_exit("Cannot locate modules directory");
+ }
+ $LOAD="/sbin/kldload $MODDIR/$MODF";
+ $STAT="/sbin/kldstat -n $MOD";
+ $UNLOAD="/sbin/kldunload -n $MOD";
+ $MAKEFILE = "-f Makefile";
+} else {
+ error_exit("Unsupported OS: $os");
+}
+if ($op eq "DEACTIVATE") {
+ unlink("$MODDIR/$MODF");
+} elsif ($op eq "START") {
+ system("$STAT");
+ if ($?) {
+ if (!-f $KERNEL_SOURCE_FILE) {
+ error_exit("Cannot locate kernel source tree");
+ }
+ print "$PROG: Compiling kernel module ($MOD) ...\n";
+ my $WRK=`mktemp -d -q /tmp/$MOD.XXXXXX`;
+ chomp($WRK);
+ if ($?) {
+ error_exit("Cannot make a compile directory");
+ }
+ system("mkdir -p $MODDIR");
+ !$? || exit(1);
+ system("cp -p $srcdir/Makefile $srcdir/dscp_rewrite.c $WRK");
+ !$? || exit(1);
+ system("(cd $WRK && /usr/bin/make $MAKEFILE -s clean && /usr/bin/make $MAKEFILE -s all)");
+ !$? || exit(1);
+ system("/bin/cp -p $WRK/$MODF $MODDIR");
+ !$? || error_exit("Unable to copy kernel module to $MODDIR");
+ system("/bin/rm -rf $WRK");
+ !$? || error_exit("Unable to delete temporary directory $WRK");
+ print "$PROG: Loading kernel module ...\n";
+ system("$LOAD");
+ !$? || error_exit("Unable to load kernel module");
+ }
+} elsif ($op eq "STOP") {
+ system("$STAT");
+ if (!$?) {
+ print "$PROG: Unloading kernel module ...\n";
+ system("$UNLOAD");
+ if ($?) {
+ print "$PROG: Unable to unload $MOD kernel module.\n";
+ }
+ }
+}
+
+
+sub error_exit {
+ print "$PROG: $_[0]\n";
+ exit(1);
+}
5 freebsd/kmod/Makefile
@@ -0,0 +1,5 @@
+
+KMOD= dscp_rewrite
+SRCS= dscp_rewrite.c
+
+.include <bsd.kmod.mk>
280 freebsd/kmod/dscp_rewrite.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2008,2009,2010,2011 Yahoo! Inc. All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$Id: dscp_rewrite.c 17 2011-03-07 21:51:09Z jans $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/pfil.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+
+SYSCTL_NODE(_net_inet_ip, OID_AUTO, dscp_rewrite, CTLFLAG_RD, NULL,
+ "DSCP rewrite source IP addresses");
+
+static int dscp_rewrite_enabled = 1;
+SYSCTL_INT(_net_inet_ip_dscp_rewrite, OID_AUTO, enabled, CTLFLAG_RW,
+ &dscp_rewrite_enabled, 0, "DSCP rewrite enabled");
+
+static struct in_addr rewrite_addresses[64];
+
+static int
+inet_aton(const char *cp, struct in_addr *addr)
+{
+ u_long octets[4];
+ const char *c;
+ char *end;
+ int i;
+
+ i = 0;
+ c = cp;
+ for (;;) {
+ octets[i] = strtoul(c, &end, 10);
+ if (c == end)
+ /* Unable to parse an octet. */
+ return (EINVAL);
+
+ /* Parsed the whole string? */
+ if (*end == '\0')
+ break;
+
+ /* Next octet? */
+ if (*end == '.') {
+ if (i == 3)
+ /* Too many octets. */
+ return (EINVAL);
+ c = end + 1;
+ i++;
+ } else
+ /* Invalid character. */
+ return (EINVAL);
+ }
+
+ if (i != 3)
+ /* Not enough octets. */
+ return (EINVAL);
+
+ /* Range-check all the octets. */
+ for (i = 0; i < 4; i++)
+ if (octets[i] > 0xff)
+ return (EINVAL);
+
+ addr->s_addr = htonl(octets[0] << 24 | octets[1] << 16 |
+ octets[2] << 8 | octets[3]);
+ return (0);
+}
+
+static int
+rewrite_sysctl_handler(SYSCTL_HANDLER_ARGS)
+{
+ char buf[24];
+ int error;
+
+ inet_ntoa_r(rewrite_addresses[arg2], buf);
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error)
+ return (error);
+ error = inet_aton(buf, &rewrite_addresses[arg2]);
+ return (error);
+}
+
+#define DSCP_SYSCTL(index) \
+ SYSCTL_PROC(_net_inet_ip_dscp_rewrite, (index), index, \
+ CTLTYPE_STRING | CTLFLAG_RW, NULL, (index), \
+ rewrite_sysctl_handler, "A", "DSCP " #index " source IP")
+
+DSCP_SYSCTL(1);
+DSCP_SYSCTL(2);
+DSCP_SYSCTL(3);
+DSCP_SYSCTL(4);
+DSCP_SYSCTL(5);
+DSCP_SYSCTL(6);
+DSCP_SYSCTL(7);
+DSCP_SYSCTL(8);
+DSCP_SYSCTL(9);
+DSCP_SYSCTL(10);
+DSCP_SYSCTL(11);
+DSCP_SYSCTL(12);
+DSCP_SYSCTL(13);
+DSCP_SYSCTL(14);
+DSCP_SYSCTL(15);
+DSCP_SYSCTL(16);
+DSCP_SYSCTL(17);
+DSCP_SYSCTL(18);
+DSCP_SYSCTL(19);
+DSCP_SYSCTL(20);
+DSCP_SYSCTL(21);
+DSCP_SYSCTL(22);
+DSCP_SYSCTL(23);
+DSCP_SYSCTL(24);
+DSCP_SYSCTL(25);
+DSCP_SYSCTL(26);
+DSCP_SYSCTL(27);
+DSCP_SYSCTL(28);
+DSCP_SYSCTL(29);
+DSCP_SYSCTL(30);
+DSCP_SYSCTL(31);
+DSCP_SYSCTL(32);
+DSCP_SYSCTL(33);
+DSCP_SYSCTL(34);
+DSCP_SYSCTL(35);
+DSCP_SYSCTL(36);
+DSCP_SYSCTL(37);
+DSCP_SYSCTL(38);
+DSCP_SYSCTL(39);
+DSCP_SYSCTL(40);
+DSCP_SYSCTL(41);
+DSCP_SYSCTL(42);
+DSCP_SYSCTL(43);
+DSCP_SYSCTL(44);
+DSCP_SYSCTL(45);
+DSCP_SYSCTL(46);
+DSCP_SYSCTL(47);
+DSCP_SYSCTL(48);
+DSCP_SYSCTL(49);
+DSCP_SYSCTL(50);
+DSCP_SYSCTL(51);
+DSCP_SYSCTL(52);
+DSCP_SYSCTL(53);
+DSCP_SYSCTL(54);
+DSCP_SYSCTL(55);
+DSCP_SYSCTL(56);
+DSCP_SYSCTL(57);
+DSCP_SYSCTL(58);
+DSCP_SYSCTL(59);
+DSCP_SYSCTL(60);
+DSCP_SYSCTL(61);
+DSCP_SYSCTL(62);
+DSCP_SYSCTL(63);
+
+static int
+dscp_rewrite_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
+ struct inpcb *inp)
+{
+ struct mbuf *m;
+ struct ip *ip;
+ int i;
+
+ KASSERT(dir == PFIL_IN, ("dscp_rewrite_in wrong direction!"));
+
+ if (!dscp_rewrite_enabled)
+ return (0);
+
+ m = *m0;
+
+ /*
+ * Find the IP header. Note that we assume that the full
+ * header is in the first mbuf since ip_input() would have
+ * already done an m_pullup() to that effect.
+ */
+ ip = mtod(m, struct ip *);
+
+ /* Extract DSCP field to get index into table;
+ * DSCP is the first 6 bits of the 8 bit TOS field. */
+ i = ip->ip_tos >> 2;
+
+ /* DSCP 0 is always passed through untouched. */
+ if (i == 0)
+ return (0);
+
+ /* If the destination IP for this index is 0, then bail. */
+ if (rewrite_addresses[i].s_addr == 0)
+ return (0);
+
+ ip->ip_dst = rewrite_addresses[i];
+
+ /* XXX: Clear DSCP? */
+
+ /*
+ * This intentionally does not update the checksum.
+ * ip_input() has already checked the checksum by the time the
+ * pfil hooks are run, and we are not sending this packet back
+ * down the stack, but up.
+ */
+ return (0);
+}
+
+static int
+dscp_rewrite_modevent(module_t mod, int type, void *arg)
+{
+ int i;
+ struct pfil_head *pfh_inet;
+
+ switch (type) {
+ case MOD_LOAD:
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return (ENOENT);
+ pfil_add_hook(dscp_rewrite_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet);
+ break;
+ case MOD_UNLOAD:
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return (ENOENT);
+ for (i=0;i<64;i++) {
+ if (rewrite_addresses[i].s_addr != 0)
+ return (EBUSY);
+ }
+ pfil_remove_hook(dscp_rewrite_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet);
+ break;
+ case MOD_QUIESCE:
+ break;
+ default:
+ return (EOPNOTSUPP);
+ }
+ return (0);
+}
+
+static moduledata_t dscp_rewrite_mod = {
+ "dscp_rewrite",
+ dscp_rewrite_modevent,
+ 0,
+};
+
+DECLARE_MODULE(dscp_rewrite, dscp_rewrite_mod, SI_SUB_PROTO_IFATTACHDOMAIN,
+ SI_ORDER_ANY);
+MODULE_VERSION(dscp_rewrite, 1);
339 linux/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
97 linux/Makefile
@@ -0,0 +1,97 @@
+.PHONY: userdefault all install clean distclean tar srpm rpm
+
+PACKAGE = iptables-daddr
+VERSION = 0.2.1
+RELEASE = 20110121
+DIST = .el5
+PKGNAME = $(PACKAGE)-$(VERSION)-$(RELEASE)$(DIST)
+MACHINE := $(shell uname -m)
+PWD := $(shell pwd)
+
+RPMBUILD = rpmbuild --define '_topdir $(topdir)'
+SUBDIRS = extensions kmod
+
+define nl
+
+
+endef
+
+ifeq ($(topdir),)
+topdir := $(PWD)/TOPDIR
+endif
+
+ifeq ($(prefix),)
+prefix := $(PWD)/BUILDROOT
+endif
+
+ifneq ($(shell date '+%Y%m%d'),$(RELEASE))
+$(warning WARNING: Today's date does not match the release date!)
+endif
+
+
+include $(addsuffix /Makefile.incl,$(SUBDIRS))
+
+srcfiles += \
+ README \
+ Makefile \
+ iptables-daddr.spec.sed
+
+specfile = $(PACKAGE).spec
+tarprefix = $(PKGNAME)
+tarfiles = $(srcfiles)
+
+tdbuilddirs = $(addprefix $(topdir)/,BUILD RPMS SPECS SRPMS SOURCES)
+tdtarfile = $(topdir)/SOURCES/$(PKGNAME).tar.bz2
+tdspecfile = $(topdir)/SPECS/$(specfile)
+tdrpmfile = $(topdir)/RPMS/$(MACHINE)/$(PKGNAME).$(MACHINE).rpm
+tdsrpmfile = $(topdir)/SRPMS/$(PKGNAME).src.rpm
+
+clean_targets = $(tarprefix)
+distclean_targets = $(clean_targets) $(prefix) $(topdir)
+
+userdefault: srpm rpm
+
+all install clean distclean::
+ $(foreach dir,$(SUBDIRS),$(MAKE) -C '$(dir)' prefix='$(prefix)' $@$(nl))
+
+clean distclean::
+ $(foreach file,\
+ $(filter $(wildcard $($(@)_targets)),$($(@)_targets)),\
+ rm -rf -- '$(file)'\
+ $(nl)\
+ )
+
+
+tar: $(tdtarfile)
+srpm: $(tdsrpmfile)
+rpm: $(tdrpmfile)
+
+$(tdspecfile): $(specfile).sed
+ rm -f -- '$@'
+ @[ -d '$(@D)' ] || mkdir -p -- '$(@D)'
+ sed \
+ -e 's/__PACKAGE__/$(PACKAGE)/g' \
+ -e 's/__VERSION__/$(VERSION)/g' \
+ -e 's/__RELEASE__/$(RELEASE)$(DIST)/g' \
+ '$<' > '$@' || rm -f -- '$@'
+ chmod -w -- '$@'
+
+$(tdtarfile): $(tarfiles)
+ @[ -d '$(@D)' ] || mkdir -p -- '$(@D)'
+ @[ -h '$(tarprefix)' ] || ln -s -- . '$(tarprefix)'
+ tar -cjhf '$@' --exclude .svn $(addprefix $(tarprefix)/,$^)
+ @rm -f '$(tarprefix)'
+
+$(tdrpmfile): $(tdspecfile) $(tdtarfile)
+ $(foreach dir,\
+ $(filter-out $(wildcard $(tdbuilddirs)),$(tdbuilddirs)),\
+ mkdir -p -- '$(dir)'$(nl)\
+ )
+ $(RPMBUILD) -bb $(tdspecfile)
+
+$(tdsrpmfile): $(tdspecfile) $(tdtarfile)
+ $(foreach dir,\
+ $(filter-out $(wildcard $(tdbuilddirs)),$(tdbuilddirs)),\
+ mkdir -p -- '$(dir)'$(nl)\
+ )
+ $(RPMBUILD) -bs $(tdspecfile)
8 linux/README
@@ -0,0 +1,8 @@
+This package supplies an Iptables module that allows rewriting of
+the destination IP address.
+
+This version will only build on RHEL5 (and maybe later).
+
+A sample invocation using the DADDR iptables module:
+# ifconfig eth0:1 10.74.92.26 netmask 255.255.255.255
+# iptables -t mangle -A INPUT -m dscp --dscp 1 -j DADDR --set-daddr=10.74.92.26
57 linux/extensions/Makefile
@@ -0,0 +1,57 @@
+.PHONY: all install clean distclean
+
+MACHINE := $(shell uname -m)
+
+define nl
+
+
+endef
+
+CFLAGS = -O2 -g
+
+ifeq ($(MACHINE),x86_64)
+LIBDIR = lib64
+else
+LIBDIR = lib
+endif
+
+ipt_libdir = $(LIBDIR)/iptables
+
+INSTDIR = $(prefix)/$(ipt_libdir)
+
+iptplugin = libipt_DADDR.so
+
+instiptplugin = $(addprefix $(INSTDIR)/,$(iptplugin))
+
+all_targets = $(iptplugin)
+install_targets = $(instiptplugin)
+clean_targets = $(all_targets)
+distclean_targets = $(clean_targets)
+
+all: $(all_targets)
+
+install: $(install_targets)
+
+clean distclean:
+ $(foreach file,\
+ $(filter $(wildcard $($(@)_targets)),$($(@)_targets)),\
+ rm -rf -- '$(file)'\
+ $(nl)\
+ )
+
+lib%.so: lib%.o
+ $(CC) -shared -o $@ $^
+
+# If building in 32-bit mode on a 64-bit kernel, need
+# -DIPT_MIN_ALIGN=8 -DKERNEL_64_USERSPACE_32
+lib%.o: lib%.c %.h
+ $(CC) $(CFLAGS) \
+ -Wall -Wunused \
+ -DIPTABLES_VERSION=\"1.3.5\" \
+ -fPIC -c $<
+
+$(instiptplugin): $(iptplugin)
+
+$(prefix)/%:
+ @[ -d '$(@D)' ] || mkdir -p -- '$(@D)'
+ cp -fp -- '$<' '$@'
6 linux/extensions/Makefile.incl
@@ -0,0 +1,6 @@
+srcfiles += \
+ extensions/README \
+ extensions/Makefile \
+ extensions/Makefile.incl \
+ extensions/ipt_DADDR.h \
+ extensions/libipt_DADDR.c
2 linux/extensions/README
@@ -0,0 +1,2 @@
+The header files under the "include" directory were copied from the
+source for the "iptables-1.3.5" package.
8 linux/extensions/ipt_DADDR.h
@@ -0,0 +1,8 @@
+#ifndef _IPT_DADDR_H_target
+#define _IPT_DADDR_H_target
+
+struct ipt_daddr_target_info {
+ u_int32_t daddr;
+};
+
+#endif /* _IPT_DADDR_H_target */
154 linux/extensions/libipt_DADDR.c
@@ -0,0 +1,154 @@
+/* Shared library add-on to iptables to add DADDR target support. */
+
+/*
+ * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL), version 2 only.
+ * This software s distributed WITHOUT ANY WARRANTY, whether express or
+ * implied. See the GNU GPL for more details:
+ * (http://www.gnu.org/licenses/gpl.html)
+ *
+ * Originally written by Quentin Barnes <qbarnes@yahoo-inc.com
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <limits.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#include <iptables.h>
+#include "ipt_DADDR.h"
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+ "DADDR target v%s options:\n"
+ " --set-daddr <ipaddr>\n"
+ " Address to set for destination.\n",
+ IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+ { "set-daddr", 1, 0, '1' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+}
+
+static void
+parse_daddr(const char *s, struct ipt_daddr_target_info *info)
+{
+ struct in_addr *ip;
+
+ /* dotted_to_addr() is not multi-thread safe, but no need to free. */
+ ip = dotted_to_addr(s);
+ if (!ip)
+ exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", s);
+
+ info->daddr = ip->s_addr;
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_daddr_target_info *daddrinfo
+ = (struct ipt_daddr_target_info *)(*target)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags)
+ exit_error(PARAMETER_PROBLEM,
+ "DADDR target: Cant specify --set-daddr twice");
+ parse_daddr(optarg, daddrinfo);
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "DADDR target: Parameter --set-daddr is required");
+}
+
+static void
+print_daddr(u_int32_t daddr)
+{
+ int i;
+ unsigned char *p = (unsigned char *)&daddr;
+
+ for (i = 0 ; i < sizeof(daddr) ; ++i)
+ printf("%d%s", p[i], (i<3)?".":"");
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ const struct ipt_daddr_target_info *daddrinfo =
+ (const struct ipt_daddr_target_info *)target->data;
+ printf("DADDR set ");
+ print_daddr(daddrinfo->daddr);
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ const struct ipt_daddr_target_info *daddrinfo =
+ (const struct ipt_daddr_target_info *)target->data;
+
+ printf("--set-daddr ");
+ print_daddr(daddrinfo->daddr);
+}
+
+static struct iptables_target daddr = {
+ .next = NULL,
+ .name = "DADDR",
+ .version = IPTABLES_VERSION,
+ .size = IPT_ALIGN(sizeof(struct ipt_daddr_target_info)),
+ .userspacesize = IPT_ALIGN(sizeof(struct ipt_daddr_target_info)),
+ .help = &help,
+ .init = &init,
+ .parse = &parse,
+ .final_check = &final_check,
+ .print = &print,
+ .save = &save,
+ .extra_opts = opts
+};
+
+void constructor(void) __attribute__ ((constructor));
+
+void constructor(void)
+{
+ register_target(&daddr);
+}
86 linux/iptables-daddr.spec.sed
@@ -0,0 +1,86 @@
+Summary: Iptables destination address rewriting
+Name: __PACKAGE__
+Version: __VERSION__
+Release: __RELEASE__
+License: GPLv2
+Group: Applications/System
+URL: to-be-filled-in
+Vendor: Yahoo! Inc.
+Packager: Quentin Barnes <qbarnes@yahoo-inc.com>
+
+%define _prefix %{nil}
+%define rpmversion %{version}-%{release}
+%define fullpkgname %{name}-%{rpmversion}
+
+BuildRoot: %{_tmppath}/%{fullpkgname}-root
+BuildRequires: kernel, kernel-devel, iptables >= 1.3.5, iptables < 1.4
+BuildRequires: iptables-devel >= 1.3.5-5.3
+Requires: iptables >= 1.3.5, iptables < 1.4
+
+Source: %{fullpkgname}.tar.bz2
+
+%description
+This kernel module and iptables plugin enable IP destination address
+rewriting using iptables rules.
+
+For information, see: to-be-filled-in
+
+%prep
+%setup -q -n %{fullpkgname}
+
+%build
+%__make all
+
+%install
+%__rm -rf -- %{buildroot}
+%makeinstall
+
+%clean
+%__rm -rf -- %{buildroot}
+
+%preun
+if [ "$1" -eq 0 ]
+then
+ rmmod '__PACKAGE__' 2> /dev/null || true
+ if %__grep -qw '^__PACKAGE__' /proc/modules
+ then
+ echo >&2 "Failed to rmmod '__PACKAGE__'."
+ echo >&2 "Remove iptables rules using DADDR and try again."
+ exit 1
+ fi
+fi
+
+%files
+%defattr(-, root, root)
+/lib*/iptables/libipt_DADDR.so
+/lib/modules/yahoo/__PACKAGE__/Install
+%defattr(0744, root, root)
+/lib/modules/yahoo/__PACKAGE__/*/ipt_DADDR.ko
+%defattr(-, root, root, -)
+%dir /
+%dir /lib*
+%dir /lib*/iptables
+%dir /lib/modules
+%dir /lib/modules/yahoo
+%defattr(-, root, root, 0755)
+%dir /lib/modules/yahoo/__PACKAGE__
+%dir /lib/modules/yahoo/__PACKAGE__/2.6.*
+
+%changelog
+* Sat Jan 15 2011 Quentin Barnes <qbarnes@yahoo-inc.com> 0.2.1-20110121
+- Add xen kernel support. [BZ #4237848]
+- Fix theoretical packaging dependency and some more "rpm -U ..." problems.
+- Can remove libiptc headers since now included in later iptables-devel RPMs.
+
+* Fri Oct 1 2010 Quentin Barnes <qbarnes@yahoo-inc.com> 0.2.0-20101001
+- Fix function argument problem that caused address to be changed incorrectly. [#4032170]
+- Fix problem when running "rpm -U ..." on package.
+
+* Fri Aug 6 2010 Quentin Barnes <qbarnes@yahoo-inc.com> 0.2.0-20100806
+- Update to use the new statically configuring ylkmmgr 0.2.0.
+
+* Sun Jul 12 2009 Quentin Barnes <qbarnes@yahoo-inc.com> 0.1.1-20090712
+- Update for RHEL5.
+
+* Mon Sep 11 2008 Quentin Barnes <qbarnes@yahoo-inc.com> 0.1-20080911
+- Initial release
3 linux/kmod/Install.sed
@@ -0,0 +1,3 @@
+prefix=__PREFIX__
+
+ipt_DADDR.ko 2.6.18 2.6.18
94 linux/kmod/Makefile
@@ -0,0 +1,94 @@
+# Give "N=1" argument to make if you want a native-only build.
+
+.PHONY: all install distclean mkfiles hdrfiles cfiles kofiles installfile \
+ instkofiles instinstallfile clean modules_install modules
+
+define nl
+
+
+endef
+
+PACKAGE = iptables-daddr
+MACHINE := $(shell uname -m)
+PWD := $(shell pwd)
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+ARCH ?= $(SUBARCH)
+KERNBASE = 2.6.18-53.el5
+
+INSTDIR = $(prefix)/lib/modules/yahoo/$(PACKAGE)
+
+ifeq ($(SUBARCH),i386)
+extrakver = PAE
+else
+extrakver =
+endif
+
+ifdef N
+ ifeq ("$(origin N)", "command line")
+ subdirs := $(shell uname -r)
+ endif
+else
+ subdirs = $(KERNBASE) $(addprefix $(KERNBASE), $(extrakver))
+endif
+
+installfile = Install
+kofiles = $(addsuffix /ipt_DADDR.ko,$(subdirs))
+
+mkfiles = $(addsuffix /Makefile,$(subdirs))
+hdrfiles = $(addsuffix /ipt_DADDR.h,$(subdirs))
+cfiles = $(addsuffix /ipt_DADDR.c,$(subdirs))
+
+instkofiles = $(addprefix $(INSTDIR)/,$(kofiles))
+instinstallfile = $(INSTDIR)/$(installfile)
+
+all_targets = $(kofiles) $(installfile)
+install_targets = $(instkofiles) $(instinstallfile)
+clean_targets = $(all_targets)
+distclean_targets = $(clean_targets) $(subdirs)
+
+all: $(all_targets)
+
+install: $(install_targets)
+
+clean distclean::
+ $(foreach file,\
+ $(filter $(wildcard $($(@)_targets)),$($(@)_targets)),\
+ rm -rf -- '$(file)'\
+ $(nl)\
+ )
+
+clean::
+ $(foreach mkfile,\
+ $(wildcard $(addsuffix /Makefile,$(subdirs))),\
+ $(MAKE) -C '/lib/modules/$(dir mkfile)/build' M='$(PWD)/$(dir mkfile)' $@\
+ $(nl)\
+ )
+
+$(mkfiles): Makefile.kmod
+ @[ -d '$(@D)' ] || mkdir -p -- '$(@D)'
+ ln -s -- '../$<' '$@'
+
+$(hdrfiles): ipt_DADDR.h
+ @[ -d '$(@D)' ] || mkdir -p -- '$(@D)'
+ ln -s -- '../$<' '$@'
+
+$(cfiles): ipt_DADDR.c
+ @[ -d '$(@D)' ] || mkdir -p -- '$(@D)'
+ ln -s -- '../$<' '$@'
+
+%/ipt_DADDR.ko: %/Makefile %/ipt_DADDR.h %/ipt_DADDR.c
+ @echo '$@' '$*' '$<'
+ $(MAKE) -C '/lib/modules/$(notdir $(@D))/build' M='$(PWD)/$(notdir $(@D))'
+
+$(INSTDIR)/%: %
+ @[ -d '$(@D)' ] || mkdir -p -- '$(@D)'
+ cp -fp -- '$<' '$@'
+
+%: %.sed
+ rm -f -- '$@'
+ sed \
+ -e 's:__PREFIX__:$(PACKAGE)/$(KERNBASE):g' \
+ '$<' > '$@' || rm -f -- '$@'
+ chmod -w -- '$@'
+
+.PRECIOUS: $(hdrfiles) $(cfiles) $(mkfiles)
7 linux/kmod/Makefile.incl
@@ -0,0 +1,7 @@
+srcfiles += \
+ kmod/Makefile \
+ kmod/Makefile.incl \
+ kmod/Makefile.kmod \
+ kmod/Install.sed \
+ kmod/ipt_DADDR.h \
+ kmod/ipt_DADDR.c
1 linux/kmod/Makefile.kmod
@@ -0,0 +1 @@
+obj-m += ipt_DADDR.o
75 linux/kmod/ipt_DADDR.c
@@ -0,0 +1,75 @@
+/* This module is used for setting the destination IP field of a packet. */
+
+/*
+ * Copyright (c) 2011 Yahoo! Inc. All rights reserved.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL), version 2 only.
+ * This software s distributed WITHOUT ANY WARRANTY, whether express or
+ * implied. See the GNU GPL for more details:
+ * (http://www.gnu.org/licenses/gpl.html)
+ *
+ * Originally written by Quentin Barnes <qbarnes@yahoo-inc.com
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include "ipt_DADDR.h"
+
+MODULE_LICENSE("GPLv2");
+MODULE_AUTHOR("Yahoo! Inc. <linux-kernel@yahoo-inc.com>");
+MODULE_DESCRIPTION("iptables DADDR mangling module");
+
+static unsigned int
+target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const void *targinfo,
+ void *userinfo)
+{
+ const struct ipt_daddr_target_info *daddrinfo = targinfo;
+
+ if (((*pskb)->nh.iph->daddr) != daddrinfo->daddr) {
+ u_int32_t diffs[2];
+
+ if (!skb_make_writable(pskb, sizeof(struct iphdr)))
+ return NF_DROP;
+
+ diffs[0] = ~htonl((*pskb)->nh.iph->daddr);
+ (*pskb)->nh.iph->daddr = daddrinfo->daddr;
+ diffs[1] = htonl((*pskb)->nh.iph->daddr);
+ (*pskb)->nh.iph->check
+ = csum_fold(csum_partial((char *)diffs,
+ sizeof(diffs),
+ (*pskb)->nh.iph->check
+ ^0xFFFF));
+ }
+ return IPT_CONTINUE;
+}
+
+static struct ipt_target ipt_daddr_reg = {
+ .name = "DADDR",
+ .target = target,
+ .targetsize = sizeof(struct ipt_daddr_target_info),
+ .table = "mangle",
+ .me = THIS_MODULE,
+};
+
+static int __init ipt_daddr_init(void)
+{
+ return ipt_register_target(&ipt_daddr_reg);
+}
+
+static void __exit ipt_daddr_fini(void)
+{
+ ipt_unregister_target(&ipt_daddr_reg);
+}
+
+module_init(ipt_daddr_init);
+module_exit(ipt_daddr_fini);
8 linux/kmod/ipt_DADDR.h
@@ -0,0 +1,8 @@
+#ifndef _IPT_DADDR_H_target
+#define _IPT_DADDR_H_target
+
+struct ipt_daddr_target_info {
+ u_int32_t daddr;
+};
+
+#endif /* _IPT_DADDR_H_target */
47 yvipagent/CHANGES
@@ -0,0 +1,47 @@
+
+Version 1.2 (2010-11-08)
+ * on FreeBSD, also explicitly set the dscp_rewrite.enabled
+ sysctl to zero
+
+Version 1.1 (2010-11-07)
+ * properly strip trailing whitespace (also fixed
+ commentary handling)
+ * print affirmative reassuring comments on successful exit
+ * really make 'ip' mandatory in the yvip.conf files
+ * add an example to yvip.conf.5
+
+Version 1.0 (2010-10-05)
+ * add support for RHEL5 by installing RPMs we depend on
+ via yum in post-activation and explicitly conflicting with what used to
+ be our yinst dependencies
+
+Version 0.6.1 (2010-01-18)
+ * tiny version bump to fix dist_install fubar
+
+Version 0.6 (2010-01-18)
+ * include DSCP bit in verbose output
+ * ensure yvipagent bails out appropriately if an already
+ configured vip is tried to be configured again
+
+Version 0.5 (2009-11-05)
+ * don't touch system config files, as we're run at yinst
+ start time anyway
+ * unconfigure all l3-dsr configs
+
+Version 0.4 (2009-10-30)
+ * install iptables rules into PREROUTING, not INPUT
+
+Version 0.3 (2009-10-27)
+ * more clearly document yvipagent's requirement of
+ exclusive control over vip management
+ * yvipagent shouldn't try to unload kernel modules
+ * ignore invalid ifcfg-file names
+ * only delete firewall rules that are actually installed
+
+Version 0.2 (2009-10-06)
+ * add "check" command
+ * exit successfully explicitly if all's peachy
+ * only process firewall files if they exist
+
+Version 0.1 (2009-09-29)
+ * Initial version
28 yvipagent/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2009,2010,2011 Yahoo! Inc. All rights reserved.
+
+Redistribution and use of this software in source and binary forms, with
+or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 yvipagent/Makefile
@@ -0,0 +1,42 @@
+# $Id: Makefile 467 2011-03-08 17:20:08Z jans $
+# $URL: svn+ssh://svn.corp.yahoo.com/yahoo/ops/yvip/agent/branches/l3dsr-open-source/Makefile $
+#
+# This Makefile is used to create a single tarball containig the various
+# bits and pieces that make up the server side code of our L3DSR
+# architecture. As such, it reacher over into a few other repositories;
+# the result is a tarball without any SVN information.
+
+TARBALL=l3dsr.tar.gz
+DOCDIR=${HOME}/dev/svn/yvip/doc
+LINUXDIR=${HOME}/dev/svn/packages/iptables-daddr/branches/l3dsr-open-source/iptables-daddr.el5
+FREEBSDDIR=${HOME}/dev/svn/dscp_rewrite/branches/l3dsr-open-source
+YVIPAGENTDIR=${HOME}/dev/svn/yvip/agent/branches/l3dsr-open-source
+
+all: ${TARBALL}
+
+${TARBALL}: doc-up freebsd-up linux-up yvipagent-up
+ ( cd .build && tar zcf ../${TARBALL} l3dsr )
+
+doc-up:
+ ( cd ${DOCDIR} && svn up )
+ mkdir -p .build/l3dsr/docs
+ cp ${DOCDIR}/README .build/l3dsr/README
+ cp ${DOCDIR}/nanog51/nanog51.pdf .build/l3dsr/docs/nanog51.pdf
+
+freebsd-up:
+ ( cd ${FREEBSDDIR} && svn up )
+ mkdir -p .build/l3dsr/freebsd
+ ( cd ${FREEBSDDIR} && pax -rw -s '/.*\.svn.*//' . ${YVIPAGENTDIR}/.build/l3dsr/freebsd/. )
+
+linux-up:
+ ( cd ${LINUXDIR} && svn up )
+ mkdir -p .build/l3dsr/linux
+ ( cd ${LINUXDIR} && pax -rw -s '/.*\.svn.*//' . ${YVIPAGENTDIR}/.build/l3dsr/linux/. )
+
+yvipagent-up:
+ ( cd ${YVIPAGENTDIR} && svn up )
+ mkdir -p .build/l3dsr/yvipagent
+ ( cd ${YVIPAGENTDIR} && pax -rw -s '/.*\.svn.*//' -s '/.*\.build.*//' . ${YVIPAGENTDIR}/.build/l3dsr/yvipagent/. )
+
+clean:
+ rm -fr .build ${TARBALL}
6 yvipagent/README
@@ -0,0 +1,6 @@
+This is the "yvipagent" tool. Install it on a host that participates in a
+Layer-3 DSR VIP. It provides a system startup service and command-line
+tool to configure the host for participation in one or more VIPs according
+to a flat configuration file.
+
+yvipagent is released under a 3-clause BSD license.
61 yvipagent/doc/yvip.conf.5
@@ -0,0 +1,61 @@
+.\" This manual page was originally written by Jan Schaumann
+.\" <jschauma@yahoo-inc.com> in September 2009.
+.Dd January 20, 2011
+.Dt YVIP 5
+.Os
+.Sh NAME
+.Nm yvip
+.Nd VIP configuration file
+.Sh DESRIPTION
+This manual page describes the configuration file syntax for files used by
+the
+.Ar /usr/local/etc/rc.d/yvip
+system startup script.
+These files are found under
+.Ar /usr/local/etc/yvip/vips
+and are by convention named after the VIP address.
+The contents of the configuration file specify the details of the VIP
+configuration.
+.Pp
+The syntax of these configuration files is as follows:
+.Bl -bullet -compact -offset indent
+.It
+empty lines are ignored
+.It
+anything including and following the '#' character is ignored
+.It
+all other content must be in the format
+.Ar key=value
+.It
+all unknown keys are ignored
+.It
+a key of
+.Ar ip
+indicating the VIP to be configured on this host;
+madatory
+.It
+a key of
+.Ar type
+indicating the type of the VIP;
+mandatory for all configurations;
+currently supported types: "L3-DSR"
+.It
+a key of
+.Ar dscp
+mapping to an integer indicating the Differentiated Services Codepoint;
+mandatory for vips of type "L3-DSR"
+.It
+any other content is a syntax error
+.El
+.Sh EXAMPLES
+The following example configures the IP address 69.147.125.65 using the
+DSCP value 41:
+.Bd -literal
+ip=69.147.125.65
+type=l3-dsr
+dscp=41
+.Ed
+.Pp
+Note that the
+.Ar key=value
+pairs are unquoted.
114 yvipagent/doc/yvipagent.8
@@ -0,0 +1,114 @@
+.\" This manual page was originally written by Jan Schaumann
+.\" <jschauma@yahoo-inc.com> in September 2009.
+.Dd January 21, 2011
+.Dt YVIPAGENT 8
+.Os
+.Sh NAME
+.Nm yvipagent
+.Nd configure a host for participation in one or more VIPs
+.Sh SYNOPSIS
+.Nm
+.Op Fl hv
+.Op Fl d Ar dir
+.Op Fl f Ar file
+check | start | stop
+.Sh DESRIPTION
+The
+.Nm
+tool configures a host for participation in one or more VIPs.
+It does this by parsing the VIP configuration files found in the directory
+specified via the
+.Fl d
+flag and installing the necessary firewall rules, loopback aliases, kernel
+modules etc.
+.Pp
+.Nm
+is normally run at system startup time (or manually) from
+.Ar /usr/local/etc/rc.d/yvip .
+.Pp
+.Nm
+will assume that it is solely responsible for all interactions of the
+given host in any kind of VIPs.
+That is, having manually configured loopback aliases, for example, is
+likely to lead to undefined behaviour.
+.Sh OPTIONS
+The following options are supported:
+.Bl -tag -width f_file_
+.It Fl d Ar dir
+Specify the directory in which to look for VIP configuration files.
+Conflicts with
+.Fl f .
+.It Fl f Ar file
+Only configure VIPs from the given VIP configuration file.
+Conflicts with
+.Fl d .
+.It Fl h
+Print a usage statement and exit.
+.It Fl v
+Be verbose. Can be specified multiple times.
+.El
+.Pp
+In addition,
+.Nm
+requires a mandatory argument
+.Ar check ,
+.Ar start
+or
+.Ar stop
+to be given.
+.Sh DETAILS
+The
+.Nm
+tool requires an argument indicating whether it is configuring or
+unconfiguring the host for a VIP.
+.Pp
+If invoked with the argument being
+.Ar check ,
+it will perform the following actions for each of the VIPs:
+.Bl -bullet -compact -offset indent
+.It
+ensure none of the VIPs have conflicting IP-DSCP pairs
+.It
+ensure none of the VIPs have an unsupported type
+.It
+ensure every VIP of type L3-DSR has a DSCP bit defined
+.It
+ensure very VIP uses a valid IP address
+.El
+.Pp
+If invoked with the argument being
+.Ar start ,
+it will perform the following actions for each of the VIPs:
+.Bl -bullet -compact -offset indent
+.It
+ensure VIP-related kernel modules are loaded (ie load if not already
+loaded)
+.It
+ensure needed firewall rules are installed (ie add if not present)
+.It
+ensure the loopback interface is persistently configured for the given vip
+.El
+.Pp
+If invoked with the argument being
+.Ar stop ,
+it will perform the following actions for each of the VIPs:
+.Bl -bullet -compact -offset indent
+.It
+persistently unconfigure the loopback interface for this VIP
+.It
+unload all firewall rules related to L3-DSR
+.El
+.Pp
+Please note that
+.Nm
+does not perform any kind of input validation on the configuration file
+besides syntax checking.
+.Sh SEE ALSO
+.Xr yvip.conf 5
+.Sh HISTORY
+The
+.Nm
+utility was originally written by
+.An Jan Schaumann
+.Aq jschauma@yahoo-inc.com
+in September 2009.
105 yvipagent/src/yvip.sh
@@ -0,0 +1,105 @@
+#! /bin/sh
+#
+# Copyright (c) 2009,2010,2011 Yahoo! Inc.
+#
+# Originally written by Jan Schaumann <jschauma@yahoo-inc.com> in September
+# 2009.
+#
+# This is an old-fashioned rc-style startup script to configure a host for
+# participation in any VIPs.
+#
+# Since this script may be used on various platforms, we can't take
+# advantage of all the neat rc(8) goodness that FreeBSD 6.x (and higher)
+# comes with, so we cobble the required functionality together ourselves.
+#
+#
+# Redistribution and use of this software in source and binary forms, with
+# or without modification, are permitted provided that the following
+# conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Yahoo! Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission of Yahoo! Inc.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+NAME="yvip"
+AGENT="/usr/local/libexec/yvipagent"
+CONFDIR="/usr/local/etc/yvip/vips"
+
+runOrDie() {
+ local arg=${1}
+
+ ${AGENT} -d ${CONFDIR} ${arg}
+ if [ $? -gt 0 ]; then
+ echo "failed!" >&2
+ exit 1;
+ fi
+ echo "done."
+}
+
+check() {
+ echo -n "Checking ${NAME} configurations... "
+ runOrDie check
+}
+
+start() {
+ echo -n "Starting ${NAME}... "
+
+ if [ ! -x "${AGENT}" ]; then
+ echo "Unable to execute ${AGENT}." >&2
+ exit 1;
+ fi
+
+ if [ ! -d "${CONFDIR}" ]; then
+ echo "Configuration file directory '${CONFDIR}' not found."
+ return
+ fi
+
+ runOrDie start
+}
+
+stop() {
+ echo -n "Stopping ${NAME}... "
+ runOrDie stop
+}
+
+usage() {
+ echo "Usage: $0 (check|start|stop|restart)"
+}
+
+case $1 in
+ check)
+ check
+ ;;
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ stop && start
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
779 yvipagent/src/yvipagent.pl
@@ -0,0 +1,779 @@
+#! /usr/local/bin/perl -Tw
+#
+# Copyright (c) 2009,2010,2011 Yahoo! Inc.
+#
+# Originally written by Jan Schaumann <jschauma@yahoo-inc.com> in September
+# 2009.
+#
+# This program configures a host for participation in one or more
+# VIPs. It does this by parsing the VIP configuration files found in the
+# directory specified via the -d flag and installing the necessary firewall
+# rules, loopback aliases, kernel modules etc.
+#
+#
+# Redistribution and use of this software in source and binary forms, with
+# or without modification, are permitted provided that the following
+# conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Yahoo! Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission of Yahoo! Inc.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use File::Basename;
+use Getopt::Long;
+Getopt::Long::Configure("bundling");
+use Socket;
+use Socket6;
+
+###
+### Constants
+###
+
+use constant TRUE => 1;
+use constant FALSE => 0;
+
+use constant EXIT_FAILURE => 1;
+use constant EXIT_SUCCESS => 0;
+
+use constant DEFAULT_DIR => "/usr/local/etc/yvip/vips";
+
+###
+### Globals
+###
+
+$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin';
+delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+my %OPTS;
+my $PROGNAME = basename($0);
+
+my %SUPPORTED_ACTIONS = ( "check" => 1,
+ "start" => 1,
+ "stop" => 1,
+ );
+
+my %SUPPORTED_OS = ( "freebsd" => 1,
+ "linux" => 1,
+ );
+
+my %SUPPORTED_TYPES = ( "l3-dsr" => 1 );
+
+my %OS_DETAILS = (
+ "freebsd" => {
+ "kernel_modules" => "dscp_rewrite",
+ "kernel_module_test" => "/sbin/kldstat -q -m <mod>",
+ "kernel_module_load" => "/sbin/kldload <mod>",
+ "loopback_start" => "/sbin/ifconfig lo0 <vip>",
+ "loopback_stop" => "/sbin/ifconfig lo0 <vip> delete",
+ "firewall_rule" => "net.inet.ip.dscp_rewrite.<dscp>=<vip>",
+ "firewall_config_check" => "/sbin/sysctl net.inet.ip.dscp_rewrite.<dscp>",
+ "firewall_config_start" => "/sbin/sysctl <rule>",
+ "firewall_config_stop" => "/sbin/sysctl <rule>",
+ },
+ "linux" => {
+ "kernel_modules" => "ipt_dscp ipt_DADDR ",
+ "kernel_module_test" => "/bin/grep -q ^<mod> /proc/modules",
+ "kernel_module_load" => "/sbin/modprobe <mod>",
+ "loopback_start" => "/sbin/ifconfig lo",
+ "loopback_stop" => "/sbin/ifconfig lo:<alias> down",
+ "firewall_rule" => "-m dscp --dscp <dscp> -j DADDR --set-daddr=<vip>",
+ "firewall_config_check" => "/sbin/iptables -t mangle -L -n",
+ "firewall_config_start" => "/sbin/iptables -t mangle -A PREROUTING <rule>",
+ "firewall_config_stop" => "/sbin/iptables -t mangle -D PREROUTING <rule>",
+ },
+ );
+
+###
+### Subroutines
+###
+
+# function : configureFirewall
+# purpose : configure any firewall rules applicable for this VIP
+# inputs : a vip ip, a dscp bit
+# returns : nothing, may die on error
+
+sub configureFirewall($$) {
+ my ($vip, $dscp) = @_;
+
+ if ($OPTS{'ACTION'} eq "start") {
+ configureFirewallStart($OPTS{'OS'}, $vip, $dscp);
+ } elsif ($OPTS{'ACTION'} eq "stop") {
+ configureFirewallStop($OPTS{'OS'});
+ }
+}
+
+
+# function : configureFirewallStart
+# purpose : configure any firewall rules applicable for this VIP
+# and start them
+# inputs : os type, a vip ip, a dscp bit
+# returns : nothing, may die on error
+
+sub configureFirewallStart($$$) {
+ my ($os, $vip, $dscp) = @_;
+
+ my ($check, $cmd, $exists, $rule);
+
+ verbose("Adding firewall rules...", 3);
+
+ $check = $OS_DETAILS{$os}{'firewall_config_check'};
+ $check =~ s/<dscp>/$dscp/g;
+ $exists = `$check`;
+ if ($exists =~ m/$vip\n/) {
+ error("This host is already configured for $vip", EXIT_FAILURE);
+ # NOTREACHED
+ }
+
+ $cmd = $OS_DETAILS{$os}{'firewall_config_start'};
+ $rule = $OS_DETAILS{$os}{'firewall_rule'};
+ $rule =~ s/<dscp>/$dscp/g;
+ $rule =~ s/<vip>/$vip/g;
+ $cmd =~ s/<rule>/$rule/g;
+ runCommandOrDie($cmd);
+}
+
+# function : configureFirewallStop
+# purpose : unconfigure all L3-DSR firewall rules
+# inputs : os type
+# returns : nothing, may die on error
+
+sub configureFirewallStop($) {
+ my ($os) = @_;
+
+ verbose("Removing firewall rules...", 3);
+
+ if ($OPTS{'OS'} eq "freebsd") {
+ configureFirewallStopFreeBSD();
+ } elsif ($OPTS{'OS'} eq "linux") {
+ configureFirewallStopLinux();
+ }
+}
+
+# function : configureFirewallStopFreeBSD
+# purpose : unconfigure all L3-DSR firewall rules on FreeBSD
+# inputs : none
+# returns : nothing; dies on error
+
+sub configureFirewallStopFreeBSD() {
+
+ my ($cmd, $rule);
+ $cmd = $OS_DETAILS{'freebsd'}{'firewall_config_stop'};
+ $cmd =~ s/<rule>//g;
+ # explicitly set all values to 0.0.0.0...
+ for my $dscp (1..63) {
+ $rule = $OS_DETAILS{'freebsd'}{'firewall_rule'};
+ $rule =~ s/<dscp>/$dscp/g;
+ $rule =~ s/<vip>/0.0.0.0/g;
+ $cmd .= " $rule";
+ }
+ # ... then explicitly disable dscp_rewrite
+ $rule = $OS_DETAILS{'freebsd'}{'firewall_rule'};
+ $rule =~ s/<dscp.*/enabled=0/;
+ $cmd .= " $rule";
+ $cmd .= " >/dev/null";
+ runCommandOrDie($cmd);
+}
+
+# function : configureFirewallStopLinux
+# purpose : unconfigure all L3-DSR firewall rules on Linux
+# inputs : none
+# returns : nothing; dies on error
+
+sub configureFirewallStopLinux() {
+
+ my (@goners, $table);
+
+ my $cmd = $OS_DETAILS{'linux'}{'firewall_config_check'};
+ $cmd =~ s/ PREROUTING//;
+ $cmd .= " --line-numbers";
+
+ $table = 0;
+ foreach my $line (split(/\n/, `$cmd`)) {
+ if ($line =~ m/^Chain PREROUTING/) {
+ $table = 1;
+ } elsif ($line =~ m/^Chain /) {
+ $table = 0;
+ }
+
+ if ($table) {
+ if ($line =~ m/^(\d+)\s+DADDR\s+.*\s+DSCP match\s+/) {
+ push(@goners, $1);
+ }
+ }
+ }
+
+ if (scalar(@goners)) {
+ foreach my $rule (reverse(@goners)) {
+ $cmd = $OS_DETAILS{'linux'}{'firewall_config_stop'};
+ $cmd =~ s/<rule>/$rule/g;
+ runCommandOrDie($cmd);
+ }
+ }
+}
+
+
+# function : configureLoopback
+# purpose : configure the loopback device for the given VIP
+# inputs : an IP address, address family
+# returns : nothing, may die on error
+
+sub configureLoopback($$) {
+ my ($ip, $af) = @_;
+
+ verbose(sprintf("%s loopback for $ip...",
+ $OPTS{'ACTION'} eq "start" ? "Configuring" : "Unconfiguring"), 3);
+ if ($OPTS{'OS'} eq "freebsd") {
+ configureLoopbackFreeBSD($ip, $af);
+ } elsif ($OPTS{'OS'} eq "linux") {
+ configureLoopbackLinux($ip, $af);
+ }
+}
+
+
+# function : configureLoopbackFreeBSD
+# purpose : configure the loopback device for the given VIP
+# inputs : an IP address, address family
+# returns : nothing, may die on error
+
+sub configureLoopbackFreeBSD($$) {
+ my ($ip, $af) = @_;
+
+ if ($OPTS{'ACTION'} eq "start") {
+ configureLoopbackFreeBSDStart($ip, $af);
+ } elsif ($OPTS{'ACTION'} eq "stop") {
+ configureLoopbackFreeBSDStop($ip, $af);
+ }
+}
+
+
+# function : configureLoopbackFreeBSDStart
+# purpose : configure the loopback device for the given VIP and enable it
+# inputs : an IP address, address family
+# returns : nothing, may die on error
+
+sub configureLoopbackFreeBSDStart($$) {
+ my ($ip, $af) = @_;
+
+ my $vip;
+
+ if ($af eq "AF_INET") {
+ $vip = "$ip netmask 0xffffffff alias";
+ } elsif ($af eq "AF_INET6") {
+ $vip = "inet6 $ip/128\n";
+ }
+
+ my $cmd = $OS_DETAILS{'freebsd'}{'loopback_start'};
+ $cmd =~ s/<vip>/$vip/g;
+ runCommandOrDie($cmd);
+}
+
+
+# function : configureLoopbackFreeBSDStop
+# purpose : unconfigure the loopback device for the given VIP and disable it
+# inputs : an IP address, address family
+# returns : nothing, silently ignores errors
+
+sub configureLoopbackFreeBSDStop($$) {
+ my ($ip, $af) = @_;
+
+ my $cmd = $OS_DETAILS{'freebsd'}{'loopback_stop'};
+ if ($af eq "AF_INET") {
+ $cmd =~ s/<vip>/$ip/g;
+ } elsif ($af eq "AF_INET6") {
+ $cmd =~ s/<vip>/inet6 $ip/g;
+ }
+
+ runCommand($cmd);
+}
+
+
+# function : configureLoopbackLinux
+# purpose : configure the loopback device for the given VIP
+# inputs : an IP address, address family
+# returns : nothing, may die on error
+
+sub configureLoopbackLinux($$) {
+ my ($ip, $af) = @_;
+
+ if ($OPTS{'ACTION'} eq "start") {
+ configureLoopbackLinuxStart($ip, $af);
+ } elsif ($OPTS{'ACTION'} eq "stop") {
+ configureLoopbackLinuxStop($ip, $af);
+ }
+}
+
+
+# function : configureLoopbackLinuxStart
+# purpose : configure the loopback device for the given VIP and enable it
+# inputs : an IP address, address family
+# returns : nothing, may die on error
+
+sub configureLoopbackLinuxStart($$) {
+ my ($ip, $af) = @_;
+
+ my $cmd = $OS_DETAILS{'linux'}{'loopback_start'};
+ my $loopback_alias = getLoopbackAlias();
+
+ $cmd .= ":$loopback_alias";
+
+ verbose("Configuring lo:$loopback_alias...", 3);
+ if ($af eq "AF_INET") {
+ $cmd .= " $ip netmask 255.255.255.255";
+ } elsif ($af eq "AF_INET6") {
+ $cmd = " $ip/128";
+ }
+ runCommandOrDie($cmd);
+}
+
+# function : configureLoopbackLinuxStop
+# purpose : unconfigure the loopback device for the given VIP and disable it
+# inputs : an IP address, address family
+# returns : nothing, may die on error
+
+sub configureLoopbackLinuxStop($$) {
+ my ($ip, $af) = @_;
+
+ verbose("Unconfiguring loopback device...", 3);
+ my $loopback_alias = -1;
+ my $cmd = "/sbin/ifconfig -a";
+ foreach my $line (split(/\n/, `$cmd`)) {
+ if ($line =~ m/^lo:(\d+)/) {
+ $loopback_alias = $1;
+ next;
+ }
+
+ if ($loopback_alias >= 0) {
+ if ($line =~ m/inet addr:$ip\s/) {
+ last;
+ }
+ }
+ }
+
+ if ($loopback_alias < 0) {
+ # No loopback alias found.
+ return;
+ }
+
+ $cmd = $OS_DETAILS{'linux'}{'loopback_stop'};
+ $cmd =~ s/<alias>/$loopback_alias/g;
+ runCommandOrDie($cmd);
+}
+
+# function : configureVip
+# purpose : configure a given Vip
+# inputs : a "vip configuration object" (ie hash ref)
+# returns : nothing, may abort on error
+
+sub configureVip($) {
+ my ($hr) = @_;
+ my %vip = %{$hr};
+
+ verbose(sprintf("%s host for VIP %s (DSCP: %s)...",
+ $OPTS{'ACTION'} eq "start" ? "Configuring" : "Unconfiguring",
+ $vip{'ip'},
+ $vip{'dscp'}), 2);
+
+ # order matters :-/
+ if ($OPTS{'ACTION'} eq "start") {
+ handleKernelModules();
+ configureFirewall($vip{'ip'}, $vip{'dscp'});
+ } else {
+ configureFirewall($vip{'ip'}, $vip{'dscp'});
+ handleKernelModules();
+ }
+
+ configureLoopback($vip{'ip'}, $vip{'af'});
+}
+
+
+# function : error
+# purpose : print given message to STDERR, then exit with optionally
+# given exit code
+# input : message, exit code
+
+sub error($;$) {
+ my ($msg, $err) = @_;
+
+ print STDERR "$PROGNAME: $msg\n";
+
+ if ($err) {
+ exit($err);
+ # NOTREACHED
+ }
+}
+
+
+# function : getLoopbackAlias
+# purpose : determine an available loopback alias, such as lo:0
+# this is a linux specific function; it invokes "ifconfig -a"
+# and parses the output
+# inputs : none
+# returns : an integer or dies on error
+
+sub getLoopbackAlias() {
+ my $l = 0;
+ my $highest = 0;
+
+ my $cmd = "/sbin/ifconfig -a";
+ foreach my $line (split(/\n/, `$cmd`)) {
+ if ($line =~ m/^lo:(\d+)/) {
+ $highest = ($1 > $highest) ? $1 : $highest;
+ }
+ }
+
+ $l = $highest + 1;
+ return $l;
+}
+
+
+# function : handleKernelModules
+# purpose : load any required kernel modules
+# inputs : none
+# returns : nothing, may die on error
+
+sub handleKernelModules() {
+ my $os = $OPTS{'OS'};
+
+ if ($OPTS{'ACTION'} ne "start") {
+ # Nothing to do, we don't try to disable any modules.
+ return;
+ }
+
+ foreach my $mod (split(/ /, $OS_DETAILS{$os}{'kernel_modules'})) {
+ my $testcmd = $OS_DETAILS{$os}{'kernel_module_test'};
+ $testcmd =~ s/<mod>/$mod/;
+
+ if (runCommand($testcmd) != 0) {
+ my $runcmd = $OS_DETAILS{$os}{'kernel_module_load'};
+ $runcmd =~ s/<mod>/$mod/;
+ verbose("Loading/verifying kernel module $mod...", 4);
+ runCommandOrDie($runcmd);
+ }
+ }
+}
+
+
+# function : init
+# purpose : initialize variables, parse command line options;
+# inputs : none
+# returns : void, may exit under certain conditions
+
+sub init() {
+ my ($ok, %rc_opts);
+
+ $ok = GetOptions("directory|d=s" => sub { delete $OPTS{'f'}; $OPTS{'d'} = $_[1]; },
+ "file|f=s" => sub { delete $OPTS{'d'}; $OPTS{'f'} = $_[1]; },
+ "help|h" => \$OPTS{'h'},
+ "verbose|v+" => sub { $OPTS{'v'}++; },
+ );
+
+ if ($OPTS{'h'} || !$ok) {
+ usage($ok);
+ exit(!$ok);
+ # NOTREACHED
+ }
+
+ if ((scalar(@ARGV) != 1) || ($ARGV[0] !~ m/^(check|start|stop)$/)) {
+ error("You need to specify exactly one of 'check', 'start' or 'stop'.",
+ EXIT_FAILURE);
+ # NOTREACHED
+ }
+
+ $OPTS{'ACTION'} = $ARGV[0];
+ $OPTS{'OS'} = $^O;
+
+ if (!$OPTS{'d'} && !$OPTS{'f'}) {
+ $OPTS{'d'} = DEFAULT_DIR;
+ }
+}
+
+# function : parseFile
+# purpose : parse a single config file and return a hash "vip config
+# object" representing this vip
+# inputs : a file name
+# returns : a hash representing a single "vip config object"
+
+sub parseFile($) {
+ my ($file) = @_;
+ my ($fh, %vip, $lineno);
+
+ verbose("Parsing $file...", 2);
+ $lineno = 0;
+
+ open($fh, "<", $file) || die("Unable to open $file: $!\n");
+ while (my $line = <$fh>) {
+ $lineno++;
+ $line =~ s/#.*//;
+ $line =~ s/^\s*//;
+ $line =~ s/\s+$//;
+ chomp($line);