diff --git a/.ebtables.metadata b/.ebtables.metadata
new file mode 100644
index 0000000..20058f5
--- /dev/null
+++ b/.ebtables.metadata
@@ -0,0 +1 @@
+791b3b535181aa66f302356c2984cf244f76a247 SOURCES/ebtables-2.0.11.tar.bz2
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8ecada6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+BUILD
+BUILDROOT
+RPMS
+SRPMS
+
+SOURCES/ebtables-2.0.11.tar.bz2
diff --git a/SOURCES/0001-add-RARP-and-update-iana-url.patch b/SOURCES/0001-add-RARP-and-update-iana-url.patch
new file mode 100644
index 0000000..f4f1766
--- /dev/null
+++ b/SOURCES/0001-add-RARP-and-update-iana-url.patch
@@ -0,0 +1,46 @@
+From f2f5c8169619e1ea5fd3849a389da349840cfd4e Mon Sep 17 00:00:00 2001
+From: Bart De Schuymer <bdschuym@pandora.be>
+Date: Tue, 3 Jul 2012 18:47:32 +0000
+Subject: [PATCH] add RARP and update iana url
+
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ ethertypes | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/ethertypes b/ethertypes
+index 5e700f6639879..813177b74588c 100644
+--- a/ethertypes
++++ b/ethertypes
+@@ -5,6 +5,7 @@
+ #
+ # This list could be found on:
+ #         http://www.iana.org/assignments/ethernet-numbers
++#         http://www.iana.org/assignments/ieee-802-numbers
+ #
+ # <name>    <hexnumber> <alias1>...<alias35> #Comment
+ #
+@@ -21,15 +22,16 @@ LAT		6004			# DEC LAT
+ DIAG		6005			# DEC Diagnostics
+ CUST		6006			# DEC Customer use
+ SCA		6007			# DEC Systems Comms Arch
+-TEB		6558             	# Trans Ether Bridging   [RFC1701]
+-RAW_FR  	6559                   	# Raw Frame Relay        [RFC1701]
++TEB		6558			# Trans Ether Bridging   [RFC1701]
++RAW_FR  	6559			# Raw Frame Relay        [RFC1701]
++RARP		8035			# Reverse ARP            [RFC903]
+ AARP		80F3			# Appletalk AARP
+-ATALK		809B                  	# Appletalk
++ATALK		809B			# Appletalk
+ 802_1Q		8100	8021q 1q 802.1q	dot1q # 802.1Q Virtual LAN tagged frame
+ IPX		8137			# Novell IPX
+ NetBEUI		8191			# NetBEUI
+ IPv6		86DD	ip6 		# IP version 6
+-PPP		880B                    # PPP
++PPP		880B			# PPP
+ ATMMPOA		884C			# MultiProtocol over ATM
+ PPP_DISC	8863			# PPPoE discovery messages
+ PPP_SES		8864			# PPPoE session messages
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-fix-compilation-warning.patch b/SOURCES/0002-fix-compilation-warning.patch
new file mode 100644
index 0000000..46a7b99
--- /dev/null
+++ b/SOURCES/0002-fix-compilation-warning.patch
@@ -0,0 +1,26 @@
+From 10f6865652777ba7f26825d46e8b419f784463dc Mon Sep 17 00:00:00 2001
+From: Petri Gynther <petri.gynther@gmail.com>
+Date: Sun, 24 Feb 2013 10:56:59 +0100
+Subject: [PATCH] fix compilation warning
+
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ communication.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/communication.c b/communication.c
+index 62ed667deac13..ba058c05a68b4 100644
+--- a/communication.c
++++ b/communication.c
+@@ -282,7 +282,7 @@ static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
+ 	}
+ close_file:
+ 	fclose(file);
+-	return 0;
++	return ret;
+ }
+ 
+ /* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
+-- 
+2.21.0
+
diff --git a/SOURCES/0003-add-info-about-Wl-no-as-needed.patch b/SOURCES/0003-add-info-about-Wl-no-as-needed.patch
new file mode 100644
index 0000000..620d32c
--- /dev/null
+++ b/SOURCES/0003-add-info-about-Wl-no-as-needed.patch
@@ -0,0 +1,26 @@
+From 99e7c5f7976707dc59f1dfbccf12d2574eee3dab Mon Sep 17 00:00:00 2001
+From: Bart De Schuymer <bdschuym@pandora.be>
+Date: Wed, 3 Jul 2013 22:12:47 +0200
+Subject: [PATCH] add info about -Wl,-no-as-needed
+
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ INSTALL | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/INSTALL b/INSTALL
+index 4a05c678caab0..e90d5c103bdc4 100644
+--- a/INSTALL
++++ b/INSTALL
+@@ -39,6 +39,8 @@ That's all
+ You can also use a base directory different from the root directory (/),
+ using the DESTDIR option. See the Makefile for more details.
+ 
++You might need to set LDFLAGS=-Wl,-no-as-needed to build ebtables correctly
++on your system.
+ 
+ ADDITIONAL PROGRAMS:
+ ----------------------
+-- 
+2.21.0
+
diff --git a/SOURCES/0004-workaround-for-kernel-regression-bug-IPv6-source-des.patch b/SOURCES/0004-workaround-for-kernel-regression-bug-IPv6-source-des.patch
new file mode 100644
index 0000000..fd6d97e
--- /dev/null
+++ b/SOURCES/0004-workaround-for-kernel-regression-bug-IPv6-source-des.patch
@@ -0,0 +1,29 @@
+From 32e8e2b169b215cca038121268d6e6968719f268 Mon Sep 17 00:00:00 2001
+From: Luis Fernando <tdthp@terra.com.br>
+Date: Wed, 3 Jul 2013 22:19:55 +0200
+Subject: [PATCH] workaround for kernel regression bug: IPv6 source/destination
+ addresses are potentially not matched correctly
+
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_ip6.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c
+index 0465e77b5d906..bbdc4aef9a172 100644
+--- a/extensions/ebt_ip6.c
++++ b/extensions/ebt_ip6.c
+@@ -312,6 +312,10 @@ static void init(struct ebt_entry_match *match)
+ 
+ 	ipinfo->invflags = 0;
+ 	ipinfo->bitmask = 0;
++	memset(ipinfo->saddr.s6_addr, 0, sizeof(ipinfo->saddr.s6_addr));
++	memset(ipinfo->smsk.s6_addr, 0, sizeof(ipinfo->smsk.s6_addr));
++	memset(ipinfo->daddr.s6_addr, 0, sizeof(ipinfo->daddr.s6_addr));
++	memset(ipinfo->dmsk.s6_addr, 0, sizeof(ipinfo->dmsk.s6_addr));
+ }
+ 
+ #define OPT_SOURCE 0x01
+-- 
+2.21.0
+
diff --git a/SOURCES/0005-Add-noflush-command-line-support-for-ebtables-restor.patch b/SOURCES/0005-Add-noflush-command-line-support-for-ebtables-restor.patch
new file mode 100644
index 0000000..061466b
--- /dev/null
+++ b/SOURCES/0005-Add-noflush-command-line-support-for-ebtables-restor.patch
@@ -0,0 +1,76 @@
+From d1d746dde7089b39598f2d7b7fef61fc52f52c25 Mon Sep 17 00:00:00 2001
+From: Sanket Shah <sanket.shah@cyberoam.com>
+Date: Wed, 31 Jul 2013 21:40:08 +0200
+Subject: [PATCH] Add --noflush command line support for ebtables-restore
+
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ ebtables-restore.c | 29 +++++++++++++++++++++++++----
+ 1 file changed, 25 insertions(+), 4 deletions(-)
+
+diff --git a/ebtables-restore.c b/ebtables-restore.c
+index ea0296055212e..bb4d0cffda1cc 100644
+--- a/ebtables-restore.c
++++ b/ebtables-restore.c
+@@ -22,13 +22,25 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <unistd.h>
++#include <getopt.h>
+ #include "include/ebtables_u.h"
+ 
++static const struct option options[] = {
++	{.name = "noflush", .has_arg = 0, .val = 'n'},
++	{ 0 }
++};
++
+ static struct ebt_u_replace replace[3];
+ void ebt_early_init_once();
+ 
+ #define OPT_KERNELDATA  0x800 /* Also defined in ebtables.c */
+ 
++static void print_usage()
++{
++	fprintf(stderr, "Usage: ebtables-restore [ --noflush ]\n");
++	exit(1);
++}
++
+ static void copy_table_names()
+ {
+ 	strcpy(replace[0].name, "filter");
+@@ -41,11 +53,20 @@ static void copy_table_names()
+ int main(int argc_, char *argv_[])
+ {
+ 	char *argv[EBTD_ARGC_MAX], cmdline[EBTD_CMDLINE_MAXLN];
+-	int i, offset, quotemode = 0, argc, table_nr = -1, line = 0, whitespace;
++	int i, offset, quotemode = 0, argc, table_nr = -1, line = 0, whitespace, c, flush = 1;
+ 	char ebtables_str[] = "ebtables";
+ 
+-	if (argc_ != 1)
+-		ebtrest_print_error("options are not supported");
++	while ((c = getopt_long(argc_, argv_, "n", options, NULL)) != -1) {
++		switch(c) {
++			case 'n':
++				flush = 0;
++				break;
++			default:
++				print_usage();
++				break;
++		}
++	}
++
+ 	ebt_silent = 0;
+ 	copy_table_names();
+ 	ebt_early_init_once();
+@@ -68,7 +89,7 @@ int main(int argc_, char *argv_[])
+ 				ebtrest_print_error("table '%s' was not recognized", cmdline+1);
+ 			table_nr = i;
+ 			replace[table_nr].command = 11;
+-			ebt_get_kernel_table(&replace[table_nr], 1);
++			ebt_get_kernel_table(&replace[table_nr], flush);
+ 			replace[table_nr].command = 0;
+ 			replace[table_nr].flags = OPT_KERNELDATA; /* Prevent do_command from initialising replace */
+ 			continue;
+-- 
+2.21.0
+
diff --git a/SOURCES/0006-don-t-print-IPv6-mask-if-it-s-all-ones-based-on-patc.patch b/SOURCES/0006-don-t-print-IPv6-mask-if-it-s-all-ones-based-on-patc.patch
new file mode 100644
index 0000000..5deb6f9
--- /dev/null
+++ b/SOURCES/0006-don-t-print-IPv6-mask-if-it-s-all-ones-based-on-patc.patch
@@ -0,0 +1,70 @@
+From 657c50fea3cc6a05dca5f055f4377ab412fe21f0 Mon Sep 17 00:00:00 2001
+From: Bart De Schuymer <bdschuym@pandora.be>
+Date: Mon, 14 Apr 2014 22:04:55 +0200
+Subject: [PATCH] don't print IPv6 mask if it's all ones (based on patch by
+ Mariusz Mazur <mmazur at axeos.com>)
+
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_ip6.c |  4 ++--
+ include/ebtables_u.h |  1 +
+ useful_functions.c   | 13 +++++++++++++
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c
+index bbdc4aef9a172..e3e0956e00f01 100644
+--- a/extensions/ebt_ip6.c
++++ b/extensions/ebt_ip6.c
+@@ -449,14 +449,14 @@ static void print(const struct ebt_u_entry *entry,
+ 		if (ipinfo->invflags & EBT_IP6_SOURCE)
+ 			printf("! ");
+ 		printf("%s", ebt_ip6_to_numeric(&ipinfo->saddr));
+-		printf("/%s ", ebt_ip6_to_numeric(&ipinfo->smsk));
++		printf("%s ", ebt_ip6_mask_to_string(&ipinfo->smsk));
+ 	}
+ 	if (ipinfo->bitmask & EBT_IP6_DEST) {
+ 		printf("--ip6-dst ");
+ 		if (ipinfo->invflags & EBT_IP6_DEST)
+ 			printf("! ");
+ 		printf("%s", ebt_ip6_to_numeric(&ipinfo->daddr));
+-		printf("/%s ", ebt_ip6_to_numeric(&ipinfo->dmsk));
++		printf("%s ", ebt_ip6_mask_to_string(&ipinfo->dmsk));
+ 	}
+ 	if (ipinfo->bitmask & EBT_IP6_TCLASS) {
+ 		printf("--ip6-tclass ");
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index ab615c1d59c44..35a5bcc54c865 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -303,6 +303,7 @@ char *ebt_mask_to_dotted(uint32_t mask);
+ void ebt_parse_ip6_address(char *address, struct in6_addr *addr, 
+ 						   struct in6_addr *msk);
+ char *ebt_ip6_to_numeric(const struct in6_addr *addrp);
++char *ebt_ip6_mask_to_string(const struct in6_addr *msk);
+ 
+ 
+ int do_command(int argc, char *argv[], int exec_style,
+diff --git a/useful_functions.c b/useful_functions.c
+index d20b68e31eabb..d14cbe9dbdba1 100644
+--- a/useful_functions.c
++++ b/useful_functions.c
+@@ -411,3 +411,16 @@ char *ebt_ip6_to_numeric(const struct in6_addr *addrp)
+ 	static char buf[50+1];
+ 	return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
+ }
++
++char *ebt_ip6_mask_to_string(const struct in6_addr *msk)
++{
++   	/* /0000:0000:0000:0000:0000:000.000.000.000
++	 * /0000:0000:0000:0000:0000:0000:0000:0000 */
++	static char buf[51+1];
++	if (msk->s6_addr32[0] == 0xFFFFFFFFL && msk->s6_addr32[1] == 0xFFFFFFFFL &&
++	    msk->s6_addr32[2] == 0xFFFFFFFFL && msk->s6_addr32[3] == 0xFFFFFFFFL)
++		*buf = '\0';
++	else
++		sprintf(buf, "/%s", ebt_ip6_to_numeric(msk));
++	return buf;
++}
+-- 
+2.21.0
+
diff --git a/SOURCES/0007-Add-kernel-headers-needed-from-v3.16.patch b/SOURCES/0007-Add-kernel-headers-needed-from-v3.16.patch
new file mode 100644
index 0000000..53f3cfc
--- /dev/null
+++ b/SOURCES/0007-Add-kernel-headers-needed-from-v3.16.patch
@@ -0,0 +1,239 @@
+From a29aa9b111e00fcf6dd8268a2a18314df0ea0d4b Mon Sep 17 00:00:00 2001
+From: Pedro Alvarez <pedro.alvarez@codethink.co.uk>
+Date: Fri, 27 Feb 2015 11:54:10 +0000
+Subject: [PATCH] Add kernel headers needed from v3.16
+
+Ebtables fails to compile with versions of the linux headers greater
+than v3.16 with this error:
+
+  extensions/ebt_ulog.c:17:45: fatal error: linux/netfilter_bridge/ebt_ulog.h: No such file or directory
+   #include <linux/netfilter_bridge/ebt_ulog.h>
+
+This patch adds netfilter_bridge headers for every supported
+extension, including filter.h and types.h, to avoid this problem and
+future problems with changes in the kernel headers.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ include/linux/netfilter_bridge.h           |  2 +-
+ include/linux/netfilter_bridge/ebt_802_3.h |  7 ++-
+ include/linux/netfilter_bridge/ebtables.h  | 70 ++++++++++------------
+ include/linux/types.h                      |  2 +-
+ 4 files changed, 37 insertions(+), 44 deletions(-)
+
+diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
+index 5094ecca9c1b3..c4dbfd91a17b9 100644
+--- a/include/linux/netfilter_bridge.h
++++ b/include/linux/netfilter_bridge.h
+@@ -24,4 +24,4 @@
+ #define NF_BR_BROUTING		5
+ #define NF_BR_NUMHOOKS		6
+ 
+-#endif
++#endif /* __LINUX_BRIDGE_NETFILTER_H */
+diff --git a/include/linux/netfilter_bridge/ebt_802_3.h b/include/linux/netfilter_bridge/ebt_802_3.h
+index 76687d51f0eb8..70028c1523164 100644
+--- a/include/linux/netfilter_bridge/ebt_802_3.h
++++ b/include/linux/netfilter_bridge/ebt_802_3.h
+@@ -2,6 +2,7 @@
+ #define __LINUX_BRIDGE_EBT_802_3_H
+ 
+ #include <linux/types.h>
++#include <linux/if_ether.h>
+ 
+ #define EBT_802_3_SAP 0x01
+ #define EBT_802_3_TYPE 0x02
+@@ -42,8 +43,8 @@ struct hdr_ni {
+ };
+ 
+ struct ebt_802_3_hdr {
+-	__u8  daddr[6];
+-	__u8  saddr[6];
++	__u8  daddr[ETH_ALEN];
++	__u8  saddr[ETH_ALEN];
+ 	__be16 len;
+ 	union {
+ 		struct hdr_ui ui;
+@@ -59,4 +60,4 @@ struct ebt_802_3_info {
+ 	__u8  invflags;
+ };
+ 
+-#endif
++#endif /* __LINUX_BRIDGE_EBT_802_3_H */
+diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
+index 8f520c600b356..19a64448c648e 100644
+--- a/include/linux/netfilter_bridge/ebtables.h
++++ b/include/linux/netfilter_bridge/ebtables.h
+@@ -10,7 +10,6 @@
+  *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+  */
+ 
+-/* Local copy of the kernel file, needed for Sparc64 support */
+ #ifndef __LINUX_BRIDGE_EFF_H
+ #define __LINUX_BRIDGE_EFF_H
+ #include <linux/if.h>
+@@ -32,14 +31,31 @@
+  * The 4 lsb are more than enough to store the verdict. */
+ #define EBT_VERDICT_BITS 0x0000000F
+ 
+-struct ebt_counter
+-{
++struct xt_match;
++struct xt_target;
++
++struct ebt_counter {
+ 	uint64_t pcnt;
+ 	uint64_t bcnt;
+ };
+ 
+-struct ebt_replace
+-{
++struct ebt_replace {
++	char name[EBT_TABLE_MAXNAMELEN];
++	unsigned int valid_hooks;
++	/* nr of rules in the table */
++	unsigned int nentries;
++	/* total size of the entries */
++	unsigned int entries_size;
++	/* start of the chains */
++	struct ebt_entries *hook_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;
++	char *entries;
++};
++
++struct ebt_replace_kernel {
+ 	char name[EBT_TABLE_MAXNAMELEN];
+ 	unsigned int valid_hooks;
+ 	/* nr of rules in the table */
+@@ -47,21 +63,12 @@ struct ebt_replace
+ 	/* total size of the entries */
+ 	unsigned int entries_size;
+ 	/* start of the chains */
+-#ifdef KERNEL_64_USERSPACE_32
+-	uint64_t hook_entry[NF_BR_NUMHOOKS];
+-#else
+ 	struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
+-#endif
+ 	/* nr of counters userspace expects back */
+ 	unsigned int num_counters;
+ 	/* where the kernel will put the old counters */
+-#ifdef KERNEL_64_USERSPACE_32
+-	uint64_t counters;
+-	uint64_t entries;
+-#else
+ 	struct ebt_counter *counters;
+ 	char *entries;
+-#endif
+ };
+ 
+ struct ebt_entries {
+@@ -85,7 +92,7 @@ struct ebt_entries {
+ 
+ /* This is a hack to make a difference between an ebt_entry struct and an
+  * ebt_entries struct when traversing the entries from start to end.
+- * Using this simplifies the code alot, while still being able to use
++ * Using this simplifies the code a lot, while still being able to use
+  * ebt_entries.
+  * Contrary, iptables doesn't use something like ebt_entries and therefore uses
+  * different techniques for naming the policy and such. So, iptables doesn't
+@@ -110,56 +117,40 @@ struct ebt_entries {
+ #define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \
+    | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST)
+ 
+-struct ebt_entry_match
+-{
++struct ebt_entry_match {
+ 	union {
+ 		char name[EBT_FUNCTION_MAXNAMELEN];
+-		struct ebt_match *match;
++		struct xt_match *match;
+ 	} u;
+ 	/* size of data */
+ 	unsigned int match_size;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+ 	unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+ };
+ 
+-struct ebt_entry_watcher
+-{
++struct ebt_entry_watcher {
+ 	union {
+ 		char name[EBT_FUNCTION_MAXNAMELEN];
+-		struct ebt_watcher *watcher;
++		struct xt_target *watcher;
+ 	} u;
+ 	/* size of data */
+ 	unsigned int watcher_size;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+ 	unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+ };
+ 
+-struct ebt_entry_target
+-{
++struct ebt_entry_target {
+ 	union {
+ 		char name[EBT_FUNCTION_MAXNAMELEN];
+-		struct ebt_target *target;
++		struct xt_target *target;
+ 	} u;
+ 	/* size of data */
+ 	unsigned int target_size;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+ 	unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+ };
+ 
+ #define EBT_STANDARD_TARGET "standard"
+-struct ebt_standard_target
+-{
++struct ebt_standard_target {
+ 	struct ebt_entry_target target;
+ 	int verdict;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+ };
+ 
+ /* one entry */
+@@ -167,7 +158,7 @@ struct ebt_entry {
+ 	/* this needs to be the first field */
+ 	unsigned int bitmask;
+ 	unsigned int invflags;
+-	uint16_t ethproto;
++	__be16 ethproto;
+ 	/* the physical in-dev */
+ 	char in[IFNAMSIZ];
+ 	/* the logical in-dev */
+@@ -202,6 +193,7 @@ struct ebt_entry {
+ #define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1)
+ #define EBT_SO_GET_MAX          (EBT_SO_GET_INIT_ENTRIES+1)
+ 
++
+ /* blatently stolen from ip_tables.h
+  * fn returns 0 to continue iteration */
+ #define EBT_MATCH_ITERATE(e, fn, args...)                   \
+diff --git a/include/linux/types.h b/include/linux/types.h
+index 630cd3bb01f0a..23ea78fd1847a 100644
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -38,7 +38,7 @@ typedef __u32 __bitwise __wsum;
+  * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid
+  * common 32/64-bit compat problems.
+  * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other
+- * architectures) and to 8-byte boundaries on 64-bit architetures.  The new
++ * architectures) and to 8-byte boundaries on 64-bit architectures.  The new
+  * aligned_64 type enforces 8-byte alignment so that structs containing
+  * aligned_64 values have the same alignment on 32-bit and 64-bit architectures.
+  * No conversions are necessary between 32-bit user-space and a 64-bit kernel.
+-- 
+2.21.0
+
diff --git a/SOURCES/0008-extensions-Use-stdint-types.patch b/SOURCES/0008-extensions-Use-stdint-types.patch
new file mode 100644
index 0000000..2d7db9f
--- /dev/null
+++ b/SOURCES/0008-extensions-Use-stdint-types.patch
@@ -0,0 +1,68 @@
+From 5bee10734107bd4365fa9aff634c1b492634f454 Mon Sep 17 00:00:00 2001
+From: Felix Janda <felix.janda@posteo.de>
+Date: Sat, 16 May 2015 12:22:39 +0200
+Subject: [PATCH] extensions: Use stdint types
+
+Signed-off-by: Felix Janda <felix.janda@posteo.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_ip6.c   |  4 ++--
+ extensions/ebt_limit.c | 10 +++++-----
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c
+index e3e0956e00f01..dd48547b0010b 100644
+--- a/extensions/ebt_ip6.c
++++ b/extensions/ebt_ip6.c
+@@ -53,8 +53,8 @@ static const struct option opts[] =
+ 
+ struct icmpv6_names {
+ 	const char *name;
+-	u_int8_t type;
+-	u_int8_t code_min, code_max;
++	uint8_t type;
++	uint8_t code_min, code_max;
+ };
+ 
+ static const struct icmpv6_names icmpv6_codes[] = {
+diff --git a/extensions/ebt_limit.c b/extensions/ebt_limit.c
+index ee40e5ccc9172..d189a09aa7cab 100644
+--- a/extensions/ebt_limit.c
++++ b/extensions/ebt_limit.c
+@@ -59,11 +59,11 @@ static void print_help(void)
+ "                                default %u\n", EBT_LIMIT_BURST);
+ }
+ 
+-static int parse_rate(const char *rate, u_int32_t *val)
++static int parse_rate(const char *rate, uint32_t *val)
+ {
+ 	const char *delim;
+-	u_int32_t r;
+-	u_int32_t mult = 1;  /* Seconds by default. */
++	uint32_t r;
++	uint32_t mult = 1;  /* Seconds by default. */
+ 
+ 	delim = strchr(rate, '/');
+ 	if (delim) {
+@@ -151,7 +151,7 @@ static void final_check(const struct ebt_u_entry *entry,
+ struct rates
+ {
+ 	const char *name;
+-	u_int32_t mult;
++	uint32_t mult;
+ };
+ 
+ static struct rates g_rates[] =
+@@ -162,7 +162,7 @@ static struct rates g_rates[] =
+ 	{ "sec", EBT_LIMIT_SCALE }
+ };
+ 
+-static void print_rate(u_int32_t period)
++static void print_rate(uint32_t period)
+ {
+ 	unsigned int i;
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0009-ethernetdb.h-Remove-C-specific-compiler-hint-macro-_.patch b/SOURCES/0009-ethernetdb.h-Remove-C-specific-compiler-hint-macro-_.patch
new file mode 100644
index 0000000..4339b8d
--- /dev/null
+++ b/SOURCES/0009-ethernetdb.h-Remove-C-specific-compiler-hint-macro-_.patch
@@ -0,0 +1,48 @@
+From 53fb609bce104b316052acec39437c62407634e9 Mon Sep 17 00:00:00 2001
+From: Felix Janda <felix.janda@posteo.de>
+Date: Sat, 16 May 2015 12:31:58 +0200
+Subject: [PATCH] ethernetdb.h: Remove C++ specific compiler hint macro _THROW
+
+Fixes compilation with musl libc
+
+Signed-off-by: Felix Janda <felix.janda@posteo.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ include/ethernetdb.h | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/include/ethernetdb.h b/include/ethernetdb.h
+index 46d8bfd1b7e58..1683abe01987e 100644
+--- a/include/ethernetdb.h
++++ b/include/ethernetdb.h
+@@ -38,21 +38,20 @@ struct ethertypeent {
+ 
+ /* Open ethertype data base files and mark them as staying open even
+    after a later search if STAY_OPEN is non-zero.  */
+-extern void setethertypeent(int __stay_open) __THROW;
++extern void setethertypeent(int __stay_open);
+ 
+ /* Close ethertype data base files and clear `stay open' flag.  */
+-extern void endethertypeent(void) __THROW;
++extern void endethertypeent(void);
+ 
+ /* Get next entry from ethertype data base file.  Open data base if
+    necessary.  */
+-extern struct ethertypeent *getethertypeent(void) __THROW;
++extern struct ethertypeent *getethertypeent(void);
+ 
+ /* Return entry from ethertype data base for network with NAME.  */
+-extern struct ethertypeent *getethertypebyname(__const char *__name)
+-    __THROW;
++extern struct ethertypeent *getethertypebyname(__const char *__name);
+ 
+ /* Return entry from ethertype data base which number is PROTO.  */
+-extern struct ethertypeent *getethertypebynumber(int __ethertype) __THROW;
++extern struct ethertypeent *getethertypebynumber(int __ethertype);
+ 
+ 
+ #endif				/* ethernetdb.h */
+-- 
+2.21.0
+
diff --git a/SOURCES/0010-ebtables-Allow-RETURN-target-rules-in-user-defined-c.patch b/SOURCES/0010-ebtables-Allow-RETURN-target-rules-in-user-defined-c.patch
new file mode 100644
index 0000000..b54f158
--- /dev/null
+++ b/SOURCES/0010-ebtables-Allow-RETURN-target-rules-in-user-defined-c.patch
@@ -0,0 +1,48 @@
+From 31b9f879b04314da07d79dd653465c4dc030f819 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Alin=20N=C4=83stac?= <alin.nastac@gmail.com>
+Date: Thu, 22 Oct 2015 16:41:03 +0200
+Subject: [PATCH] ebtables: Allow RETURN target rules in user defined chains
+
+During loop checking ebtables marks entries with '1 << NF_BR_NUMHOOKS' if
+they're called from a base chain rather than a user defined chain.
+
+This can be used by ebtables targets that can encode a special return
+value to bail out if e.g. RETURN is used from a base chain.
+
+Unfortunately, this is broken, since the '1 << NF_BR_NUMHOOKS' is also
+copied to called user-defined-chains (i.e., a user defined chain can no
+longer be distinguished from a base chain):
+
+root@OpenWrt:~# ebtables -N foo
+root@OpenWrt:~# ebtables -A OUTPUT -j foo
+root@OpenWrt:~# ebtables -A foo -j mark --mark-or 3 --mark-target RETURN
+--mark-target RETURN not allowed on base chain.
+
+This works if -A OUTPUT -j foo is omitted, but will still appear
+if we try to call foo from OUTPUT afterwards.
+
+After this patch we still reject
+'-A OUTPUT -j mark .. --mark-target RETURN'.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ libebtc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libebtc.c b/libebtc.c
+index 17ba8f243dd45..74830ecf2e91b 100644
+--- a/libebtc.c
++++ b/libebtc.c
+@@ -1102,7 +1102,7 @@ void ebt_check_for_loops(struct ebt_u_replace *replace)
+ 			/* check if we've dealt with this chain already */
+ 			if (entries2->hook_mask & (1<<i))
+ 				goto letscontinue;
+-			entries2->hook_mask |= entries->hook_mask;
++			entries2->hook_mask |= entries->hook_mask & ~(1 << NF_BR_NUMHOOKS);
+ 			/* Jump to the chain, make sure we know how to get back */
+ 			stack[sp].chain_nr = chain_nr;
+ 			stack[sp].n = j;
+-- 
+2.21.0
+
diff --git a/SOURCES/0011-ebtables-extensions-Constify-option-struct.patch b/SOURCES/0011-ebtables-extensions-Constify-option-struct.patch
new file mode 100644
index 0000000..fc6c3e4
--- /dev/null
+++ b/SOURCES/0011-ebtables-extensions-Constify-option-struct.patch
@@ -0,0 +1,265 @@
+From d1824930e9c9011c84f162db71d1ed649e14a6d1 Mon Sep 17 00:00:00 2001
+From: Gargi Sharma <gs051095@gmail.com>
+Date: Tue, 28 Mar 2017 19:42:39 +0530
+Subject: [PATCH] ebtables: extensions: Constify option struct
+
+The struct  of the type option is only used to initialise a field
+inside the ebt_u_watcher or ebt_u_target or ebt_u_match struct and
+is not modified anywhere.
+
+Signed-off-by: Gargi Sharma <gs051095@gmail.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_802_3.c    | 2 +-
+ extensions/ebt_among.c    | 2 +-
+ extensions/ebt_arp.c      | 2 +-
+ extensions/ebt_arpreply.c | 2 +-
+ extensions/ebt_ip.c       | 2 +-
+ extensions/ebt_limit.c    | 2 +-
+ extensions/ebt_log.c      | 2 +-
+ extensions/ebt_mark.c     | 2 +-
+ extensions/ebt_mark_m.c   | 2 +-
+ extensions/ebt_nat.c      | 4 ++--
+ extensions/ebt_nflog.c    | 2 +-
+ extensions/ebt_pkttype.c  | 2 +-
+ extensions/ebt_redirect.c | 2 +-
+ extensions/ebt_standard.c | 2 +-
+ extensions/ebt_stp.c      | 2 +-
+ extensions/ebt_ulog.c     | 2 +-
+ extensions/ebt_vlan.c     | 2 +-
+ 17 files changed, 18 insertions(+), 18 deletions(-)
+
+diff --git a/extensions/ebt_802_3.c b/extensions/ebt_802_3.c
+index dd22eb2605334..458484939231d 100644
+--- a/extensions/ebt_802_3.c
++++ b/extensions/ebt_802_3.c
+@@ -17,7 +17,7 @@
+ #define _802_3_SAP '1'
+ #define _802_3_TYPE '2'
+ 
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "802_3-sap"   , required_argument, 0, _802_3_SAP },
+ 	{ "802_3-type"  , required_argument, 0, _802_3_TYPE },
+diff --git a/extensions/ebt_among.c b/extensions/ebt_among.c
+index f97d07ec118ed..e4fc5ac22a005 100644
+--- a/extensions/ebt_among.c
++++ b/extensions/ebt_among.c
+@@ -26,7 +26,7 @@
+ #define AMONG_DST_F '3'
+ #define AMONG_SRC_F '4'
+ 
+-static struct option opts[] = {
++static const struct option opts[] = {
+ 	{"among-dst", required_argument, 0, AMONG_DST},
+ 	{"among-src", required_argument, 0, AMONG_SRC},
+ 	{"among-dst-file", required_argument, 0, AMONG_DST_F},
+diff --git a/extensions/ebt_arp.c b/extensions/ebt_arp.c
+index 64d337d5967cf..b2819553ab313 100644
+--- a/extensions/ebt_arp.c
++++ b/extensions/ebt_arp.c
+@@ -24,7 +24,7 @@
+ #define ARP_MAC_S  '6'
+ #define ARP_MAC_D  '7'
+ #define ARP_GRAT   '8'
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "arp-opcode"    , required_argument, 0, ARP_OPCODE },
+ 	{ "arp-op"        , required_argument, 0, ARP_OPCODE },
+diff --git a/extensions/ebt_arpreply.c b/extensions/ebt_arpreply.c
+index c3757f389ba23..51eda66adbff3 100644
+--- a/extensions/ebt_arpreply.c
++++ b/extensions/ebt_arpreply.c
+@@ -19,7 +19,7 @@ static int mac_supplied;
+ 
+ #define REPLY_MAC '1'
+ #define REPLY_TARGET '2'
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "arpreply-mac" ,    required_argument, 0, REPLY_MAC    },
+ 	{ "arpreply-target" , required_argument, 0, REPLY_TARGET },
+diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c
+index 4e0b7f0780302..59559feffa50b 100644
+--- a/extensions/ebt_ip.c
++++ b/extensions/ebt_ip.c
+@@ -25,7 +25,7 @@
+ #define IP_SPORT  '5'
+ #define IP_DPORT  '6'
+ 
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "ip-source"           , required_argument, 0, IP_SOURCE },
+ 	{ "ip-src"              , required_argument, 0, IP_SOURCE },
+diff --git a/extensions/ebt_limit.c b/extensions/ebt_limit.c
+index d189a09aa7cab..2cbf4dee51fb4 100644
+--- a/extensions/ebt_limit.c
++++ b/extensions/ebt_limit.c
+@@ -41,7 +41,7 @@ static int string_to_number(const char *s, unsigned int min, unsigned int max,
+ #define ARG_LIMIT		'1'
+ #define ARG_LIMIT_BURST		'2'
+ 
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "limit",		required_argument, 0, ARG_LIMIT },
+ 	{ "limit-burst",	required_argument, 0, ARG_LIMIT_BURST },
+diff --git a/extensions/ebt_log.c b/extensions/ebt_log.c
+index 1cf831a7ec17a..97d50919d25ca 100644
+--- a/extensions/ebt_log.c
++++ b/extensions/ebt_log.c
+@@ -61,7 +61,7 @@ static int name_to_loglevel(char* arg)
+ #define LOG_IP     '4'
+ #define LOG_LOG    '5'
+ #define LOG_IP6    '6'
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "log-prefix", required_argument, 0, LOG_PREFIX },
+ 	{ "log-level" , required_argument, 0, LOG_LEVEL  },
+diff --git a/extensions/ebt_mark.c b/extensions/ebt_mark.c
+index 5776b1cb24509..4cf1378d5085c 100644
+--- a/extensions/ebt_mark.c
++++ b/extensions/ebt_mark.c
+@@ -20,7 +20,7 @@ static int mark_supplied;
+ #define MARK_ORMARK  '3'
+ #define MARK_ANDMARK '4'
+ #define MARK_XORMARK '5'
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "mark-target" , required_argument, 0, MARK_TARGET },
+ 	/* an oldtime messup, we should have always used the scheme
+diff --git a/extensions/ebt_mark_m.c b/extensions/ebt_mark_m.c
+index 2a259b04368d0..7561f059c0108 100644
+--- a/extensions/ebt_mark_m.c
++++ b/extensions/ebt_mark_m.c
+@@ -15,7 +15,7 @@
+ 
+ #define MARK '1'
+ 
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "mark", required_argument, 0, MARK },
+ 	{ 0 }
+diff --git a/extensions/ebt_nat.c b/extensions/ebt_nat.c
+index e6afbf8f3a3f8..00d9cd4083247 100644
+--- a/extensions/ebt_nat.c
++++ b/extensions/ebt_nat.c
+@@ -21,7 +21,7 @@ static int to_source_supplied, to_dest_supplied;
+ #define NAT_S_TARGET '2'
+ #define NAT_D_TARGET '2'
+ #define NAT_S_ARP '3'
+-static struct option opts_s[] =
++static const struct option opts_s[] =
+ {
+ 	{ "to-source"     , required_argument, 0, NAT_S },
+ 	{ "to-src"        , required_argument, 0, NAT_S },
+@@ -30,7 +30,7 @@ static struct option opts_s[] =
+ 	{ 0 }
+ };
+ 
+-static struct option opts_d[] =
++static const struct option opts_d[] =
+ {
+ 	{ "to-destination", required_argument, 0, NAT_D },
+ 	{ "to-dst"        , required_argument, 0, NAT_D },
+diff --git a/extensions/ebt_nflog.c b/extensions/ebt_nflog.c
+index 0cd10e05f1c33..405673a01f893 100644
+--- a/extensions/ebt_nflog.c
++++ b/extensions/ebt_nflog.c
+@@ -25,7 +25,7 @@ enum {
+ 	NFLOG_NFLOG = 0x16,
+ };
+ 
+-static struct option nflog_opts[] = {
++static const struct option nflog_opts[] = {
+ 	{"nflog-group", required_argument, NULL, NFLOG_GROUP},
+ 	{"nflog-prefix", required_argument, NULL, NFLOG_PREFIX},
+ 	{"nflog-range", required_argument, NULL, NFLOG_RANGE},
+diff --git a/extensions/ebt_pkttype.c b/extensions/ebt_pkttype.c
+index 5b5cb0398d559..486c85c3c3faf 100644
+--- a/extensions/ebt_pkttype.c
++++ b/extensions/ebt_pkttype.c
+@@ -27,7 +27,7 @@ char *classes[] =
+ 	"\0"
+ };
+ 
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "pkttype-type"        , required_argument, 0, '1' },
+ 	{ 0 }
+diff --git a/extensions/ebt_redirect.c b/extensions/ebt_redirect.c
+index e47081894317c..3f8227a917583 100644
+--- a/extensions/ebt_redirect.c
++++ b/extensions/ebt_redirect.c
+@@ -14,7 +14,7 @@
+ #include <linux/netfilter_bridge/ebt_redirect.h>
+ 
+ #define REDIRECT_TARGET '1'
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "redirect-target", required_argument, 0, REDIRECT_TARGET },
+ 	{ 0 }
+diff --git a/extensions/ebt_standard.c b/extensions/ebt_standard.c
+index 67d4d7cc7046b..81edead71a840 100644
+--- a/extensions/ebt_standard.c
++++ b/extensions/ebt_standard.c
+@@ -11,7 +11,7 @@
+ #include <getopt.h>
+ #include "../include/ebtables_u.h"
+ 
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{0}
+ };
+diff --git a/extensions/ebt_stp.c b/extensions/ebt_stp.c
+index 2b108a707fe65..5c5fc3334311d 100644
+--- a/extensions/ebt_stp.c
++++ b/extensions/ebt_stp.c
+@@ -27,7 +27,7 @@
+ #define STP_FWDD	'l'
+ #define STP_NUMOPS 12
+ 
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "stp-type"         , required_argument, 0, STP_TYPE},
+ 	{ "stp-flags"        , required_argument, 0, STP_FLAGS},
+diff --git a/extensions/ebt_ulog.c b/extensions/ebt_ulog.c
+index 162586d7a4c35..54eec53f7069f 100644
+--- a/extensions/ebt_ulog.c
++++ b/extensions/ebt_ulog.c
+@@ -24,7 +24,7 @@
+ #define ULOG_CPRANGE    '3'
+ #define ULOG_QTHRESHOLD '4'
+ #define ULOG_ULOG       '5'
+-static struct option opts[] =
++static const struct option opts[] =
+ {
+ 	{ "ulog-prefix"    , required_argument, 0, ULOG_PREFIX     },
+ 	{ "ulog-nlgroup"   , required_argument, 0, ULOG_NLGROUP    },
+diff --git a/extensions/ebt_vlan.c b/extensions/ebt_vlan.c
+index 6714c82d4d1ac..0a37067b5ebde 100644
+--- a/extensions/ebt_vlan.c
++++ b/extensions/ebt_vlan.c
+@@ -25,7 +25,7 @@
+ #define VLAN_PRIO  '2'
+ #define VLAN_ENCAP '3'
+ 
+-static struct option opts[] = {
++static const struct option opts[] = {
+ 	{"vlan-id"   , required_argument, NULL, VLAN_ID},
+ 	{"vlan-prio" , required_argument, NULL, VLAN_PRIO},
+ 	{"vlan-encap", required_argument, NULL, VLAN_ENCAP},
+-- 
+2.21.0
+
diff --git a/SOURCES/0012-Use-flock-for-concurrent-option.patch b/SOURCES/0012-Use-flock-for-concurrent-option.patch
new file mode 100644
index 0000000..11becfd
--- /dev/null
+++ b/SOURCES/0012-Use-flock-for-concurrent-option.patch
@@ -0,0 +1,126 @@
+From 908ec85f171a1307eeee48499f43d3778c96a210 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Fri, 6 Oct 2017 12:48:50 +0200
+Subject: [PATCH] Use flock() for --concurrent option
+
+The previous locking mechanism was not atomic, hence it was possible
+that a killed ebtables process would leave the lock file in place which
+in turn made future ebtables processes wait indefinitely for the lock to
+become free.
+
+Fix this by using flock(). This also simplifies code quite a bit because
+there is no need for a custom signal handler or an __exit routine
+anymore.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ ebtables.c |  8 --------
+ libebtc.c  | 49 +++++--------------------------------------------
+ 2 files changed, 5 insertions(+), 52 deletions(-)
+
+diff --git a/ebtables.c b/ebtables.c
+index 62f1ba80063d8..f7dfccf4b2f31 100644
+--- a/ebtables.c
++++ b/ebtables.c
+@@ -528,12 +528,6 @@ void ebt_early_init_once()
+ 	ebt_iterate_targets(merge_target);
+ }
+ 
+-/* signal handler, installed when the option --concurrent is specified. */
+-static void sighandler(int signum)
+-{
+-	exit(-1);
+-}
+-
+ /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */
+ int do_command(int argc, char *argv[], int exec_style,
+                struct ebt_u_replace *replace_)
+@@ -1047,8 +1041,6 @@ big_iface_length:
+ 			strcpy(replace->filename, optarg);
+ 			break;
+ 		case 13 : /* concurrent */
+-			signal(SIGINT, sighandler);
+-			signal(SIGTERM, sighandler);
+ 			use_lockfd = 1;
+ 			break;
+ 		case 1 :
+diff --git a/libebtc.c b/libebtc.c
+index 74830ecf2e91b..c0ff8ccfa66db 100644
+--- a/libebtc.c
++++ b/libebtc.c
+@@ -31,6 +31,7 @@
+ #include "include/ethernetdb.h"
+ #include <unistd.h>
+ #include <fcntl.h>
++#include <sys/file.h>
+ #include <sys/wait.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+@@ -137,58 +138,18 @@ void ebt_list_extensions()
+ #define LOCKDIR "/var/lib/ebtables"
+ #define LOCKFILE LOCKDIR"/lock"
+ #endif
+-static int lockfd = -1, locked;
+ int use_lockfd;
+ /* Returns 0 on success, -1 when the file is locked by another process
+  * or -2 on any other error. */
+ static int lock_file()
+ {
+-	int try = 0;
+-	int ret = 0;
+-	sigset_t sigset;
+-
+-tryagain:
+-	/* the SIGINT handler will call unlock_file. To make sure the state
+-	 * of the variable locked is correct, we need to temporarily mask the
+-	 * SIGINT interrupt. */
+-	sigemptyset(&sigset);
+-	sigaddset(&sigset, SIGINT);
+-	sigprocmask(SIG_BLOCK, &sigset, NULL);
+-	lockfd = open(LOCKFILE, O_CREAT | O_EXCL | O_WRONLY, 00600);
+-	if (lockfd < 0) {
+-		if (errno == EEXIST)
+-			ret = -1;
+-		else if (try == 1)
+-			ret = -2;
+-		else {
+-			if (mkdir(LOCKDIR, 00700))
+-				ret = -2;
+-			else {
+-				try = 1;
+-				goto tryagain;
+-			}
+-		}
+-	} else {
+-		close(lockfd);
+-		locked = 1;
+-	}
+-	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+-	return ret;
+-}
++	int fd = open(LOCKFILE, O_CREAT, 00600);
+ 
+-void unlock_file()
+-{
+-	if (locked) {
+-		remove(LOCKFILE);
+-		locked = 0;
+-	}
++	if (fd < 0)
++		return -2;
++	return flock(fd, LOCK_EX);
+ }
+ 
+-void __attribute__ ((destructor)) onexit()
+-{
+-	if (use_lockfd)
+-		unlock_file();
+-}
+ /* Get the table from the kernel or from a binary file
+  * init: 1 = ask the kernel for the initial contents of a table, i.e. the
+  *           way it looks when the table is insmod'ed
+-- 
+2.21.0
+
diff --git a/SOURCES/0013-Fix-locking-if-LOCKDIR-does-not-exist.patch b/SOURCES/0013-Fix-locking-if-LOCKDIR-does-not-exist.patch
new file mode 100644
index 0000000..4d5ca65
--- /dev/null
+++ b/SOURCES/0013-Fix-locking-if-LOCKDIR-does-not-exist.patch
@@ -0,0 +1,46 @@
+From b3d4dbcbfe2986711492634c193f32db14f06a22 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Mon, 15 Jan 2018 16:27:31 +0100
+Subject: [PATCH] Fix locking if LOCKDIR does not exist
+
+The previous conversion to using flock() missed a crucial bit of code
+which tries to create LOCKDIR once in case opening the lock failed -
+This patch reestablishes the old behaviour.
+
+Reported-by: Tangchen (UVP) <tang.chen@huawei.com>
+Fixes: 6a826591878db ("Use flock() for --concurrent option")
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ libebtc.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/libebtc.c b/libebtc.c
+index c0ff8ccfa66db..d47424872dc51 100644
+--- a/libebtc.c
++++ b/libebtc.c
+@@ -143,10 +143,16 @@ int use_lockfd;
+  * or -2 on any other error. */
+ static int lock_file()
+ {
+-	int fd = open(LOCKFILE, O_CREAT, 00600);
+-
+-	if (fd < 0)
+-		return -2;
++	int fd, try = 0;
++
++retry:
++	fd = open(LOCKFILE, O_CREAT, 00600);
++	if (fd < 0) {
++		if (try == 1 || mkdir(LOCKDIR, 00700))
++			return -2;
++		try = 1;
++		goto retry;
++	}
+ 	return flock(fd, LOCK_EX);
+ }
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0014-include-sync-linux-netfilter_bridge-ebt_ip.h-with-ke.patch b/SOURCES/0014-include-sync-linux-netfilter_bridge-ebt_ip.h-with-ke.patch
new file mode 100644
index 0000000..103e78f
--- /dev/null
+++ b/SOURCES/0014-include-sync-linux-netfilter_bridge-ebt_ip.h-with-ke.patch
@@ -0,0 +1,54 @@
+From e3335b04db67142173124e28914b4fc5db2cfc38 Mon Sep 17 00:00:00 2001
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 4 Mar 2018 09:28:55 +0100
+Subject: [PATCH] include: sync linux/netfilter_bridge/ebt_ip.h with kernel
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ include/linux/netfilter_bridge/ebt_ip.h | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h
+index c4bbc41b0ea47..46d6261370b0c 100644
+--- a/include/linux/netfilter_bridge/ebt_ip.h
++++ b/include/linux/netfilter_bridge/ebt_ip.h
+@@ -1,3 +1,4 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+ /*
+  *  ebt_ip
+  *
+@@ -23,8 +24,10 @@
+ #define EBT_IP_PROTO 0x08
+ #define EBT_IP_SPORT 0x10
+ #define EBT_IP_DPORT 0x20
++#define EBT_IP_ICMP 0x40
++#define EBT_IP_IGMP 0x80
+ #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
+- EBT_IP_SPORT | EBT_IP_DPORT )
++		     EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
+ #define EBT_IP_MATCH "ip"
+ 
+ /* the same values are used for the invflags */
+@@ -37,8 +40,15 @@ struct ebt_ip_info {
+ 	__u8  protocol;
+ 	__u8  bitmask;
+ 	__u8  invflags;
+-	__u16 sport[2];
+-	__u16 dport[2];
++	union {
++		__u16 sport[2];
++		__u8 icmp_type[2];
++		__u8 igmp_type[2];
++	};
++	union {
++		__u16 dport[2];
++		__u8 icmp_code[2];
++	};
+ };
+ 
+ #endif
+-- 
+2.21.0
+
diff --git a/SOURCES/0015-Move-ICMP-type-handling-functions-from-ebt_ip6-to-us.patch b/SOURCES/0015-Move-ICMP-type-handling-functions-from-ebt_ip6-to-us.patch
new file mode 100644
index 0000000..7ef7b54
--- /dev/null
+++ b/SOURCES/0015-Move-ICMP-type-handling-functions-from-ebt_ip6-to-us.patch
@@ -0,0 +1,464 @@
+From 67de7ef4ab4d3042f8f24f7f5ef20d5711e6820b Mon Sep 17 00:00:00 2001
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 4 Mar 2018 09:28:56 +0100
+Subject: [PATCH] Move ICMP type handling functions from ebt_ip6 to
+ useful_functions.c
+
+Allow using these functions for ebt_ip as well.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_ip6.c | 165 +++----------------------------------------
+ include/ebtables_u.h |  17 ++++-
+ useful_functions.c   | 151 ++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 174 insertions(+), 159 deletions(-)
+
+diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c
+index dd48547b0010b..347797b4afe18 100644
+--- a/extensions/ebt_ip6.c
++++ b/extensions/ebt_ip6.c
+@@ -11,9 +11,6 @@
+  *
+  */
+ 
+-#include <errno.h>
+-#include <inttypes.h>
+-#include <limits.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -51,13 +48,7 @@ static const struct option opts[] =
+ };
+ 
+ 
+-struct icmpv6_names {
+-	const char *name;
+-	uint8_t type;
+-	uint8_t code_min, code_max;
+-};
+-
+-static const struct icmpv6_names icmpv6_codes[] = {
++static const struct ebt_icmp_names icmpv6_codes[] = {
+ 	{ "destination-unreachable", 1, 0, 0xFF },
+ 	{ "no-route", 1, 0, 0 },
+ 	{ "communication-prohibited", 1, 1, 1 },
+@@ -141,97 +132,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
+ 	free(buffer);
+ }
+ 
+-static char*
+-parse_num(const char *str, long min, long max, long *num)
+-{
+-	char *end;
+-
+-	errno = 0;
+-	*num = strtol(str, &end, 10);
+-	if (errno && (*num == LONG_MIN || *num == LONG_MAX)) {
+-		ebt_print_error("Invalid number %s: %s", str, strerror(errno));
+-		return NULL;
+-	}
+-	if (min <= max) {
+-		if (*num > max || *num < min) {
+-			ebt_print_error("Value %ld out of range (%ld, %ld)", *num, min, max);
+-			return NULL;
+-		}
+-	}
+-	if (*num == 0 && str == end)
+-		return NULL;
+-	return end;
+-}
+-
+-static char *
+-parse_range(const char *str, long min, long max, long num[])
+-{
+-	char *next;
+-
+-	next = parse_num(str, min, max, num);
+-	if (next == NULL)
+-		return NULL;
+-	if (next && *next == ':')
+-		next = parse_num(next+1, min, max, &num[1]);
+-	else
+-		num[1] = num[0];
+-	return next;
+-}
+-
+-static int
+-parse_icmpv6(const char *icmpv6type, uint8_t type[], uint8_t code[])
+-{
+-	static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
+-	unsigned int match = limit;
+-	unsigned int i;
+-	long number[2];
+-
+-	for (i = 0; i < limit; i++) {
+-		if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)))
+-			continue;
+-		if (match != limit)
+-			ebt_print_error("Ambiguous ICMPv6 type `%s':"
+-					" `%s' or `%s'?",
+-					icmpv6type, icmpv6_codes[match].name,
+-					icmpv6_codes[i].name);
+-		match = i;
+-	}
+-
+-	if (match < limit) {
+-		type[0] = type[1] = icmpv6_codes[match].type;
+-		code[0] = icmpv6_codes[match].code_min;
+-		code[1] = icmpv6_codes[match].code_max;
+-	} else {
+-		char *next = parse_range(icmpv6type, 0, 255, number);
+-		if (!next) {
+-			ebt_print_error("Unknown ICMPv6 type `%s'",
+-							icmpv6type);
+-			return -1;
+-		}
+-		type[0] = (uint8_t) number[0];
+-		type[1] = (uint8_t) number[1];
+-		switch (*next) {
+-		case 0:
+-			code[0] = 0;
+-			code[1] = 255;
+-			return 0;
+-		case '/':
+-			next = parse_range(next+1, 0, 255, number);
+-			code[0] = (uint8_t) number[0];
+-			code[1] = (uint8_t) number[1];
+-			if (next == NULL)
+-				return -1;
+-			if (next && *next == 0)
+-				return 0;
+-		/* fallthrough */
+-		default:
+-			ebt_print_error("unknown character %c", *next);
+-			return -1;
+-		}
+-	}
+-	return 0;
+-}
+-
+ static void print_port_range(uint16_t *ports)
+ {
+ 	if (ports[0] == ports[1])
+@@ -240,58 +140,6 @@ static void print_port_range(uint16_t *ports)
+ 		printf("%d:%d ", ports[0], ports[1]);
+ }
+ 
+-static void print_icmp_code(uint8_t *code)
+-{
+-	if (code[0] == code[1])
+-		printf("/%"PRIu8 " ", code[0]);
+-	else
+-		printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
+-}
+-
+-static void print_icmp_type(uint8_t *type, uint8_t *code)
+-{
+-	unsigned int i;
+-
+-	if (type[0] != type[1]) {
+-		printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
+-		print_icmp_code(code);
+-		return;
+-	}
+-
+-	for (i = 0; i < ARRAY_SIZE(icmpv6_codes); i++) {
+-		if (icmpv6_codes[i].type != type[0])
+-			continue;
+-
+-		if (icmpv6_codes[i].code_min == code[0] &&
+-		    icmpv6_codes[i].code_max == code[1]) {
+-			printf("%s ", icmpv6_codes[i].name);
+-			return;
+-		}
+-	}
+-	printf("%"PRIu8, type[0]);
+-	print_icmp_code(code);
+-}
+-
+-static void print_icmpv6types(void)
+-{
+-	unsigned int i;
+-        printf("Valid ICMPv6 Types:");
+-
+-	for (i=0; i < ARRAY_SIZE(icmpv6_codes); i++) {
+-		if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
+-			if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
+-			    && (icmpv6_codes[i].code_max
+-			        == icmpv6_codes[i-1].code_max))
+-				printf(" (%s)", icmpv6_codes[i].name);
+-			else
+-				printf("\n   %s", icmpv6_codes[i].name);
+-		}
+-		else
+-			printf("\n%s", icmpv6_codes[i].name);
+-	}
+-	printf("\n");
+-}
+-
+ static void print_help()
+ {
+ 	printf(
+@@ -303,7 +151,9 @@ static void print_help()
+ "--ip6-sport  [!] port[:port]   : tcp/udp source port or port range\n"
+ "--ip6-dport  [!] port[:port]   : tcp/udp destination port or port range\n"
+ "--ip6-icmp-type [!] type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n");
+-print_icmpv6types();
++
++	printf("\nValid ICMPv6 Types:\n");
++	ebt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes));
+ }
+ 
+ static void init(struct ebt_entry_match *match)
+@@ -374,7 +224,9 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ 		ipinfo->bitmask |= EBT_IP6_ICMP6;
+ 		if (ebt_check_inverse2(optarg))
+ 			ipinfo->invflags |= EBT_IP6_ICMP6;
+-		if (parse_icmpv6(optarg, ipinfo->icmpv6_type, ipinfo->icmpv6_code))
++		if (ebt_parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
++				   optarg, ipinfo->icmpv6_type,
++				   ipinfo->icmpv6_code))
+ 			return 0;
+ 		break;
+ 
+@@ -493,7 +345,8 @@ static void print(const struct ebt_u_entry *entry,
+ 		printf("--ip6-icmp-type ");
+ 		if (ipinfo->invflags & EBT_IP6_ICMP6)
+ 			printf("! ");
+-		print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
++		ebt_print_icmp_type(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
++				    ipinfo->icmpv6_type, ipinfo->icmpv6_code);
+ 	}
+ }
+ 
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index 35a5bcc54c865..17afa9487f5ad 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -222,6 +222,15 @@ struct ebt_u_target
+ 	struct ebt_u_target *next;
+ };
+ 
++
++struct ebt_icmp_names {
++	const char *name;
++	uint8_t type;
++	uint8_t code_min, code_max;
++};
++
++
++
+ /* libebtc.c */
+ 
+ extern struct ebt_u_table *ebt_tables;
+@@ -300,11 +309,17 @@ void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
+ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask);
+ void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk);
+ char *ebt_mask_to_dotted(uint32_t mask);
+-void ebt_parse_ip6_address(char *address, struct in6_addr *addr, 
++void ebt_parse_ip6_address(char *address, struct in6_addr *addr,
+ 						   struct in6_addr *msk);
+ char *ebt_ip6_to_numeric(const struct in6_addr *addrp);
+ char *ebt_ip6_mask_to_string(const struct in6_addr *msk);
+ 
++int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
++		   const char *icmptype, uint8_t type[], uint8_t code[]);
++void ebt_print_icmp_type(const struct ebt_icmp_names *icmp_codes,
++			 size_t n_codes, uint8_t *type, uint8_t *code);
++void ebt_print_icmp_types(const struct ebt_icmp_names *icmp_codes,
++			  size_t n_codes);
+ 
+ int do_command(int argc, char *argv[], int exec_style,
+                struct ebt_u_replace *replace_);
+diff --git a/useful_functions.c b/useful_functions.c
+index d14cbe9dbdba1..8f54bae83fae8 100644
+--- a/useful_functions.c
++++ b/useful_functions.c
+@@ -24,6 +24,9 @@
+  */
+ #include "include/ebtables_u.h"
+ #include "include/ethernetdb.h"
++#include <errno.h>
++#include <inttypes.h>
++#include <limits.h>
+ #include <stdio.h>
+ #include <netinet/ether.h>
+ #include <string.h>
+@@ -34,6 +37,7 @@
+ #include <sys/socket.h>
+ #include <arpa/inet.h>
+ 
++
+ const unsigned char mac_type_unicast[ETH_ALEN] =   {0,0,0,0,0,0};
+ const unsigned char msk_type_unicast[ETH_ALEN] =   {1,0,0,0,0,0};
+ const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
+@@ -188,7 +192,7 @@ static int undot_ip(char *ip, unsigned char *ip2)
+ 			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;
+ 		p = q + 1;
+@@ -275,7 +279,7 @@ char *ebt_mask_to_dotted(uint32_t mask)
+ 		*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], 
++		sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
+ 		   ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
+ 		   ((unsigned char *)&mask)[3]);
+ 
+@@ -424,3 +428,146 @@ char *ebt_ip6_mask_to_string(const struct in6_addr *msk)
+ 		sprintf(buf, "/%s", ebt_ip6_to_numeric(msk));
+ 	return buf;
+ }
++
++static char*
++parse_num(const char *str, long min, long max, long *num)
++{
++	char *end;
++
++	errno = 0;
++	*num = strtol(str, &end, 10);
++	if (errno && (*num == LONG_MIN || *num == LONG_MAX)) {
++		ebt_print_error("Invalid number %s: %s", str, strerror(errno));
++		return NULL;
++	}
++	if (min <= max) {
++		if (*num > max || *num < min) {
++			ebt_print_error("Value %ld out of range (%ld, %ld)", *num, min, max);
++			return NULL;
++		}
++	}
++	if (*num == 0 && str == end)
++		return NULL;
++	return end;
++}
++
++static char *
++parse_range(const char *str, long min, long max, long num[])
++{
++	char *next;
++
++	next = parse_num(str, min, max, num);
++	if (next == NULL)
++		return NULL;
++	if (next && *next == ':')
++		next = parse_num(next+1, min, max, &num[1]);
++	else
++		num[1] = num[0];
++	return next;
++}
++
++int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
++		   const char *icmptype, uint8_t type[], uint8_t code[])
++{
++	unsigned int match = n_codes;
++	unsigned int i;
++	long number[2];
++
++	for (i = 0; i < n_codes; i++) {
++		if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype)))
++			continue;
++		if (match != n_codes)
++			ebt_print_error("Ambiguous ICMP type `%s':"
++					" `%s' or `%s'?",
++					icmptype, icmp_codes[match].name,
++					icmp_codes[i].name);
++		match = i;
++	}
++
++	if (match < n_codes) {
++		type[0] = type[1] = icmp_codes[match].type;
++		code[0] = icmp_codes[match].code_min;
++		code[1] = icmp_codes[match].code_max;
++	} else {
++		char *next = parse_range(icmptype, 0, 255, number);
++		if (!next) {
++			ebt_print_error("Unknown ICMP type `%s'",
++							icmptype);
++			return -1;
++		}
++		type[0] = (uint8_t) number[0];
++		type[1] = (uint8_t) number[1];
++		switch (*next) {
++		case 0:
++			code[0] = 0;
++			code[1] = 255;
++			return 0;
++		case '/':
++			next = parse_range(next+1, 0, 255, number);
++			code[0] = (uint8_t) number[0];
++			code[1] = (uint8_t) number[1];
++			if (next == NULL)
++				return -1;
++			if (next && *next == 0)
++				return 0;
++		/* fallthrough */
++		default:
++			ebt_print_error("unknown character %c", *next);
++			return -1;
++		}
++	}
++	return 0;
++}
++
++static void print_icmp_code(uint8_t *code)
++{
++	if (code[0] == code[1])
++		printf("/%"PRIu8 " ", code[0]);
++	else
++		printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
++}
++
++void ebt_print_icmp_type(const struct ebt_icmp_names *icmp_codes,
++			 size_t n_codes, uint8_t *type, uint8_t *code)
++{
++	unsigned int i;
++
++	if (type[0] != type[1]) {
++		printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
++		print_icmp_code(code);
++		return;
++	}
++
++	for (i = 0; i < n_codes; i++) {
++		if (icmp_codes[i].type != type[0])
++			continue;
++
++		if (icmp_codes[i].code_min == code[0] &&
++		    icmp_codes[i].code_max == code[1]) {
++			printf("%s ", icmp_codes[i].name);
++			return;
++		}
++	}
++	printf("%"PRIu8, type[0]);
++	print_icmp_code(code);
++}
++
++void ebt_print_icmp_types(const struct ebt_icmp_names *icmp_codes,
++			  size_t n_codes)
++{
++	unsigned int i;
++
++	for (i = 0; i < n_codes; i++) {
++		if (i && icmp_codes[i].type == icmp_codes[i-1].type) {
++			if (icmp_codes[i].code_min == icmp_codes[i-1].code_min
++			    && (icmp_codes[i].code_max
++			        == icmp_codes[i-1].code_max))
++				printf(" (%s)", icmp_codes[i].name);
++			else
++				printf("\n   %s", icmp_codes[i].name);
++		}
++		else
++			printf("\n%s", icmp_codes[i].name);
++	}
++	printf("\n");
++}
+-- 
+2.21.0
+
diff --git a/SOURCES/0016-ebt_ip-add-support-for-matching-ICMP-type-and-code.patch b/SOURCES/0016-ebt_ip-add-support-for-matching-ICMP-type-and-code.patch
new file mode 100644
index 0000000..98921b6
--- /dev/null
+++ b/SOURCES/0016-ebt_ip-add-support-for-matching-ICMP-type-and-code.patch
@@ -0,0 +1,180 @@
+From fca4a7f4d3242ff4ad58081e69bc70ba1f6c46a5 Mon Sep 17 00:00:00 2001
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 4 Mar 2018 09:28:57 +0100
+Subject: [PATCH] ebt_ip: add support for matching ICMP type and code
+
+We already have ICMPv6 type/code matches. This adds support for IPv4 ICMP
+matches in the same way.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_ip.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 94 insertions(+), 2 deletions(-)
+
+diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c
+index 59559feffa50b..42660d4564fbf 100644
+--- a/extensions/ebt_ip.c
++++ b/extensions/ebt_ip.c
+@@ -24,6 +24,7 @@
+ #define IP_PROTO  '4'
+ #define IP_SPORT  '5'
+ #define IP_DPORT  '6'
++#define IP_ICMP   '7'
+ 
+ static const struct option opts[] =
+ {
+@@ -38,9 +39,64 @@ static const struct option opts[] =
+ 	{ "ip-sport"            , required_argument, 0, IP_SPORT  },
+ 	{ "ip-destination-port" , required_argument, 0, IP_DPORT  },
+ 	{ "ip-dport"            , required_argument, 0, IP_DPORT  },
++	{ "ip-icmp-type"        , required_argument, 0, IP_ICMP   },
+ 	{ 0 }
+ };
+ 
++static const struct ebt_icmp_names icmp_codes[] = {
++	{ "echo-reply", 0, 0, 0xFF },
++	/* Alias */ { "pong", 0, 0, 0xFF },
++
++	{ "destination-unreachable", 3, 0, 0xFF },
++	{   "network-unreachable", 3, 0, 0 },
++	{   "host-unreachable", 3, 1, 1 },
++	{   "protocol-unreachable", 3, 2, 2 },
++	{   "port-unreachable", 3, 3, 3 },
++	{   "fragmentation-needed", 3, 4, 4 },
++	{   "source-route-failed", 3, 5, 5 },
++	{   "network-unknown", 3, 6, 6 },
++	{   "host-unknown", 3, 7, 7 },
++	{   "network-prohibited", 3, 9, 9 },
++	{   "host-prohibited", 3, 10, 10 },
++	{   "TOS-network-unreachable", 3, 11, 11 },
++	{   "TOS-host-unreachable", 3, 12, 12 },
++	{   "communication-prohibited", 3, 13, 13 },
++	{   "host-precedence-violation", 3, 14, 14 },
++	{   "precedence-cutoff", 3, 15, 15 },
++
++	{ "source-quench", 4, 0, 0xFF },
++
++	{ "redirect", 5, 0, 0xFF },
++	{   "network-redirect", 5, 0, 0 },
++	{   "host-redirect", 5, 1, 1 },
++	{   "TOS-network-redirect", 5, 2, 2 },
++	{   "TOS-host-redirect", 5, 3, 3 },
++
++	{ "echo-request", 8, 0, 0xFF },
++	/* Alias */ { "ping", 8, 0, 0xFF },
++
++	{ "router-advertisement", 9, 0, 0xFF },
++
++	{ "router-solicitation", 10, 0, 0xFF },
++
++	{ "time-exceeded", 11, 0, 0xFF },
++	/* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
++	{   "ttl-zero-during-transit", 11, 0, 0 },
++	{   "ttl-zero-during-reassembly", 11, 1, 1 },
++
++	{ "parameter-problem", 12, 0, 0xFF },
++	{   "ip-header-bad", 12, 0, 0 },
++	{   "required-option-missing", 12, 1, 1 },
++
++	{ "timestamp-request", 13, 0, 0xFF },
++
++	{ "timestamp-reply", 14, 0, 0xFF },
++
++	{ "address-mask-request", 17, 0, 0xFF },
++
++	{ "address-mask-reply", 18, 0, 0xFF }
++};
++
+ /* put the mask into 4 bytes */
+ /* transform a protocol and service name into a port number */
+ static uint16_t parse_port(const char *protocol, const char *name)
+@@ -105,7 +161,11 @@ static void print_help()
+ "--ip-tos    [!] tos           : ip tos specification\n"
+ "--ip-proto  [!] protocol      : ip protocol specification\n"
+ "--ip-sport  [!] port[:port]   : tcp/udp source port or port range\n"
+-"--ip-dport  [!] port[:port]   : tcp/udp destination port or port range\n");
++"--ip-dport  [!] port[:port]   : tcp/udp destination port or port range\n"
++"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n");
++
++	printf("\nValid ICMP Types:\n");
++	ebt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
+ }
+ 
+ static void init(struct ebt_entry_match *match)
+@@ -122,6 +182,7 @@ static void init(struct ebt_entry_match *match)
+ #define OPT_PROTO  0x08
+ #define OPT_SPORT  0x10
+ #define OPT_DPORT  0x20
++#define OPT_ICMP   0x40
+ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+    unsigned int *flags, struct ebt_entry_match **match)
+ {
+@@ -170,6 +231,16 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ 			parse_port_range(NULL, optarg, ipinfo->dport);
+ 		break;
+ 
++	case IP_ICMP:
++		ebt_check_option2(flags, OPT_ICMP);
++		ipinfo->bitmask |= EBT_IP_ICMP;
++		if (ebt_check_inverse2(optarg))
++			ipinfo->invflags |= EBT_IP_ICMP;
++		if (ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg,
++				   ipinfo->icmp_type, ipinfo->icmp_code))
++			return 0;
++		break;
++
+ 	case IP_myTOS:
+ 		ebt_check_option2(flags, OPT_TOS);
+ 		if (ebt_check_inverse2(optarg))
+@@ -219,10 +290,17 @@ static void final_check(const struct ebt_u_entry *entry,
+ 		(ipinfo->protocol!=IPPROTO_TCP &&
+ 		 ipinfo->protocol!=IPPROTO_UDP &&
+ 		 ipinfo->protocol!=IPPROTO_SCTP &&
+-		 ipinfo->protocol!=IPPROTO_DCCP)))
++		 ipinfo->protocol!=IPPROTO_DCCP))) {
+ 		ebt_print_error("For port filtering the IP protocol must be "
+ 				"either 6 (tcp), 17 (udp), 33 (dccp) or "
+ 				"132 (sctp)");
++	} else if ((ipinfo->bitmask & EBT_IP_ICMP) &&
++	         (!(ipinfo->bitmask & EBT_IP_PROTO) ||
++	            ipinfo->invflags & EBT_IP_PROTO ||
++	            ipinfo->protocol != IPPROTO_ICMP)) {
++		ebt_print_error("For ICMP filtering the IP protocol must be "
++				"1 (icmp)");
++	}
+ }
+ 
+ static void print(const struct ebt_u_entry *entry,
+@@ -280,6 +358,13 @@ static void print(const struct ebt_u_entry *entry,
+ 			printf("! ");
+ 		print_port_range(ipinfo->dport);
+ 	}
++	if (ipinfo->bitmask & EBT_IP_ICMP) {
++		printf("--ip-icmp-type ");
++		if (ipinfo->invflags & EBT_IP_ICMP)
++			printf("! ");
++		ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
++				    ipinfo->icmp_type, ipinfo->icmp_code);
++	}
+ }
+ 
+ static int compare(const struct ebt_entry_match *m1,
+@@ -322,6 +407,13 @@ static int compare(const struct ebt_entry_match *m1,
+ 		   ipinfo1->dport[1] != ipinfo2->dport[1])
+ 			return 0;
+ 	}
++	if (ipinfo1->bitmask & EBT_IP_ICMP) {
++		if (ipinfo1->icmp_type[0] != ipinfo2->icmp_type[0] ||
++		    ipinfo1->icmp_type[1] != ipinfo2->icmp_type[1] ||
++		    ipinfo1->icmp_code[0] != ipinfo2->icmp_code[0] ||
++		    ipinfo1->icmp_code[1] != ipinfo2->icmp_code[1])
++			return 0;
++	}
+ 	return 1;
+ }
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0017-ebt_ip-add-support-for-matching-IGMP-type.patch b/SOURCES/0017-ebt_ip-add-support-for-matching-IGMP-type.patch
new file mode 100644
index 0000000..9a1cd74
--- /dev/null
+++ b/SOURCES/0017-ebt_ip-add-support-for-matching-IGMP-type.patch
@@ -0,0 +1,206 @@
+From 4808d6bfc74e9cf79609245c0ff3c6e079249ce5 Mon Sep 17 00:00:00 2001
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 4 Mar 2018 09:28:58 +0100
+Subject: [PATCH] ebt_ip: add support for matching IGMP type
+
+We already have ICMPv6 type/code matches (which can be used to distinguish
+different types of MLD packets). Add support for IPv4 IGMP matches in the
+same way.
+
+To reuse as much code as possible, the ICMP type/code handling functions
+are extended to allow passing a NULL code range.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_ip.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
+ useful_functions.c  | 35 ++++++++++++++++++++++-------------
+ 2 files changed, 65 insertions(+), 14 deletions(-)
+
+diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c
+index 42660d4564fbf..1ffdb95f156df 100644
+--- a/extensions/ebt_ip.c
++++ b/extensions/ebt_ip.c
+@@ -25,6 +25,7 @@
+ #define IP_SPORT  '5'
+ #define IP_DPORT  '6'
+ #define IP_ICMP   '7'
++#define IP_IGMP   '8'
+ 
+ static const struct option opts[] =
+ {
+@@ -40,6 +41,7 @@ static const struct option opts[] =
+ 	{ "ip-destination-port" , required_argument, 0, IP_DPORT  },
+ 	{ "ip-dport"            , required_argument, 0, IP_DPORT  },
+ 	{ "ip-icmp-type"        , required_argument, 0, IP_ICMP   },
++	{ "ip-igmp-type"        , required_argument, 0, IP_IGMP   },
+ 	{ 0 }
+ };
+ 
+@@ -97,6 +99,14 @@ static const struct ebt_icmp_names icmp_codes[] = {
+ 	{ "address-mask-reply", 18, 0, 0xFF }
+ };
+ 
++static const struct ebt_icmp_names igmp_types[] = {
++	{ "membership-query", 0x11 },
++	{ "membership-report-v1", 0x12 },
++	{ "membership-report-v2", 0x16 },
++	{ "leave-group", 0x17 },
++	{ "membership-report-v3", 0x22 },
++};
++
+ /* put the mask into 4 bytes */
+ /* transform a protocol and service name into a port number */
+ static uint16_t parse_port(const char *protocol, const char *name)
+@@ -162,10 +172,13 @@ static void print_help()
+ "--ip-proto  [!] protocol      : ip protocol specification\n"
+ "--ip-sport  [!] port[:port]   : tcp/udp source port or port range\n"
+ "--ip-dport  [!] port[:port]   : tcp/udp destination port or port range\n"
+-"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n");
++"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n"
++"--ip-igmp-type [!] type[:type]               : igmp type or type range\n");
+ 
+ 	printf("\nValid ICMP Types:\n");
+ 	ebt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
++	printf("\nValid IGMP Types:\n");
++	ebt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
+ }
+ 
+ static void init(struct ebt_entry_match *match)
+@@ -183,6 +196,7 @@ static void init(struct ebt_entry_match *match)
+ #define OPT_SPORT  0x10
+ #define OPT_DPORT  0x20
+ #define OPT_ICMP   0x40
++#define OPT_IGMP   0x80
+ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+    unsigned int *flags, struct ebt_entry_match **match)
+ {
+@@ -241,6 +255,16 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ 			return 0;
+ 		break;
+ 
++	case IP_IGMP:
++		ebt_check_option2(flags, OPT_IGMP);
++		ipinfo->bitmask |= EBT_IP_IGMP;
++		if (ebt_check_inverse2(optarg))
++			ipinfo->invflags |= EBT_IP_IGMP;
++		if (ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg,
++				   ipinfo->igmp_type, NULL))
++			return 0;
++		break;
++
+ 	case IP_myTOS:
+ 		ebt_check_option2(flags, OPT_TOS);
+ 		if (ebt_check_inverse2(optarg))
+@@ -300,6 +324,12 @@ static void final_check(const struct ebt_u_entry *entry,
+ 	            ipinfo->protocol != IPPROTO_ICMP)) {
+ 		ebt_print_error("For ICMP filtering the IP protocol must be "
+ 				"1 (icmp)");
++	} else if ((ipinfo->bitmask & EBT_IP_IGMP) &&
++	         (!(ipinfo->bitmask & EBT_IP_PROTO) ||
++	            ipinfo->invflags & EBT_IP_PROTO ||
++	            ipinfo->protocol != IPPROTO_IGMP)) {
++		ebt_print_error("For IGMP filtering the IP protocol must be "
++				"2 (igmp)");
+ 	}
+ }
+ 
+@@ -365,6 +395,13 @@ static void print(const struct ebt_u_entry *entry,
+ 		ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
+ 				    ipinfo->icmp_type, ipinfo->icmp_code);
+ 	}
++	if (ipinfo->bitmask & EBT_IP_IGMP) {
++		printf("--ip-igmp-type ");
++		if (ipinfo->invflags & EBT_IP_IGMP)
++			printf("! ");
++		ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
++				    ipinfo->igmp_type, NULL);
++	}
+ }
+ 
+ static int compare(const struct ebt_entry_match *m1,
+@@ -414,6 +451,11 @@ static int compare(const struct ebt_entry_match *m1,
+ 		    ipinfo1->icmp_code[1] != ipinfo2->icmp_code[1])
+ 			return 0;
+ 	}
++	if (ipinfo1->bitmask & EBT_IP_IGMP) {
++		if (ipinfo1->igmp_type[0] != ipinfo2->igmp_type[0] ||
++		    ipinfo1->igmp_type[1] != ipinfo2->igmp_type[1])
++			return 0;
++	}
+ 	return 1;
+ }
+ 
+diff --git a/useful_functions.c b/useful_functions.c
+index 8f54bae83fae8..8a34f820f230b 100644
+--- a/useful_functions.c
++++ b/useful_functions.c
+@@ -486,8 +486,10 @@ int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
+ 
+ 	if (match < n_codes) {
+ 		type[0] = type[1] = icmp_codes[match].type;
+-		code[0] = icmp_codes[match].code_min;
+-		code[1] = icmp_codes[match].code_max;
++		if (code) {
++			code[0] = icmp_codes[match].code_min;
++			code[1] = icmp_codes[match].code_max;
++		}
+ 	} else {
+ 		char *next = parse_range(icmptype, 0, 255, number);
+ 		if (!next) {
+@@ -499,17 +501,21 @@ int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
+ 		type[1] = (uint8_t) number[1];
+ 		switch (*next) {
+ 		case 0:
+-			code[0] = 0;
+-			code[1] = 255;
++			if (code) {
++				code[0] = 0;
++				code[1] = 255;
++			}
+ 			return 0;
+ 		case '/':
+-			next = parse_range(next+1, 0, 255, number);
+-			code[0] = (uint8_t) number[0];
+-			code[1] = (uint8_t) number[1];
+-			if (next == NULL)
+-				return -1;
+-			if (next && *next == 0)
+-				return 0;
++			if (code) {
++				next = parse_range(next+1, 0, 255, number);
++				code[0] = (uint8_t) number[0];
++				code[1] = (uint8_t) number[1];
++				if (next == NULL)
++					return -1;
++				if (next && *next == 0)
++					return 0;
++			}
+ 		/* fallthrough */
+ 		default:
+ 			ebt_print_error("unknown character %c", *next);
+@@ -521,6 +527,9 @@ int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
+ 
+ static void print_icmp_code(uint8_t *code)
+ {
++	if (!code)
++		return;
++
+ 	if (code[0] == code[1])
+ 		printf("/%"PRIu8 " ", code[0]);
+ 	else
+@@ -542,8 +551,8 @@ void ebt_print_icmp_type(const struct ebt_icmp_names *icmp_codes,
+ 		if (icmp_codes[i].type != type[0])
+ 			continue;
+ 
+-		if (icmp_codes[i].code_min == code[0] &&
+-		    icmp_codes[i].code_max == code[1]) {
++		if (!code || (icmp_codes[i].code_min == code[0] &&
++			      icmp_codes[i].code_max == code[1])) {
+ 			printf("%s ", icmp_codes[i].name);
+ 			return;
+ 		}
+-- 
+2.21.0
+
diff --git a/SOURCES/0018-extensions-Add-string-filter-to-ebtables.patch b/SOURCES/0018-extensions-Add-string-filter-to-ebtables.patch
new file mode 100644
index 0000000..d9ab70e
--- /dev/null
+++ b/SOURCES/0018-extensions-Add-string-filter-to-ebtables.patch
@@ -0,0 +1,497 @@
+From 746a409113ab837c55b8cfaf819c7905c8f9e295 Mon Sep 17 00:00:00 2001
+From: Bernie Harris <bernie.harris@alliedtelesis.co.nz>
+Date: Wed, 21 Mar 2018 15:42:29 +1300
+Subject: [PATCH] extensions: Add string filter to ebtables
+
+This patch is part of a proposal to add a string filter to
+ebtables, which would be similar to the string filter in
+iptables.
+
+Like iptables, the ebtables filter uses the xt_string module,
+however some modifications have been made for this to work
+correctly.
+
+Currently ebtables assumes that the revision number of all match
+modules is 0. The xt_string module doesn't register a match with
+revision 0 so the solution is to modify ebtables to allow
+extensions to specify a revision number, similar to iptables.
+This gets passed down to the kernel, which is then able to find
+the match module correctly.
+
+Signed-off-by: Bernie Harris <bernie.harris@alliedtelesis.co.nz>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ ebtables.8              |  20 +++
+ extensions/Makefile     |   2 +-
+ extensions/ebt_string.c | 319 ++++++++++++++++++++++++++++++++++++++++
+ include/ebtables.h      |  16 +-
+ include/ebtables_u.h    |   1 +
+ libebtc.c               |   6 +-
+ 6 files changed, 359 insertions(+), 5 deletions(-)
+ create mode 100644 extensions/ebt_string.c
+
+diff --git a/ebtables.8 b/ebtables.8
+index 45a88b2347de6..00c4562d20036 100644
+--- a/ebtables.8
++++ b/ebtables.8
+@@ -810,6 +810,26 @@ The hello time timer (0-65535) range.
+ .TP
+ .BR "--stp-forward-delay " "[!] [\fIdelay\fP][:\fIdelay\fP]"
+ The forward delay timer (0-65535) range.
++.SS string
++This module matches on a given string using some pattern matching strategy.
++.TP
++.BR "--string-algo " "\fIalgorithm\fP"
++The pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
++.TP
++.BR "--string-from " "\fIoffset\fP"
++The lowest offset from which a match can start. (default: 0)
++.TP
++.BR "--string-to " "\fIoffset\fP"
++The highest offset from which a match can start. (default: size of frame)
++.TP
++.BR "--string " "[!] \fIpattern\fP"
++Matches the given pattern.
++.TP
++.BR "--string-hex " "[!] \fIpattern\fP"
++Matches the given pattern in hex notation, e.g. '|0D 0A|', '|0D0A|', 'www|09|netfilter|03|org|00|'
++.TP
++.BR "--string-icase"
++Ignore case when searching.
+ .SS vlan
+ Specify 802.1Q Tag Control Information fields.
+ The protocol must be specified as
+diff --git a/extensions/Makefile b/extensions/Makefile
+index b3548e81eca85..60a70a2298357 100644
+--- a/extensions/Makefile
++++ b/extensions/Makefile
+@@ -1,7 +1,7 @@
+ #! /usr/bin/make
+ 
+ EXT_FUNC+=802_3 nat arp arpreply ip ip6 standard log redirect vlan mark_m mark \
+-          pkttype stp among limit ulog nflog
++          pkttype stp among limit ulog nflog string
+ 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)
+diff --git a/extensions/ebt_string.c b/extensions/ebt_string.c
+new file mode 100644
+index 0000000000000..793f5df312f10
+--- /dev/null
++++ b/extensions/ebt_string.c
+@@ -0,0 +1,319 @@
++/* ebt_string
++ *
++ * Author:
++ * Bernie Harris <bernie.harris@alliedtelesis.co.nz>
++ *
++ * February, 2018
++ *
++ * Based on:
++ *  libxt_string.c, Copyright (C) 2000 Emmanuel Roger  <winfield@freegates.be>
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdint.h>
++#include <getopt.h>
++#include <netdb.h>
++#include <ctype.h>
++#include "../include/ebtables_u.h"
++#include <linux/if_packet.h>
++#include <linux/netfilter/xt_string.h>
++
++#define STRING_FROM  '1'
++#define STRING_TO    '2'
++#define STRING_ALGO  '3'
++#define STRING_ICASE '4'
++#define STRING       '5'
++#define STRING_HEX   '6'
++#define OPT_STRING_FROM  (1 << 0)
++#define OPT_STRING_TO    (1 << 1)
++#define OPT_STRING_ALGO  (1 << 2)
++#define OPT_STRING_ICASE (1 << 3)
++#define OPT_STRING       (1 << 4)
++#define OPT_STRING_HEX   (1 << 5)
++
++static const struct option opts[] =
++{
++	{ "string-from"             , required_argument, 0, STRING_FROM },
++	{ "string-to"               , required_argument, 0, STRING_TO },
++	{ "string-algo"             , required_argument, 0, STRING_ALGO },
++	{ "string-icase"            , no_argument,       0, STRING_ICASE },
++	{ "string"                  , required_argument, 0, STRING },
++	{ "string-hex"              , required_argument, 0, STRING_HEX },
++	{ 0 }
++};
++
++static void print_help()
++{
++	printf(
++"string options:\n"
++"--string-from offset    : Offset to start searching from (default: 0)\n"
++"--string-to   offset    : Offset to stop searching (default: packet size)\n"
++"--string-algo algorithm : Algorithm (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)\n"
++"--string-icase          : Ignore case when searching\n"
++"--string     [!] string : Match a string in a packet\n"
++"--string-hex [!] string : Match a hex string in a packet, e.g. |0D 0A|, |0D0A|, netfilter|03|org\n");
++}
++
++static void init(struct ebt_entry_match *match)
++{
++	struct xt_string_info *info = (struct xt_string_info *)match->data;
++
++	info->to_offset = UINT16_MAX;
++}
++
++static void parse_string(const char *s, struct xt_string_info *info)
++{
++	/* xt_string does not need \0 at the end of the pattern */
++	if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
++		strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
++		info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
++		return;
++	}
++	ebt_print_error2("STRING too long \"%s\"", s);
++}
++
++static void parse_hex_string(const char *s, struct xt_string_info *info)
++{
++	int i=0, slen, sindex=0, schar;
++	short hex_f = 0, literal_f = 0;
++	char hextmp[3];
++
++	slen = strlen(s);
++
++	if (slen == 0) {
++		ebt_print_error2("STRING must contain at least one char");
++	}
++
++	while (i < slen) {
++		if (s[i] == '\\' && !hex_f) {
++			literal_f = 1;
++		} else if (s[i] == '\\') {
++			ebt_print_error2("Cannot include literals in hex data");
++		} else if (s[i] == '|') {
++			if (hex_f)
++				hex_f = 0;
++			else {
++				hex_f = 1;
++				/* get past any initial whitespace just after the '|' */
++				while (s[i+1] == ' ')
++					i++;
++			}
++			if (i+1 >= slen)
++				break;
++			else
++				i++;  /* advance to the next character */
++		}
++
++		if (literal_f) {
++			if (i+1 >= slen) {
++				ebt_print_error2("Bad literal placement at end of string");
++			}
++			info->pattern[sindex] = s[i+1];
++			i += 2;  /* skip over literal char */
++			literal_f = 0;
++		} else if (hex_f) {
++			if (i+1 >= slen) {
++				ebt_print_error2("Odd number of hex digits");
++			}
++			if (i+2 >= slen) {
++				/* must end with a "|" */
++				ebt_print_error2("Invalid hex block");
++			}
++			if (! isxdigit(s[i])) /* check for valid hex char */
++				ebt_print_error2("Invalid hex char '%c'", s[i]);
++			if (! isxdigit(s[i+1])) /* check for valid hex char */
++				ebt_print_error2("Invalid hex char '%c'", s[i+1]);
++			hextmp[0] = s[i];
++			hextmp[1] = s[i+1];
++			hextmp[2] = '\0';
++			if (! sscanf(hextmp, "%x", &schar))
++				ebt_print_error2("Invalid hex char `%c'", s[i]);
++			info->pattern[sindex] = (char) schar;
++			if (s[i+2] == ' ')
++				i += 3;  /* spaces included in the hex block */
++			else
++				i += 2;
++		} else {  /* the char is not part of hex data, so just copy */
++			info->pattern[sindex] = s[i];
++			i++;
++		}
++		if (sindex > XT_STRING_MAX_PATTERN_SIZE)
++			ebt_print_error2("STRING too long \"%s\"", s);
++		sindex++;
++	}
++	info->patlen = sindex;
++}
++
++static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
++		 unsigned int *flags, struct ebt_entry_match **match)
++{
++	struct xt_string_info *info = (struct xt_string_info *)(*match)->data;
++	int i;
++	int input_string_length = 0;
++	char buf[3] = { 0 };
++
++	switch (c) {
++	case STRING_FROM:
++		ebt_check_option2(flags, OPT_STRING_FROM);
++		if (ebt_check_inverse2(optarg))
++			ebt_print_error2("Unexpected `!' after --string-from");
++		info->from_offset = (__u16)strtoul(optarg, NULL, 10);
++		break;
++	case STRING_TO:
++		ebt_check_option2(flags, OPT_STRING_TO);
++		if (ebt_check_inverse2(optarg))
++			ebt_print_error2("Unexpected `!' after --string-to");
++		info->to_offset = (__u16)strtoul(optarg, NULL, 10);
++		break;
++	case STRING_ALGO:
++		ebt_check_option2(flags, OPT_STRING_ALGO);
++		if (ebt_check_inverse2(optarg))
++			ebt_print_error2("Unexpected `!' after --string-algo");
++		strncpy(info->algo, optarg, XT_STRING_MAX_ALGO_NAME_SIZE);
++		break;
++	case STRING_ICASE:
++		ebt_check_option2(flags, OPT_STRING_ICASE);
++		if (ebt_check_inverse2(optarg))
++			ebt_print_error2("Unexpected `!' after --string-icase");
++		info->u.v1.flags |= XT_STRING_FLAG_IGNORECASE;
++		break;
++	case STRING:
++		ebt_check_option2(flags, OPT_STRING);
++		parse_string(optarg, info);
++		if (ebt_check_inverse2(optarg)) {
++			info->u.v1.flags |= XT_STRING_FLAG_INVERT;
++		}
++		break;
++	case STRING_HEX:
++		ebt_check_option2(flags, OPT_STRING_HEX);
++		parse_hex_string(optarg, info);
++		if (ebt_check_inverse2(optarg)) {
++			info->u.v1.flags |= XT_STRING_FLAG_INVERT;
++		}
++		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 hookmask, unsigned int time)
++{
++	struct xt_string_info *info = (struct xt_string_info *)match->data;
++
++	if (info->to_offset < info->from_offset) {
++		ebt_print_error2("'to' offset should not be less than 'from' "
++				 "offset");
++	}
++}
++
++/* Test to see if the string contains non-printable chars or quotes */
++static unsigned short int is_hex_string(const char *str,
++					const unsigned short int len)
++{
++	unsigned int i;
++	for (i=0; i < len; i++) {
++		if (! isprint(str[i])) {
++			/* string contains at least one non-printable char */
++			return 1;
++		}
++	}
++	/* use hex output if the last char is a "\" */
++	if (str[len-1] == '\\')
++		return 1;
++	return 0;
++}
++
++/* Print string with "|" chars included as one would pass to --string-hex */
++static void print_hex_string(const char *str, const unsigned short int len)
++{
++	unsigned int i;
++	/* start hex block */
++	printf("\"|");
++	for (i=0; i < len; i++)
++		printf("%02x", (unsigned char)str[i]);
++	/* close hex block */
++	printf("|\" ");
++}
++
++static void print_string(const char *str, const unsigned short int len)
++{
++	unsigned int i;
++	printf("\"");
++	for (i=0; i < len; i++) {
++		if (str[i] == '\"' || str[i] == '\\')
++			putchar('\\');
++		printf("%c", (unsigned char) str[i]);
++	}
++	printf("\" ");  /* closing quote */
++}
++
++static void print(const struct ebt_u_entry *entry,
++		  const struct ebt_entry_match *match)
++{
++	const struct xt_string_info *info =
++		(const struct xt_string_info *) match->data;
++	int invert = info->u.v1.flags & XT_STRING_FLAG_INVERT;
++
++	if (is_hex_string(info->pattern, info->patlen)) {
++		printf("--string-hex %s", invert ? "! " : "");
++		print_hex_string(info->pattern, info->patlen);
++	} else {
++		printf("--string %s", invert ? "! " : "");
++		print_string(info->pattern, info->patlen);
++	}
++	printf("--string-algo %s ", info->algo);
++	if (info->from_offset != 0)
++		printf("--string-from %u ", info->from_offset);
++	if (info->to_offset != 0)
++		printf("--string-to %u ", info->to_offset);
++	if (info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
++		printf("--string-icase ");
++}
++
++static int compare(const struct ebt_entry_match *m1,
++		   const struct ebt_entry_match *m2)
++{
++	const struct xt_string_info *info1 =
++		(const struct xt_string_info *) m1->data;
++	const struct xt_string_info *info2 =
++		(const struct xt_string_info *) m2->data;
++
++	if (info1->from_offset != info2->from_offset)
++		return 0;
++	if (info1->to_offset != info2->to_offset)
++		return 0;
++	if (info1->u.v1.flags != info2->u.v1.flags)
++		return 0;
++	if (info1->patlen != info2->patlen)
++		return 0;
++	if (strncmp (info1->algo, info2->algo, XT_STRING_MAX_ALGO_NAME_SIZE) != 0)
++		return 0;
++	if (strncmp (info1->pattern, info2->pattern, info1->patlen) != 0)
++		return 0;
++
++	return 1;
++}
++
++static struct ebt_u_match string_match =
++{
++	.name		= "string",
++	.revision	= 1,
++	.size		= sizeof(struct xt_string_info),
++	.help		= print_help,
++	.init		= init,
++	.parse		= parse,
++	.final_check	= final_check,
++	.print		= print,
++	.compare	= compare,
++	.extra_ops	= opts,
++};
++
++void _init(void)
++{
++	ebt_register_match(&string_match);
++}
+diff --git a/include/ebtables.h b/include/ebtables.h
+index 8f520c600b356..9bbedbb72eea5 100644
+--- a/include/ebtables.h
++++ b/include/ebtables.h
+@@ -20,6 +20,7 @@
+ #define EBT_TABLE_MAXNAMELEN 32
+ #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+ #define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
++#define EBT_EXTENSION_MAXNAMELEN 31
+ 
+ /* verdicts >0 are "branches" */
+ #define EBT_ACCEPT   -1
+@@ -113,7 +114,10 @@ struct ebt_entries {
+ struct ebt_entry_match
+ {
+ 	union {
+-		char name[EBT_FUNCTION_MAXNAMELEN];
++		struct {
++			char name[EBT_EXTENSION_MAXNAMELEN];
++			uint8_t revision;
++		};
+ 		struct ebt_match *match;
+ 	} u;
+ 	/* size of data */
+@@ -127,7 +131,10 @@ struct ebt_entry_match
+ struct ebt_entry_watcher
+ {
+ 	union {
+-		char name[EBT_FUNCTION_MAXNAMELEN];
++		struct {
++			char name[EBT_EXTENSION_MAXNAMELEN];
++			uint8_t revision;
++		};
+ 		struct ebt_watcher *watcher;
+ 	} u;
+ 	/* size of data */
+@@ -141,7 +148,10 @@ struct ebt_entry_watcher
+ struct ebt_entry_target
+ {
+ 	union {
+-		char name[EBT_FUNCTION_MAXNAMELEN];
++		struct {
++			char name[EBT_EXTENSION_MAXNAMELEN];
++			uint8_t revision;
++		};
+ 		struct ebt_target *target;
+ 	} u;
+ 	/* size of data */
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index 17afa9487f5ad..c8589969bd8e0 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -144,6 +144,7 @@ struct ebt_u_entry
+ struct ebt_u_match
+ {
+ 	char name[EBT_FUNCTION_MAXNAMELEN];
++	uint8_t revision;
+ 	/* size of the real match data */
+ 	unsigned int size;
+ 	void (*help)(void);
+diff --git a/libebtc.c b/libebtc.c
+index d47424872dc51..92fd76485c723 100644
+--- a/libebtc.c
++++ b/libebtc.c
+@@ -272,6 +272,7 @@ void ebt_reinit_extensions()
+ 			if (!m->m)
+ 				ebt_print_memory();
+ 			strcpy(m->m->u.name, m->name);
++			m->m->u.revision = m->revision;
+ 			m->m->match_size = EBT_ALIGN(m->size);
+ 			m->used = 0;
+ 		}
+@@ -550,8 +551,10 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace,
+ 		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->u.revision != m->m->u.revision)) {
+ 				m_l2 = m_l2->next;
++			}
+ 			if (!m_l2 || !m->compare(m->m, m_l2->m))
+ 				goto letscontinue;
+ 			j++;
+@@ -1209,6 +1212,7 @@ void ebt_register_match(struct ebt_u_match *m)
+ 	if (!m->m)
+ 		ebt_print_memory();
+ 	strcpy(m->m->u.name, m->name);
++	m->m->u.revision = m->revision;
+ 	m->m->match_size = EBT_ALIGN(m->size);
+ 	m->init(m->m);
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0019-include-Fix-musl-libc-compatibility.patch b/SOURCES/0019-include-Fix-musl-libc-compatibility.patch
new file mode 100644
index 0000000..4617054
--- /dev/null
+++ b/SOURCES/0019-include-Fix-musl-libc-compatibility.patch
@@ -0,0 +1,51 @@
+From fa5642bfc0585bfadef238b830058e4d6e07f4a4 Mon Sep 17 00:00:00 2001
+From: Baruch Siach <baruch@tkos.co.il>
+Date: Fri, 4 May 2018 12:46:52 +0300
+Subject: [PATCH] include: Fix musl libc compatibility
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Conflicting definitions of struct ethhdr between the kernel and musl
+libc provides headers causes a build failure:
+
+In file included from .../usr/include/netinet/ether.h:8:0,
+                 from useful_functions.c:28:
+.../usr/include/netinet/if_ether.h:107:8: error: redefinition of ‘struct ethhdr’
+ struct ethhdr {
+        ^~~~~~
+In file included from include/linux/netfilter_bridge.h:8:0,
+                 from include/linux/netfilter_bridge/ebtables.h:17,
+                 from include/ebtables_u.h:27,
+                 from useful_functions.c:25:
+include/linux/if_ether.h:119:8: note: originally defined here
+ struct ethhdr {
+        ^~~~~~
+
+Recent enough versions kernel headers allow the libc to suppress
+conflicting kernel definitions. Include the libc proivded
+netinet/ether.h before kernel headers to suppress the conflicting
+definition of struct ethhdr.
+
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ include/ebtables_u.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index c8589969bd8e0..4824a145964ef 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -24,6 +24,7 @@
+ #ifndef EBTABLES_U_H
+ #define EBTABLES_U_H
+ #include <netinet/in.h>
++#include <netinet/ether.h>
+ #include <linux/netfilter_bridge/ebtables.h>
+ #include <linux/netfilter/x_tables.h>
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0020-ebtables-Fix-build-errors-and-warnings.patch b/SOURCES/0020-ebtables-Fix-build-errors-and-warnings.patch
new file mode 100644
index 0000000..dd909c1
--- /dev/null
+++ b/SOURCES/0020-ebtables-Fix-build-errors-and-warnings.patch
@@ -0,0 +1,161 @@
+From 10b72726428476e5efe582d34aa409b53d8b1434 Mon Sep 17 00:00:00 2001
+From: Duncan Roe <duncan_roe@optusnet.com.au>
+Date: Tue, 15 May 2018 08:26:43 +1000
+Subject: [PATCH] ebtables: Fix build errors and warnings
+
+Since commit b1cdae87f25021eb835872d86d6e7206bd421c3f, make fails thusly:
+
+> libebtc.c: In function 'ebt_reinit_extensions':
+> libebtc.c:275:11: error: 'union <anonymous>' has no member named 'revision'
+>     m->m->u.revision = m->revision;
+>            ^
+> libebtc.c: In function 'ebt_check_rule_exists':
+> libebtc.c:555:21: error: 'union <anonymous>' has no member named 'revision'
+>            m_l2->m->u.revision != m->m->u.revision)) {
+>                      ^
+> libebtc.c:555:41: error: 'union <anonymous>' has no member named 'revision'
+>            m_l2->m->u.revision != m->m->u.revision)) {
+>                                          ^
+> libebtc.c: In function 'ebt_register_match':
+> libebtc.c:1215:9: error: 'union <anonymous>' has no member named 'revision'
+>   m->m->u.revision = m->revision;
+>          ^
+The cause of this failure is that the commit updated include/ebtables.h but
+libebtc.c uses include/linux/netfilter_bridge/ebtables.h via
+include/ebtables_u.h (gcc -E -C verifies this).
+
+The 2 versions of ebtables.h looked to me to be otherwise close enough, so
+amended ebtables_u.h to use the newer one.
+
+Makefile insists on being warning-free, so cleared up warnings. Apart from
+unused variables, there was also the issue that the diagnostic macro
+ebt_print_error2 *returns* (i.e. makes its caller return) and returns -1. This
+is unsuitable for use in functions which do not return a value, so introduced
+ebt_print_error3 to do this.
+
+Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_string.c | 25 +++++++++++--------------
+ include/ebtables_u.h    |  4 +++-
+ 2 files changed, 14 insertions(+), 15 deletions(-)
+
+diff --git a/extensions/ebt_string.c b/extensions/ebt_string.c
+index 793f5df312f10..9550c41096a86 100644
+--- a/extensions/ebt_string.c
++++ b/extensions/ebt_string.c
+@@ -71,7 +71,7 @@ static void parse_string(const char *s, struct xt_string_info *info)
+ 		info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
+ 		return;
+ 	}
+-	ebt_print_error2("STRING too long \"%s\"", s);
++	ebt_print_error3("STRING too long \"%s\"", s);
+ }
+ 
+ static void parse_hex_string(const char *s, struct xt_string_info *info)
+@@ -83,14 +83,14 @@ static void parse_hex_string(const char *s, struct xt_string_info *info)
+ 	slen = strlen(s);
+ 
+ 	if (slen == 0) {
+-		ebt_print_error2("STRING must contain at least one char");
++		ebt_print_error3("STRING must contain at least one char");
+ 	}
+ 
+ 	while (i < slen) {
+ 		if (s[i] == '\\' && !hex_f) {
+ 			literal_f = 1;
+ 		} else if (s[i] == '\\') {
+-			ebt_print_error2("Cannot include literals in hex data");
++			ebt_print_error3("Cannot include literals in hex data");
+ 		} else if (s[i] == '|') {
+ 			if (hex_f)
+ 				hex_f = 0;
+@@ -108,28 +108,28 @@ static void parse_hex_string(const char *s, struct xt_string_info *info)
+ 
+ 		if (literal_f) {
+ 			if (i+1 >= slen) {
+-				ebt_print_error2("Bad literal placement at end of string");
++				ebt_print_error3("Bad literal placement at end of string");
+ 			}
+ 			info->pattern[sindex] = s[i+1];
+ 			i += 2;  /* skip over literal char */
+ 			literal_f = 0;
+ 		} else if (hex_f) {
+ 			if (i+1 >= slen) {
+-				ebt_print_error2("Odd number of hex digits");
++				ebt_print_error3("Odd number of hex digits");
+ 			}
+ 			if (i+2 >= slen) {
+ 				/* must end with a "|" */
+-				ebt_print_error2("Invalid hex block");
++				ebt_print_error3("Invalid hex block");
+ 			}
+ 			if (! isxdigit(s[i])) /* check for valid hex char */
+-				ebt_print_error2("Invalid hex char '%c'", s[i]);
++				ebt_print_error3("Invalid hex char '%c'", s[i]);
+ 			if (! isxdigit(s[i+1])) /* check for valid hex char */
+-				ebt_print_error2("Invalid hex char '%c'", s[i+1]);
++				ebt_print_error3("Invalid hex char '%c'", s[i+1]);
+ 			hextmp[0] = s[i];
+ 			hextmp[1] = s[i+1];
+ 			hextmp[2] = '\0';
+ 			if (! sscanf(hextmp, "%x", &schar))
+-				ebt_print_error2("Invalid hex char `%c'", s[i]);
++				ebt_print_error3("Invalid hex char `%c'", s[i]);
+ 			info->pattern[sindex] = (char) schar;
+ 			if (s[i+2] == ' ')
+ 				i += 3;  /* spaces included in the hex block */
+@@ -140,7 +140,7 @@ static void parse_hex_string(const char *s, struct xt_string_info *info)
+ 			i++;
+ 		}
+ 		if (sindex > XT_STRING_MAX_PATTERN_SIZE)
+-			ebt_print_error2("STRING too long \"%s\"", s);
++			ebt_print_error3("STRING too long \"%s\"", s);
+ 		sindex++;
+ 	}
+ 	info->patlen = sindex;
+@@ -150,9 +150,6 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ 		 unsigned int *flags, struct ebt_entry_match **match)
+ {
+ 	struct xt_string_info *info = (struct xt_string_info *)(*match)->data;
+-	int i;
+-	int input_string_length = 0;
+-	char buf[3] = { 0 };
+ 
+ 	switch (c) {
+ 	case STRING_FROM:
+@@ -206,7 +203,7 @@ static void final_check(const struct ebt_u_entry *entry,
+ 	struct xt_string_info *info = (struct xt_string_info *)match->data;
+ 
+ 	if (info->to_offset < info->from_offset) {
+-		ebt_print_error2("'to' offset should not be less than 'from' "
++		ebt_print_error3("'to' offset should not be less than 'from' "
+ 				 "offset");
+ 	}
+ }
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index 4824a145964ef..7adc5a2f33329 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -25,7 +25,7 @@
+ #define EBTABLES_U_H
+ #include <netinet/in.h>
+ #include <netinet/ether.h>
+-#include <linux/netfilter_bridge/ebtables.h>
++#include <ebtables.h>
+ #include <linux/netfilter/x_tables.h>
+ 
+ #ifndef IPPROTO_SCTP
+@@ -338,6 +338,8 @@ _ch;})
+ #define ebt_print_error(format,args...) __ebt_print_error(format, ##args);
+ #define ebt_print_error2(format, args...) do {__ebt_print_error(format, ##args); \
+    return -1;} while (0)
++#define ebt_print_error3(format, args...) do {__ebt_print_error(format, ##args); \
++   return;} while (0)
+ #define ebt_check_option2(flags,mask)	\
+ ({ebt_check_option(flags,mask);		\
+  if (ebt_errormsg[0] != '\0')		\
+-- 
+2.21.0
+
diff --git a/SOURCES/0021-build-update-ebtables.h-from-kernel-and-drop-local-u.patch b/SOURCES/0021-build-update-ebtables.h-from-kernel-and-drop-local-u.patch
new file mode 100644
index 0000000..31c8924
--- /dev/null
+++ b/SOURCES/0021-build-update-ebtables.h-from-kernel-and-drop-local-u.patch
@@ -0,0 +1,416 @@
+From b96b42e4ad9c47bf2a511905bca4e52bb4cee16d Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Wed, 6 Jun 2018 13:36:25 +0200
+Subject: [PATCH] build: update ebtables.h from kernel and drop local unused
+ copy
+
+Revert 66a97018a31eed416c6a25d051ea172e4d65be1b partly so as to use
+<linux/netfilter_bridge/ebtables.h> again and import a new ebtables.h
+from the kernel tree that has the "revision" field.
+
+With this, include/ebtables.h is (again) used by no source file, and
+so can be removed.
+
+Signed-off-by: Jan Engelhardt <jengelh@inai.de>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ include/ebtables.h                        | 286 ----------------------
+ include/ebtables_u.h                      |   2 +-
+ include/linux/netfilter_bridge/ebtables.h |  27 +-
+ 3 files changed, 20 insertions(+), 295 deletions(-)
+ delete mode 100644 include/ebtables.h
+
+diff --git a/include/ebtables.h b/include/ebtables.h
+deleted file mode 100644
+index 9bbedbb72eea5..0000000000000
+--- a/include/ebtables.h
++++ /dev/null
+@@ -1,286 +0,0 @@
+-/*
+- *  ebtables
+- *
+- *	Authors:
+- *	Bart De Schuymer		<bdschuym@pandora.be>
+- *
+- *  ebtables.c,v 2.0, April, 2002
+- *
+- *  This code is stongly inspired on the iptables code which is
+- *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+- */
+-
+-/* Local copy of the kernel file, needed for Sparc64 support */
+-#ifndef __LINUX_BRIDGE_EFF_H
+-#define __LINUX_BRIDGE_EFF_H
+-#include <linux/if.h>
+-#include <linux/netfilter_bridge.h>
+-#include <linux/if_ether.h>
+-
+-#define EBT_TABLE_MAXNAMELEN 32
+-#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+-#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+-#define EBT_EXTENSION_MAXNAMELEN 31
+-
+-/* verdicts >0 are "branches" */
+-#define EBT_ACCEPT   -1
+-#define EBT_DROP     -2
+-#define EBT_CONTINUE -3
+-#define EBT_RETURN   -4
+-#define NUM_STANDARD_TARGETS   4
+-/* ebtables target modules store the verdict inside an int. We can
+- * reclaim a part of this int for backwards compatible extensions.
+- * The 4 lsb are more than enough to store the verdict. */
+-#define EBT_VERDICT_BITS 0x0000000F
+-
+-struct ebt_counter
+-{
+-	uint64_t pcnt;
+-	uint64_t bcnt;
+-};
+-
+-struct ebt_replace
+-{
+-	char name[EBT_TABLE_MAXNAMELEN];
+-	unsigned int valid_hooks;
+-	/* nr of rules in the table */
+-	unsigned int nentries;
+-	/* total size of the entries */
+-	unsigned int entries_size;
+-	/* start of the chains */
+-#ifdef KERNEL_64_USERSPACE_32
+-	uint64_t hook_entry[NF_BR_NUMHOOKS];
+-#else
+-	struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
+-#endif
+-	/* nr of counters userspace expects back */
+-	unsigned int num_counters;
+-	/* where the kernel will put the old counters */
+-#ifdef KERNEL_64_USERSPACE_32
+-	uint64_t counters;
+-	uint64_t entries;
+-#else
+-	struct ebt_counter *counters;
+-	char *entries;
+-#endif
+-};
+-
+-struct ebt_entries {
+-	/* this field is always set to zero
+-	 * See EBT_ENTRY_OR_ENTRIES.
+-	 * Must be same size as ebt_entry.bitmask */
+-	unsigned int distinguisher;
+-	/* the chain name */
+-	char name[EBT_CHAIN_MAXNAMELEN];
+-	/* counter offset for this chain */
+-	unsigned int counter_offset;
+-	/* one standard (accept, drop, return) per hook */
+-	int policy;
+-	/* nr. of entries */
+-	unsigned int nentries;
+-	/* entry list */
+-	char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+-};
+-
+-/* used for the bitmask of struct ebt_entry */
+-
+-/* This is a hack to make a difference between an ebt_entry struct and an
+- * ebt_entries struct when traversing the entries from start to end.
+- * Using this simplifies the code alot, while still being able to use
+- * ebt_entries.
+- * Contrary, iptables doesn't use something like ebt_entries and therefore uses
+- * different techniques for naming the policy and such. So, iptables doesn't
+- * need a hack like this.
+- */
+-#define EBT_ENTRY_OR_ENTRIES 0x01
+-/* these are the normal masks */
+-#define EBT_NOPROTO 0x02
+-#define EBT_802_3 0x04
+-#define EBT_SOURCEMAC 0x08
+-#define EBT_DESTMAC 0x10
+-#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \
+-   | EBT_ENTRY_OR_ENTRIES)
+-
+-#define EBT_IPROTO 0x01
+-#define EBT_IIN 0x02
+-#define EBT_IOUT 0x04
+-#define EBT_ISOURCE 0x8
+-#define EBT_IDEST 0x10
+-#define EBT_ILOGICALIN 0x20
+-#define EBT_ILOGICALOUT 0x40
+-#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \
+-   | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST)
+-
+-struct ebt_entry_match
+-{
+-	union {
+-		struct {
+-			char name[EBT_EXTENSION_MAXNAMELEN];
+-			uint8_t revision;
+-		};
+-		struct ebt_match *match;
+-	} u;
+-	/* size of data */
+-	unsigned int match_size;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+-	unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+-};
+-
+-struct ebt_entry_watcher
+-{
+-	union {
+-		struct {
+-			char name[EBT_EXTENSION_MAXNAMELEN];
+-			uint8_t revision;
+-		};
+-		struct ebt_watcher *watcher;
+-	} u;
+-	/* size of data */
+-	unsigned int watcher_size;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+-	unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+-};
+-
+-struct ebt_entry_target
+-{
+-	union {
+-		struct {
+-			char name[EBT_EXTENSION_MAXNAMELEN];
+-			uint8_t revision;
+-		};
+-		struct ebt_target *target;
+-	} u;
+-	/* size of data */
+-	unsigned int target_size;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+-	unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+-};
+-
+-#define EBT_STANDARD_TARGET "standard"
+-struct ebt_standard_target
+-{
+-	struct ebt_entry_target target;
+-	int verdict;
+-#ifdef KERNEL_64_USERSPACE_32
+-	unsigned int pad;
+-#endif
+-};
+-
+-/* one entry */
+-struct ebt_entry {
+-	/* this needs to be the first field */
+-	unsigned int bitmask;
+-	unsigned int invflags;
+-	uint16_t ethproto;
+-	/* the physical in-dev */
+-	char in[IFNAMSIZ];
+-	/* the logical in-dev */
+-	char logical_in[IFNAMSIZ];
+-	/* the physical out-dev */
+-	char out[IFNAMSIZ];
+-	/* the logical out-dev */
+-	char logical_out[IFNAMSIZ];
+-	unsigned char sourcemac[ETH_ALEN];
+-	unsigned char sourcemsk[ETH_ALEN];
+-	unsigned char destmac[ETH_ALEN];
+-	unsigned char destmsk[ETH_ALEN];
+-	/* sizeof ebt_entry + matches */
+-	unsigned int watchers_offset;
+-	/* sizeof ebt_entry + matches + watchers */
+-	unsigned int target_offset;
+-	/* sizeof ebt_entry + matches + watchers + target */
+-	unsigned int next_offset;
+-	unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+-};
+-
+-/* {g,s}etsockopt numbers */
+-#define EBT_BASE_CTL            128
+-
+-#define EBT_SO_SET_ENTRIES      (EBT_BASE_CTL)
+-#define EBT_SO_SET_COUNTERS     (EBT_SO_SET_ENTRIES+1)
+-#define EBT_SO_SET_MAX          (EBT_SO_SET_COUNTERS+1)
+-
+-#define EBT_SO_GET_INFO         (EBT_BASE_CTL)
+-#define EBT_SO_GET_ENTRIES      (EBT_SO_GET_INFO+1)
+-#define EBT_SO_GET_INIT_INFO    (EBT_SO_GET_ENTRIES+1)
+-#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1)
+-#define EBT_SO_GET_MAX          (EBT_SO_GET_INIT_ENTRIES+1)
+-
+-/* blatently stolen from ip_tables.h
+- * fn returns 0 to continue iteration */
+-#define EBT_MATCH_ITERATE(e, fn, args...)                   \
+-({                                                          \
+-	unsigned int __i;                                   \
+-	int __ret = 0;                                      \
+-	struct ebt_entry_match *__match;                    \
+-	                                                    \
+-	for (__i = sizeof(struct ebt_entry);                \
+-	     __i < (e)->watchers_offset;                    \
+-	     __i += __match->match_size +                   \
+-	     sizeof(struct ebt_entry_match)) {              \
+-		__match = (void *)(e) + __i;                \
+-		                                            \
+-		__ret = fn(__match , ## args);              \
+-		if (__ret != 0)                             \
+-			break;                              \
+-	}                                                   \
+-	if (__ret == 0) {                                   \
+-		if (__i != (e)->watchers_offset)            \
+-			__ret = -EINVAL;                    \
+-	}                                                   \
+-	__ret;                                              \
+-})
+-
+-#define EBT_WATCHER_ITERATE(e, fn, args...)                 \
+-({                                                          \
+-	unsigned int __i;                                   \
+-	int __ret = 0;                                      \
+-	struct ebt_entry_watcher *__watcher;                \
+-	                                                    \
+-	for (__i = e->watchers_offset;                      \
+-	     __i < (e)->target_offset;                      \
+-	     __i += __watcher->watcher_size +               \
+-	     sizeof(struct ebt_entry_watcher)) {            \
+-		__watcher = (void *)(e) + __i;              \
+-		                                            \
+-		__ret = fn(__watcher , ## args);            \
+-		if (__ret != 0)                             \
+-			break;                              \
+-	}                                                   \
+-	if (__ret == 0) {                                   \
+-		if (__i != (e)->target_offset)              \
+-			__ret = -EINVAL;                    \
+-	}                                                   \
+-	__ret;                                              \
+-})
+-
+-#define EBT_ENTRY_ITERATE(entries, size, fn, args...)       \
+-({                                                          \
+-	unsigned int __i;                                   \
+-	int __ret = 0;                                      \
+-	struct ebt_entry *__entry;                          \
+-	                                                    \
+-	for (__i = 0; __i < (size);) {                      \
+-		__entry = (void *)(entries) + __i;          \
+-		__ret = fn(__entry , ## args);              \
+-		if (__ret != 0)                             \
+-			break;                              \
+-		if (__entry->bitmask != 0)                  \
+-			__i += __entry->next_offset;        \
+-		else                                        \
+-			__i += sizeof(struct ebt_entries);  \
+-	}                                                   \
+-	if (__ret == 0) {                                   \
+-		if (__i != (size))                          \
+-			__ret = -EINVAL;                    \
+-	}                                                   \
+-	__ret;                                              \
+-})
+-
+-#endif
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index 7adc5a2f33329..3235bf5967055 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -25,7 +25,7 @@
+ #define EBTABLES_U_H
+ #include <netinet/in.h>
+ #include <netinet/ether.h>
+-#include <ebtables.h>
++#include <linux/netfilter_bridge/ebtables.h>
+ #include <linux/netfilter/x_tables.h>
+ 
+ #ifndef IPPROTO_SCTP
+diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
+index 19a64448c648e..5be75f282cd20 100644
+--- a/include/linux/netfilter_bridge/ebtables.h
++++ b/include/linux/netfilter_bridge/ebtables.h
+@@ -1,3 +1,4 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+ /*
+  *  ebtables
+  *
+@@ -6,19 +7,20 @@
+  *
+  *  ebtables.c,v 2.0, April, 2002
+  *
+- *  This code is stongly inspired on the iptables code which is
++ *  This code is strongly inspired by the iptables code which is
+  *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+  */
+ 
+ #ifndef __LINUX_BRIDGE_EFF_H
+ #define __LINUX_BRIDGE_EFF_H
++#include <linux/types.h>
+ #include <linux/if.h>
+ #include <linux/netfilter_bridge.h>
+-#include <linux/if_ether.h>
+ 
+ #define EBT_TABLE_MAXNAMELEN 32
+ #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+ #define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
++#define EBT_EXTENSION_MAXNAMELEN 31
+ 
+ /* verdicts >0 are "branches" */
+ #define EBT_ACCEPT   -1
+@@ -35,8 +37,8 @@ struct xt_match;
+ struct xt_target;
+ 
+ struct ebt_counter {
+-	uint64_t pcnt;
+-	uint64_t bcnt;
++	__u64 pcnt;
++	__u64 bcnt;
+ };
+ 
+ struct ebt_replace {
+@@ -119,7 +121,10 @@ struct ebt_entries {
+ 
+ struct ebt_entry_match {
+ 	union {
+-		char name[EBT_FUNCTION_MAXNAMELEN];
++		struct {
++			char name[EBT_EXTENSION_MAXNAMELEN];
++			uint8_t revision;
++		};
+ 		struct xt_match *match;
+ 	} u;
+ 	/* size of data */
+@@ -129,7 +134,10 @@ struct ebt_entry_match {
+ 
+ struct ebt_entry_watcher {
+ 	union {
+-		char name[EBT_FUNCTION_MAXNAMELEN];
++		struct {
++			char name[EBT_EXTENSION_MAXNAMELEN];
++			uint8_t revision;
++		};
+ 		struct xt_target *watcher;
+ 	} u;
+ 	/* size of data */
+@@ -139,7 +147,10 @@ struct ebt_entry_watcher {
+ 
+ struct ebt_entry_target {
+ 	union {
+-		char name[EBT_FUNCTION_MAXNAMELEN];
++		struct {
++			char name[EBT_EXTENSION_MAXNAMELEN];
++			uint8_t revision;
++		};
+ 		struct xt_target *target;
+ 	} u;
+ 	/* size of data */
+@@ -265,4 +276,4 @@ struct ebt_entry {
+ 	__ret;                                              \
+ })
+ 
+-#endif
++#endif /* __LINUX_BRIDGE_EFF_H */
+-- 
+2.21.0
+
diff --git a/SOURCES/0022-extensions-fix-build-failure-on-fc28.patch b/SOURCES/0022-extensions-fix-build-failure-on-fc28.patch
new file mode 100644
index 0000000..04c676f
--- /dev/null
+++ b/SOURCES/0022-extensions-fix-build-failure-on-fc28.patch
@@ -0,0 +1,35 @@
+From d3724c422da83279eb7550019668c29bbf16592a Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Wed, 6 Jun 2018 14:21:57 +0200
+Subject: [PATCH] extensions: fix build failure on fc28
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+make fails via:
+extensions/ebt_string.c: In function ‘parse’:
+extensions/ebt_string.c:171:3: error: ‘strncpy’ specified bound 16 equals destination size [-Werror=stringop-truncation]
+   strncpy(info->algo, optarg, XT_STRING_MAX_ALGO_NAME_SIZE);
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_string.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/extensions/ebt_string.c b/extensions/ebt_string.c
+index 9550c41096a86..3deff1ba83264 100644
+--- a/extensions/ebt_string.c
++++ b/extensions/ebt_string.c
+@@ -168,7 +168,7 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ 		ebt_check_option2(flags, OPT_STRING_ALGO);
+ 		if (ebt_check_inverse2(optarg))
+ 			ebt_print_error2("Unexpected `!' after --string-algo");
+-		strncpy(info->algo, optarg, XT_STRING_MAX_ALGO_NAME_SIZE);
++		snprintf(info->algo, sizeof(info->algo), "%s", optarg);
+ 		break;
+ 	case STRING_ICASE:
+ 		ebt_check_option2(flags, OPT_STRING_ICASE);
+-- 
+2.21.0
+
diff --git a/SOURCES/0023-extensions-ebt_string-take-action-if-snprintf-discar.patch b/SOURCES/0023-extensions-ebt_string-take-action-if-snprintf-discar.patch
new file mode 100644
index 0000000..cb17078
--- /dev/null
+++ b/SOURCES/0023-extensions-ebt_string-take-action-if-snprintf-discar.patch
@@ -0,0 +1,36 @@
+From 2a33cbf1d286443259093cfb77219fdc60cfb7df Mon Sep 17 00:00:00 2001
+From: Duncan Roe <duncan_roe@optusnet.com.au>
+Date: Fri, 15 Jun 2018 11:31:56 +1000
+Subject: [PATCH] extensions: ebt_string: take action if snprintf discards data
+
+56993546c805 ("extensions: fix build failure on fc28") eliminated a gcc
+warning that strncpy could make a string w/out a NUL terminator.
+snprintf guarantees NUL-termination (so fixes that possibility).  But,
+snprintf may discard data to make room for the NUL.  This patch errors
+straight away in that eventuality.
+
+Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_string.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/extensions/ebt_string.c b/extensions/ebt_string.c
+index 3deff1ba83264..7d24f8002f4d7 100644
+--- a/extensions/ebt_string.c
++++ b/extensions/ebt_string.c
+@@ -168,7 +168,9 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ 		ebt_check_option2(flags, OPT_STRING_ALGO);
+ 		if (ebt_check_inverse2(optarg))
+ 			ebt_print_error2("Unexpected `!' after --string-algo");
+-		snprintf(info->algo, sizeof(info->algo), "%s", optarg);
++		if (snprintf(info->algo, sizeof(info->algo), "%s", optarg) >=
++				sizeof(info->algo))
++			ebt_print_error2("\"%s\" is truncated", info->algo);
+ 		break;
+ 	case STRING_ICASE:
+ 		ebt_check_option2(flags, OPT_STRING_ICASE);
+-- 
+2.21.0
+
diff --git a/SOURCES/0024-build-drop-install-o-g-root.patch b/SOURCES/0024-build-drop-install-o-g-root.patch
new file mode 100644
index 0000000..e258ce2
--- /dev/null
+++ b/SOURCES/0024-build-drop-install-o-g-root.patch
@@ -0,0 +1,89 @@
+From 2dcebe667a4cbebe0c825633510c015143d5ed92 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Wed, 27 Jun 2018 11:50:38 +0200
+Subject: [PATCH] build: drop install -o/-g root
+
+Calling /usr/bin/install with -o/-g will attempt to chown, and fail
+if unsuccessful, which makes an unprivileged install with DESTDIR a
+futile attempt always.
+
+Drop it, because /usr/bin/install chowns to the current running user
+*anyway*, which means when root calls `make install`, it will do the
+right thing as before.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ Makefile | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index c1106a4e08345..79ee167e0258b 100644
+--- a/Makefile
++++ b/Makefile
+@@ -157,31 +157,31 @@ tmp3:=$(shell printf $(PIPE) | sed 's/\//\\\//g')
+ scripts: ebtables-save ebtables.sysv ebtables-config
+ 	cat ebtables-save | sed 's/__EXEC_PATH__/$(tmp1)/g' > ebtables-save_
+ 	mkdir -p $(DESTDIR)$(BINDIR)
+-	install -m 0755 -o root -g root ebtables-save_ $(DESTDIR)$(BINDIR)/ebtables-save
++	install -m 0755 ebtables-save_ $(DESTDIR)$(BINDIR)/ebtables-save
+ 	cat ebtables.sysv | sed 's/__EXEC_PATH__/$(tmp1)/g' | sed 's/__SYSCONFIG__/$(tmp2)/g' > ebtables.sysv_
+ 	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(INITDIR); fi
+-	if test -d $(DESTDIR)$(INITDIR); then install -m 0755 -o root -g root ebtables.sysv_ $(DESTDIR)$(INITDIR)/ebtables; fi
++	if test -d $(DESTDIR)$(INITDIR); then install -m 0755 ebtables.sysv_ $(DESTDIR)$(INITDIR)/ebtables; fi
+ 	cat ebtables-config | sed 's/__SYSCONFIG__/$(tmp2)/g' > ebtables-config_
+ 	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(SYSCONFIGDIR); fi
+-	if test -d $(DESTDIR)$(SYSCONFIGDIR); then install -m 0600 -o root -g root ebtables-config_ $(DESTDIR)$(SYSCONFIGDIR)/ebtables-config; fi
++	if test -d $(DESTDIR)$(SYSCONFIGDIR); then install -m 0600 ebtables-config_ $(DESTDIR)$(SYSCONFIGDIR)/ebtables-config; fi
+ 	rm -f ebtables-save_ ebtables.sysv_ ebtables-config_
+ 
+ tmp4:=$(shell printf $(LOCKFILE) | sed 's/\//\\\//g')
+ $(MANDIR)/man8/ebtables.8: ebtables.8
+ 	mkdir -p $(DESTDIR)$(@D)
+ 	sed -e 's/$$(VERSION)/$(PROGVERSION)/' -e 's/$$(DATE)/$(PROGDATE)/' -e 's/$$(LOCKFILE)/$(tmp4)/' ebtables.8 > ebtables.8_
+-	install -m 0644 -o root -g root ebtables.8_ $(DESTDIR)$@
++	install -m 0644 ebtables.8_ $(DESTDIR)$@
+ 	rm -f ebtables.8_
+ 
+ $(DESTDIR)$(ETHERTYPESFILE): ethertypes
+ 	mkdir -p $(@D)
+-	install -m 0644 -o root -g root $< $@
++	install -m 0644 $< $@
+ 
+ .PHONY: exec
+ exec: ebtables ebtables-restore
+ 	mkdir -p $(DESTDIR)$(BINDIR)
+-	install -m 0755 -o root -g root $(PROGNAME) $(DESTDIR)$(BINDIR)/$(PROGNAME)
+-	install -m 0755 -o root -g root ebtables-restore $(DESTDIR)$(BINDIR)/ebtables-restore
++	install -m 0755 $(PROGNAME) $(DESTDIR)$(BINDIR)/$(PROGNAME)
++	install -m 0755 ebtables-restore $(DESTDIR)$(BINDIR)/ebtables-restore
+ 
+ .PHONY: install
+ install: $(MANDIR)/man8/ebtables.8 $(DESTDIR)$(ETHERTYPESFILE) exec scripts
+@@ -205,18 +205,18 @@ release:
+ 	rm -f extensions/ebt_inat.c
+ 	rm -rf $(CVSDIRS)
+ 	mkdir -p include/linux/netfilter_bridge
+-	install -m 0644 -o root -g root \
++	install -m 0644 \
+ 		$(KERNEL_INCLUDES)/linux/netfilter_bridge.h include/linux/
+ # To keep possible compile error complaints about undefined ETH_P_8021Q
+ # off my back
+-	install -m 0644 -o root -g root \
++	install -m 0644 \
+ 		$(KERNEL_INCLUDES)/linux/if_ether.h include/linux/
+-	install -m 0644 -o root -g root \
++	install -m 0644 \
+ 		$(KERNEL_INCLUDES)/linux/types.h include/linux/
+-	install -m 0644 -o root -g root \
++	install -m 0644 \
+ 		$(KERNEL_INCLUDES)/linux/netfilter_bridge/*.h \
+ 		include/linux/netfilter_bridge/
+-	install -m 0644 -o root -g root \
++	install -m 0644 \
+ 		include/ebtables.h include/linux/netfilter_bridge/
+ 	make clean
+ 	touch *
+-- 
+2.21.0
+
diff --git a/SOURCES/0025-build-rename-sed-source-files-to-.in.patch b/SOURCES/0025-build-rename-sed-source-files-to-.in.patch
new file mode 100644
index 0000000..3a64ebd
--- /dev/null
+++ b/SOURCES/0025-build-rename-sed-source-files-to-.in.patch
@@ -0,0 +1,82 @@
+From 67613b5a7ce545683a4831bf6297f9a108538827 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Wed, 27 Jun 2018 11:50:39 +0200
+Subject: [PATCH] build: rename sed source files to .in
+
+Prepare for autoconf-based substitution of macros in the file.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ Makefile                              | 14 +++++++-------
+ ebtables-config => ebtables-config.in |  0
+ ebtables-save => ebtables-save.in     |  0
+ ebtables.8 => ebtables.8.in           |  0
+ ebtables.sysv => ebtables.sysv.in     |  0
+ 5 files changed, 7 insertions(+), 7 deletions(-)
+ rename ebtables-config => ebtables-config.in (100%)
+ rename ebtables-save => ebtables-save.in (100%)
+ rename ebtables.8 => ebtables.8.in (100%)
+ rename ebtables.sysv => ebtables.sysv.in (100%)
+
+diff --git a/Makefile b/Makefile
+index 79ee167e0258b..d0a12d6ed7325 100644
+--- a/Makefile
++++ b/Makefile
+@@ -154,22 +154,22 @@ tmp1:=$(shell printf $(BINDIR) | sed 's/\//\\\//g')
+ tmp2:=$(shell printf $(SYSCONFIGDIR) | sed 's/\//\\\//g')
+ tmp3:=$(shell printf $(PIPE) | sed 's/\//\\\//g')
+ .PHONY: scripts
+-scripts: ebtables-save ebtables.sysv ebtables-config
+-	cat ebtables-save | sed 's/__EXEC_PATH__/$(tmp1)/g' > ebtables-save_
++scripts: ebtables-save.in ebtables.sysv.in ebtables-config.in
++	sed -e 's/__EXEC_PATH__/$(tmp1)/g' <ebtables-save.in >ebtables-save_
+ 	mkdir -p $(DESTDIR)$(BINDIR)
+ 	install -m 0755 ebtables-save_ $(DESTDIR)$(BINDIR)/ebtables-save
+-	cat ebtables.sysv | sed 's/__EXEC_PATH__/$(tmp1)/g' | sed 's/__SYSCONFIG__/$(tmp2)/g' > ebtables.sysv_
++	sed -e 's/__EXEC_PATH__/$(tmp1)/g' -e 's/__SYSCONFIG__/$(tmp2)/g' <ebtables.sysv.in >ebtables.sysv_
+ 	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(INITDIR); fi
+ 	if test -d $(DESTDIR)$(INITDIR); then install -m 0755 ebtables.sysv_ $(DESTDIR)$(INITDIR)/ebtables; fi
+-	cat ebtables-config | sed 's/__SYSCONFIG__/$(tmp2)/g' > ebtables-config_
++	sed -e 's/__SYSCONFIG__/$(tmp2)/g' <ebtables-config >ebtables-config_
+ 	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(SYSCONFIGDIR); fi
+ 	if test -d $(DESTDIR)$(SYSCONFIGDIR); then install -m 0600 ebtables-config_ $(DESTDIR)$(SYSCONFIGDIR)/ebtables-config; fi
+ 	rm -f ebtables-save_ ebtables.sysv_ ebtables-config_
+ 
+ tmp4:=$(shell printf $(LOCKFILE) | sed 's/\//\\\//g')
+-$(MANDIR)/man8/ebtables.8: ebtables.8
++$(MANDIR)/man8/ebtables.8: ebtables.8.in
+ 	mkdir -p $(DESTDIR)$(@D)
+-	sed -e 's/$$(VERSION)/$(PROGVERSION)/' -e 's/$$(DATE)/$(PROGDATE)/' -e 's/$$(LOCKFILE)/$(tmp4)/' ebtables.8 > ebtables.8_
++	sed -e 's/$$(VERSION)/$(PROGVERSION)/' -e 's/$$(DATE)/$(PROGDATE)/' -e 's/$$(LOCKFILE)/$(tmp4)/' <$< >ebtables.8_
+ 	install -m 0644 ebtables.8_ $(DESTDIR)$@
+ 	rm -f ebtables.8_
+ 
+@@ -224,7 +224,7 @@ release:
+ 	touch include/*
+ 	touch include/linux/*
+ 	touch include/linux/netfilter_bridge/*
+-	sed -i -e 's/$$(VERSION)/$(PROGVERSION)/' -e 's/$$(DATE)/$(PROGDATE)/' -e 's/$$(LOCKFILE)/$(tmp4)/' ebtables.8
++	sed -i -e 's/$$(VERSION)/$(PROGVERSION)/' -e 's/$$(DATE)/$(PROGDATE)/' -e 's/$$(LOCKFILE)/$(tmp4)/' <ebtables.8.in >ebtables.8
+ 	sed -i -e 's/$$(VERSION)/$(PROGVERSION_)/' -e 's/$$(RELEASE)/$(PROGRELEASE)/' ebtables.spec
+ 	cd ..;tar -c $(DIR) | gzip >$(DIR).tar.gz; cd -
+ 	rm -rf include/linux
+diff --git a/ebtables-config b/ebtables-config.in
+similarity index 100%
+rename from ebtables-config
+rename to ebtables-config.in
+diff --git a/ebtables-save b/ebtables-save.in
+similarity index 100%
+rename from ebtables-save
+rename to ebtables-save.in
+diff --git a/ebtables.8 b/ebtables.8.in
+similarity index 100%
+rename from ebtables.8
+rename to ebtables.8.in
+diff --git a/ebtables.sysv b/ebtables.sysv.in
+similarity index 100%
+rename from ebtables.sysv
+rename to ebtables.sysv.in
+-- 
+2.21.0
+
diff --git a/SOURCES/0026-build-use-autoconf-style-placeholders-in-sed-ed-file.patch b/SOURCES/0026-build-use-autoconf-style-placeholders-in-sed-ed-file.patch
new file mode 100644
index 0000000..82d745b
--- /dev/null
+++ b/SOURCES/0026-build-use-autoconf-style-placeholders-in-sed-ed-file.patch
@@ -0,0 +1,187 @@
+From 0784cbd11e40aa6c04acb89c30b9d5bb45703b33 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Wed, 27 Jun 2018 11:50:40 +0200
+Subject: [PATCH] build: use autoconf-style placeholders in sed-ed files
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ Makefile         |  8 ++++----
+ ebtables-save.in |  2 +-
+ ebtables.8.in    |  6 +++---
+ ebtables.sysv.in | 38 +++++++++++++++++++-------------------
+ 4 files changed, 27 insertions(+), 27 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index d0a12d6ed7325..7c70db0267983 100644
+--- a/Makefile
++++ b/Makefile
+@@ -155,13 +155,13 @@ tmp2:=$(shell printf $(SYSCONFIGDIR) | sed 's/\//\\\//g')
+ tmp3:=$(shell printf $(PIPE) | sed 's/\//\\\//g')
+ .PHONY: scripts
+ scripts: ebtables-save.in ebtables.sysv.in ebtables-config.in
+-	sed -e 's/__EXEC_PATH__/$(tmp1)/g' <ebtables-save.in >ebtables-save_
++	sed -e 's/[@]sbindir@/$(tmp1)/g' <ebtables-save.in >ebtables-save_
+ 	mkdir -p $(DESTDIR)$(BINDIR)
+ 	install -m 0755 ebtables-save_ $(DESTDIR)$(BINDIR)/ebtables-save
+-	sed -e 's/__EXEC_PATH__/$(tmp1)/g' -e 's/__SYSCONFIG__/$(tmp2)/g' <ebtables.sysv.in >ebtables.sysv_
++	sed -e 's/[@]sbindir@/$(tmp1)/g' -e 's/[@]sysconfigdir@/$(tmp2)/g' <ebtables.sysv.in >ebtables.sysv_
+ 	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(INITDIR); fi
+ 	if test -d $(DESTDIR)$(INITDIR); then install -m 0755 ebtables.sysv_ $(DESTDIR)$(INITDIR)/ebtables; fi
+-	sed -e 's/__SYSCONFIG__/$(tmp2)/g' <ebtables-config >ebtables-config_
++	sed -e 's/[@]sysconfigdir@/$(tmp2)/g' <ebtables-config >ebtables-config_
+ 	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(SYSCONFIGDIR); fi
+ 	if test -d $(DESTDIR)$(SYSCONFIGDIR); then install -m 0600 ebtables-config_ $(DESTDIR)$(SYSCONFIGDIR)/ebtables-config; fi
+ 	rm -f ebtables-save_ ebtables.sysv_ ebtables-config_
+@@ -169,7 +169,7 @@ scripts: ebtables-save.in ebtables.sysv.in ebtables-config.in
+ tmp4:=$(shell printf $(LOCKFILE) | sed 's/\//\\\//g')
+ $(MANDIR)/man8/ebtables.8: ebtables.8.in
+ 	mkdir -p $(DESTDIR)$(@D)
+-	sed -e 's/$$(VERSION)/$(PROGVERSION)/' -e 's/$$(DATE)/$(PROGDATE)/' -e 's/$$(LOCKFILE)/$(tmp4)/' <$< >ebtables.8_
++	sed -e 's/[@]PACKAGE_VERSION@/$(PROGVERSION)/' -e 's/[@]PACKAGE_DATE@/$(PROGDATE)/' -e 's/[@]LOCKFILE@/$(tmp4)/' <$< >ebtables.8_
+ 	install -m 0644 ebtables.8_ $(DESTDIR)$@
+ 	rm -f ebtables.8_
+ 
+diff --git a/ebtables-save.in b/ebtables-save.in
+index 49d733b7adf5e..df141490c20b1 100644
+--- a/ebtables-save.in
++++ b/ebtables-save.in
+@@ -8,7 +8,7 @@
+ 
+ use strict;
+ my $table;
+-my $ebtables = "__EXEC_PATH__/ebtables";
++my $ebtables = "@sbindir@/ebtables";
+ my $cnt = "";
+ my $version = "1.0";
+ my $table_name;
+diff --git a/ebtables.8.in b/ebtables.8.in
+index 00c4562d20036..3e97c84da0e86 100644
+--- a/ebtables.8.in
++++ b/ebtables.8.in
+@@ -1,4 +1,4 @@
+-.TH EBTABLES 8  "December 2011"
++.TH EBTABLES 8  "@PACKAGE_DATE@"
+ .\"
+ .\" Man page written by Bart De Schuymer <bdschuym@pandora.be>
+ .\" It is based on the iptables man page.
+@@ -24,7 +24,7 @@
+ .\"     
+ .\"
+ .SH NAME
+-ebtables (v2.0.10-4) \- Ethernet bridge frame table administration
++ebtables (@PACKAGE_VERSION@) \- Ethernet bridge frame table administration
+ .SH SYNOPSIS
+ .BR "ebtables " [ -t " table ] " - [ ACDI "] chain rule specification [match extensions] [watcher extensions] target"
+ .br
+@@ -1123,7 +1123,7 @@ arp message and the hardware address length in the arp header is 6 bytes.
+ .br
+ .SH FILES
+ .I /etc/ethertypes
+-.I /var/lib/ebtables/lock
++.I @LOCKFILE@
+ .SH ENVIRONMENT VARIABLES
+ .I EBTABLES_ATOMIC_FILE
+ .SH MAILINGLISTS
+diff --git a/ebtables.sysv.in b/ebtables.sysv.in
+index b6848f14257e8..bbf0e7424cb2b 100644
+--- a/ebtables.sysv.in
++++ b/ebtables.sysv.in
+@@ -9,8 +9,8 @@
+ # chkconfig: - 15 85
+ # description: Ethernet Bridge filtering tables
+ #
+-# config: __SYSCONFIG__/ebtables         (text)
+-#         __SYSCONFIG__/ebtables.<table> (binary)
++# config: @sysconfigdir@/ebtables         (text)
++#         @sysconfigdir@/ebtables.<table> (binary)
+ 
+ source /etc/init.d/functions
+ source /etc/sysconfig/network
+@@ -18,9 +18,9 @@ source /etc/sysconfig/network
+ # Check that networking is up.
+ [ ${NETWORKING} = "no" ] && exit 0
+ 
+-[ -x __EXEC_PATH__/ebtables ] || exit 1
+-[ -x __EXEC_PATH__/ebtables-save ] || exit 1
+-[ -x __EXEC_PATH__/ebtables-restore ] || exit 1
++[ -x @sbindir@/ebtables ] || exit 1
++[ -x @sbindir@/ebtables-save ] || exit 1
++[ -x @sbindir@/ebtables-restore ] || exit 1
+ 
+ RETVAL=0
+ prog="ebtables"
+@@ -35,17 +35,17 @@ EBTABLES_SAVE_ON_STOP="no"
+ EBTABLES_SAVE_ON_RESTART="no"
+ EBTABLES_SAVE_COUNTER="no"
+ 
+-config=__SYSCONFIG__/$prog-config
++config=@sysconfigdir@/$prog-config
+ [ -f "$config" ] && . "$config"
+ 
+ start() {
+ 	echo -n $"Starting $desc ($prog): "
+ 	if [ "$EBTABLES_BINARY_FORMAT" = "yes" ]; then
+-		for table in $(ls __SYSCONFIG__/ebtables.* 2>/dev/null | sed -e 's/.*ebtables\.//' -e '/save/d' ); do
+-			__EXEC_PATH__/ebtables -t $table --atomic-file __SYSCONFIG__/ebtables.$table --atomic-commit || RETVAL=1
++		for table in $(ls @sysconfigdir@/ebtables.* 2>/dev/null | sed -e 's/.*ebtables\.//' -e '/save/d' ); do
++			@sbindir@/ebtables -t $table --atomic-file @sysconfigdir@/ebtables.$table --atomic-commit || RETVAL=1
+ 		done
+ 	else
+-		__EXEC_PATH__/ebtables-restore < /etc/sysconfig/ebtables || RETVAL=1
++		@sbindir@/ebtables-restore < /etc/sysconfig/ebtables || RETVAL=1
+ 	fi
+ 
+ 	if [ $RETVAL -eq 0 ]; then
+@@ -60,7 +60,7 @@ start() {
+ stop() {
+ 	echo -n $"Stopping $desc ($prog): "
+ 	for table in $(grep '^ebtable_' /proc/modules | sed -e 's/ebtable_\([^ ]*\).*/\1/'); do
+-		__EXEC_PATH__/ebtables -t $table --init-table || RETVAL=1
++		@sbindir@/ebtables -t $table --init-table || RETVAL=1
+ 	done
+ 
+ 	if [ "$EBTABLES_MODULES_UNLOAD" = "yes" ]; then
+@@ -86,22 +86,22 @@ restart() {
+ save() {
+ 	echo -n $"Saving $desc ($prog): "
+ 	if [ "$EBTABLES_TEXT_FORMAT" = "yes" ]; then
+-		if [ -e __SYSCONFIG__/ebtables ]; then
+-			chmod 0600 __SYSCONFIG__/ebtables
+-			mv -f __SYSCONFIG__/ebtables __SYSCONFIG__/ebtables.save
++		if [ -e @sysconfigdir@/ebtables ]; then
++			chmod 0600 @sysconfigdir@/ebtables
++			mv -f @sysconfigdir@/ebtables @sysconfigdir@/ebtables.save
+ 		fi
+-		__EXEC_PATH__/ebtables-save > __SYSCONFIG__/ebtables || RETVAL=1
++		@sbindir@/ebtables-save > @sysconfigdir@/ebtables || RETVAL=1
+ 	fi
+ 	if [ "$EBTABLES_BINARY_FORMAT" = "yes" ]; then
+-		rm -f __SYSCONFIG__/ebtables.*.save
+-		for oldtable in $(ls __SYSCONFIG__/ebtables.* 2>/dev/null | grep -vF 'ebtables.save'); do
++		rm -f @sysconfigdir@/ebtables.*.save
++		for oldtable in $(ls @sysconfigdir@/ebtables.* 2>/dev/null | grep -vF 'ebtables.save'); do
+ 			chmod 0600 $oldtable
+ 			mv -f $oldtable $oldtable.save
+ 		done
+ 		for table in $(grep '^ebtable_' /proc/modules | sed -e 's/ebtable_\([^ ]*\).*/\1/'); do
+-			__EXEC_PATH__/ebtables -t $table --atomic-file __SYSCONFIG__/ebtables.$table --atomic-save || RETVAL=1
++			@sbindir@/ebtables -t $table --atomic-file @sysconfigdir@/ebtables.$table --atomic-save || RETVAL=1
+ 			if [ "$EBTABLES_SAVE_COUNTER" = "no" ]; then
+-				__EXEC_PATH__/ebtables -t $table --atomic-file __SYSCONFIG__/ebtables.$table -Z || RETVAL=1
++				@sbindir@/ebtables -t $table --atomic-file @sysconfigdir@/ebtables.$table -Z || RETVAL=1
+ 			fi
+ 		done
+ 	fi
+@@ -134,7 +134,7 @@ case "$1" in
+ 	save
+ 	;;
+   status)
+-	__EXEC_PATH__/ebtables-save
++	@sbindir@/ebtables-save
+ 	RETVAL=$?
+ 	;;
+   *)
+-- 
+2.21.0
+
diff --git a/SOURCES/0027-extensions-use-__attribute__-constructor-for-autoreg.patch b/SOURCES/0027-extensions-use-__attribute__-constructor-for-autoreg.patch
new file mode 100644
index 0000000..cdd7357
--- /dev/null
+++ b/SOURCES/0027-extensions-use-__attribute__-constructor-for-autoreg.patch
@@ -0,0 +1,410 @@
+From 22476c0758b930b972c5397ee3ba1bef5ccf6223 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Wed, 27 Jun 2018 11:50:41 +0200
+Subject: [PATCH] extensions: use __attribute__((constructor)) for
+ autoregistration
+
+The ebtables initialization is easier, and, judging from the "static"
+recipe in Makefile, that calling ebt_*_register ahead of main is
+safe.
+
+This means that a static build won't need the pseudomain hack,
+and that -nostartfiles can also go away.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ Makefile                    | 34 +---------------------------------
+ extensions/Makefile         |  4 ++--
+ extensions/ebt_802_3.c      |  2 +-
+ extensions/ebt_among.c      |  2 +-
+ extensions/ebt_arp.c        |  2 +-
+ extensions/ebt_arpreply.c   |  2 +-
+ extensions/ebt_ip.c         |  2 +-
+ extensions/ebt_ip6.c        |  2 +-
+ extensions/ebt_limit.c      |  2 +-
+ extensions/ebt_log.c        |  2 +-
+ extensions/ebt_mark.c       |  2 +-
+ extensions/ebt_mark_m.c     |  2 +-
+ extensions/ebt_nat.c        |  2 +-
+ extensions/ebt_nflog.c      |  2 +-
+ extensions/ebt_pkttype.c    |  2 +-
+ extensions/ebt_redirect.c   |  2 +-
+ extensions/ebt_standard.c   |  2 +-
+ extensions/ebt_stp.c        |  2 +-
+ extensions/ebt_string.c     |  2 +-
+ extensions/ebt_ulog.c       |  2 +-
+ extensions/ebt_vlan.c       |  2 +-
+ extensions/ebtable_broute.c |  2 +-
+ extensions/ebtable_filter.c |  2 +-
+ extensions/ebtable_nat.c    |  2 +-
+ include/ebtables_u.h        |  2 ++
+ 25 files changed, 27 insertions(+), 57 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 7c70db0267983..4d7b10f4916d6 100644
+--- a/Makefile
++++ b/Makefile
+@@ -116,39 +116,7 @@ daemon: ebtablesd ebtablesu
+ # a little scripting for a static binary, making one for ebtables-restore
+ # should be completely analogous
+ static: extensions/ebt_*.c extensions/ebtable_*.c ebtables.c communication.c ebtables-standalone.c getethertype.c libebtc.c useful_functions.c
+-	cp ebtables-standalone.c ebtables-standalone.c_ ; \
+-	cp include/ebtables_u.h include/ebtables_u.h_ ; \
+-	sed "s/ main(/ pseudomain(/" ebtables-standalone.c > ebtables-standalone.c__ ; \
+-	mv ebtables-standalone.c__ ebtables-standalone.c ; \
+-	printf "\nint main(int argc, char *argv[])\n{\n "  >> ebtables-standalone.c ; \
+-	for arg in $(EXT_FUNC) \
+-	; do \
+-	sed s/_init/_$${arg}_init/ extensions/ebt_$${arg}.c > extensions/ebt_$${arg}.c_ ; \
+-	mv extensions/ebt_$${arg}.c_ extensions/ebt_$${arg}.c ; \
+-	printf "\t%s();\n" _$${arg}_init >> ebtables-standalone.c ; \
+-	printf "extern void %s();\n" _$${arg}_init >> include/ebtables_u.h ; \
+-	done ; \
+-	for arg in $(EXT_TABLES) \
+-	; do \
+-	sed s/_init/_t_$${arg}_init/ extensions/ebtable_$${arg}.c > extensions/ebtable_$${arg}.c_ ; \
+-	mv extensions/ebtable_$${arg}.c_ extensions/ebtable_$${arg}.c ; \
+-	printf "\t%s();\n" _t_$${arg}_init >> ebtables-standalone.c ; \
+-	printf "extern void %s();\n" _t_$${arg}_init >> include/ebtables_u.h ; \
+-	done ; \
+-	printf "\n\tpseudomain(argc, argv);\n\treturn 0;\n}\n" >> ebtables-standalone.c ;\
+-	$(CC) $(CFLAGS) $(LDFLAGS) $(PROGSPECS) -o $@ $^ -I$(KERNEL_INCLUDES) -Iinclude ; \
+-	for arg in $(EXT_FUNC) \
+-	; do \
+-	sed "s/ .*_init/ _init/" extensions/ebt_$${arg}.c > extensions/ebt_$${arg}.c_ ; \
+-	mv extensions/ebt_$${arg}.c_ extensions/ebt_$${arg}.c ; \
+-	done ; \
+-	for arg in $(EXT_TABLES) \
+-	; do \
+-	sed "s/ .*_init/ _init/" extensions/ebtable_$${arg}.c > extensions/ebtable_$${arg}.c_ ; \
+-	mv extensions/ebtable_$${arg}.c_ extensions/ebtable_$${arg}.c ; \
+-	done ; \
+-	mv ebtables-standalone.c_ ebtables-standalone.c ; \
+-	mv include/ebtables_u.h_ include/ebtables_u.h
++	$(CC) $(CFLAGS) $(LDFLAGS) $(PROGSPECS) -o $@ $^ -I$(KERNEL_INCLUDES) -Iinclude
+ 
+ tmp1:=$(shell printf $(BINDIR) | sed 's/\//\\\//g')
+ tmp2:=$(shell printf $(SYSCONFIGDIR) | sed 's/\//\\\//g')
+diff --git a/extensions/Makefile b/extensions/Makefile
+index 60a70a2298357..daa11fce36e5e 100644
+--- a/extensions/Makefile
++++ b/extensions/Makefile
+@@ -11,13 +11,13 @@ EXT_LIBSI+=$(foreach T,$(EXT_FUNC), -lebt_$(T))
+ EXT_LIBSI+=$(foreach T,$(EXT_TABLES), -lebtable_$(T))
+ 
+ extensions/ebt_%.so: extensions/ebt_%.o
+-	$(CC) $(LDFLAGS) -shared -o $@ -lc $< -nostartfiles
++	$(CC) $(LDFLAGS) -shared -o $@ -lc $<
+ 
+ extensions/libebt_%.so: extensions/ebt_%.so
+ 	mv $< $@
+ 
+ extensions/ebtable_%.so: extensions/ebtable_%.o
+-	$(CC) $(LDFLAGS) -shared -o $@ -lc $< -nostartfiles
++	$(CC) $(LDFLAGS) -shared -o $@ -lc $<
+ 
+ extensions/libebtable_%.so: extensions/ebtable_%.so
+ 	mv $< $@
+diff --git a/extensions/ebt_802_3.c b/extensions/ebt_802_3.c
+index 458484939231d..d70fd441e60db 100644
+--- a/extensions/ebt_802_3.c
++++ b/extensions/ebt_802_3.c
+@@ -141,7 +141,7 @@ static struct ebt_u_match _802_3_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&_802_3_match);
+ }
+diff --git a/extensions/ebt_among.c b/extensions/ebt_among.c
+index e4fc5ac22a005..b1560e8f09e8d 100644
+--- a/extensions/ebt_among.c
++++ b/extensions/ebt_among.c
+@@ -491,7 +491,7 @@ static struct ebt_u_match among_match = {
+ 	.extra_ops 	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&among_match);
+ }
+diff --git a/extensions/ebt_arp.c b/extensions/ebt_arp.c
+index b2819553ab313..84b6e900eff62 100644
+--- a/extensions/ebt_arp.c
++++ b/extensions/ebt_arp.c
+@@ -362,7 +362,7 @@ static struct ebt_u_match arp_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&arp_match);
+ }
+diff --git a/extensions/ebt_arpreply.c b/extensions/ebt_arpreply.c
+index 51eda66adbff3..399868bdd9059 100644
+--- a/extensions/ebt_arpreply.c
++++ b/extensions/ebt_arpreply.c
+@@ -133,7 +133,7 @@ static struct ebt_u_target arpreply_target =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_target(&arpreply_target);
+ }
+diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c
+index 1ffdb95f156df..faffade35f7f1 100644
+--- a/extensions/ebt_ip.c
++++ b/extensions/ebt_ip.c
+@@ -472,7 +472,7 @@ static struct ebt_u_match ip_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&ip_match);
+ }
+diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c
+index 347797b4afe18..17a4303177284 100644
+--- a/extensions/ebt_ip6.c
++++ b/extensions/ebt_ip6.c
+@@ -413,7 +413,7 @@ static struct ebt_u_match ip6_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&ip6_match);
+ }
+diff --git a/extensions/ebt_limit.c b/extensions/ebt_limit.c
+index 2cbf4dee51fb4..1fe9d84ffd137 100644
+--- a/extensions/ebt_limit.c
++++ b/extensions/ebt_limit.c
+@@ -212,7 +212,7 @@ static struct ebt_u_match limit_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&limit_match);
+ }
+diff --git a/extensions/ebt_log.c b/extensions/ebt_log.c
+index 97d50919d25ca..b5d32321948c8 100644
+--- a/extensions/ebt_log.c
++++ b/extensions/ebt_log.c
+@@ -217,7 +217,7 @@ static struct ebt_u_watcher log_watcher =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_watcher(&log_watcher);
+ }
+diff --git a/extensions/ebt_mark.c b/extensions/ebt_mark.c
+index 4cf1378d5085c..b4f93b5960b6a 100644
+--- a/extensions/ebt_mark.c
++++ b/extensions/ebt_mark.c
+@@ -172,7 +172,7 @@ static struct ebt_u_target mark_target =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_target(&mark_target);
+ }
+diff --git a/extensions/ebt_mark_m.c b/extensions/ebt_mark_m.c
+index 7561f059c0108..b6d11a2903bbe 100644
+--- a/extensions/ebt_mark_m.c
++++ b/extensions/ebt_mark_m.c
+@@ -121,7 +121,7 @@ static struct ebt_u_match mark_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&mark_match);
+ }
+diff --git a/extensions/ebt_nat.c b/extensions/ebt_nat.c
+index 00d9cd4083247..fe7e9875498e0 100644
+--- a/extensions/ebt_nat.c
++++ b/extensions/ebt_nat.c
+@@ -231,7 +231,7 @@ static struct ebt_u_target dnat_target =
+ 	.extra_ops	= opts_d,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_target(&snat_target);
+ 	ebt_register_target(&dnat_target);
+diff --git a/extensions/ebt_nflog.c b/extensions/ebt_nflog.c
+index 405673a01f893..04c547d06cee0 100644
+--- a/extensions/ebt_nflog.c
++++ b/extensions/ebt_nflog.c
+@@ -166,7 +166,7 @@ static struct ebt_u_watcher nflog_watcher = {
+ 	.extra_ops = nflog_opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_watcher(&nflog_watcher);
+ }
+diff --git a/extensions/ebt_pkttype.c b/extensions/ebt_pkttype.c
+index 486c85c3c3faf..bf578fcf98f92 100644
+--- a/extensions/ebt_pkttype.c
++++ b/extensions/ebt_pkttype.c
+@@ -125,7 +125,7 @@ static struct ebt_u_match pkttype_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&pkttype_match);
+ }
+diff --git a/extensions/ebt_redirect.c b/extensions/ebt_redirect.c
+index 3f8227a917583..59fe818f7b205 100644
+--- a/extensions/ebt_redirect.c
++++ b/extensions/ebt_redirect.c
+@@ -108,7 +108,7 @@ static struct ebt_u_target redirect_target =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_target(&redirect_target);
+ }
+diff --git a/extensions/ebt_standard.c b/extensions/ebt_standard.c
+index 81edead71a840..f3c33086bac53 100644
+--- a/extensions/ebt_standard.c
++++ b/extensions/ebt_standard.c
+@@ -84,7 +84,7 @@ static struct ebt_u_target standard =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_target(&standard);
+ }
+diff --git a/extensions/ebt_stp.c b/extensions/ebt_stp.c
+index 5c5fc3334311d..311bc63d2cb0c 100644
+--- a/extensions/ebt_stp.c
++++ b/extensions/ebt_stp.c
+@@ -337,7 +337,7 @@ static struct ebt_u_match stp_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&stp_match);
+ }
+diff --git a/extensions/ebt_string.c b/extensions/ebt_string.c
+index 7d24f8002f4d7..97fbe19eca54f 100644
+--- a/extensions/ebt_string.c
++++ b/extensions/ebt_string.c
+@@ -312,7 +312,7 @@ static struct ebt_u_match string_match =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&string_match);
+ }
+diff --git a/extensions/ebt_ulog.c b/extensions/ebt_ulog.c
+index 54eec53f7069f..72a6c8b199b42 100644
+--- a/extensions/ebt_ulog.c
++++ b/extensions/ebt_ulog.c
+@@ -180,7 +180,7 @@ static struct ebt_u_watcher ulog_watcher =
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_watcher(&ulog_watcher);
+ }
+diff --git a/extensions/ebt_vlan.c b/extensions/ebt_vlan.c
+index 0a37067b5ebde..0818d48e8521b 100644
+--- a/extensions/ebt_vlan.c
++++ b/extensions/ebt_vlan.c
+@@ -181,7 +181,7 @@ static struct ebt_u_match vlan_match = {
+ 	.extra_ops	= opts,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_match(&vlan_match);
+ }
+diff --git a/extensions/ebtable_broute.c b/extensions/ebtable_broute.c
+index 5259355e2b01b..c106f0825a147 100644
+--- a/extensions/ebtable_broute.c
++++ b/extensions/ebtable_broute.c
+@@ -23,7 +23,7 @@ ebt_u_table table =
+ 	.help		= print_help,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_table(&table);
+ }
+diff --git a/extensions/ebtable_filter.c b/extensions/ebtable_filter.c
+index e41fb84ffbf20..c0bf105d75986 100644
+--- a/extensions/ebtable_filter.c
++++ b/extensions/ebtable_filter.c
+@@ -29,7 +29,7 @@ static struct ebt_u_table table =
+ 	.help		= print_help,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_table(&table);
+ }
+diff --git a/extensions/ebtable_nat.c b/extensions/ebtable_nat.c
+index b21c9ddaedd46..ee044823866c3 100644
+--- a/extensions/ebtable_nat.c
++++ b/extensions/ebtable_nat.c
+@@ -30,7 +30,7 @@ ebt_u_table table =
+ 	.help		= print_help,
+ };
+ 
+-void _init(void)
++static void _INIT(void)
+ {
+ 	ebt_register_table(&table);
+ }
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index 3235bf5967055..7f5968dc6f39d 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -44,6 +44,8 @@
+ #define EBT_ALIGN(s) (((s) + (EBT_MIN_ALIGN-1)) & ~(EBT_MIN_ALIGN-1))
+ #define ERRORMSG_MAXLEN 128
+ 
++#define _INIT __attribute__((constructor)) _init
++
+ struct ebt_u_entries
+ {
+ 	int policy;
+-- 
+2.21.0
+
diff --git a/SOURCES/0028-Add-.gitignore.patch b/SOURCES/0028-Add-.gitignore.patch
new file mode 100644
index 0000000..ec69317
--- /dev/null
+++ b/SOURCES/0028-Add-.gitignore.patch
@@ -0,0 +1,28 @@
+From 038a7384ffce9b3a134eee81a5f490391b505ee4 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Wed, 27 Jun 2018 11:50:42 +0200
+Subject: [PATCH] Add .gitignore
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ .gitignore | 7 +++++++
+ 1 file changed, 7 insertions(+)
+ create mode 100644 .gitignore
+
+diff --git a/.gitignore b/.gitignore
+new file mode 100644
+index 0000000000000..d2fc36e763a45
+--- /dev/null
++++ b/.gitignore
+@@ -0,0 +1,7 @@
++*.o
++*.so
++/ebtables
++/ebtables-restore
++/ebtablesd
++/ebtablesu
++/static
+-- 
+2.21.0
+
diff --git a/SOURCES/0029-build-move-to-automake.patch b/SOURCES/0029-build-move-to-automake.patch
new file mode 100644
index 0000000..ad21775
--- /dev/null
+++ b/SOURCES/0029-build-move-to-automake.patch
@@ -0,0 +1,512 @@
+From fe81d4fa47b6b69e01de7f7d41002b8e12fec284 Mon Sep 17 00:00:00 2001
+From: Jan Engelhardt <jengelh@inai.de>
+Date: Wed, 27 Jun 2018 11:50:43 +0200
+Subject: [PATCH] build: move to automake
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ .gitignore    |  23 +++++-
+ INSTALL       |  99 +++++++++--------------
+ Makefile      | 214 --------------------------------------------------
+ Makefile.am   |  76 ++++++++++++++++++
+ autogen.sh    |   4 +
+ configure.ac  |  23 ++++++
+ m4/.gitignore |   2 +
+ 7 files changed, 163 insertions(+), 278 deletions(-)
+ delete mode 100644 Makefile
+ create mode 100644 Makefile.am
+ create mode 100755 autogen.sh
+ create mode 100644 configure.ac
+ create mode 100644 m4/.gitignore
+
+diff --git a/.gitignore b/.gitignore
+index d2fc36e763a45..1fff83c78ba13 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -1,7 +1,28 @@
+-*.o
++*.a
++*.la
++*.lo
+ *.so
++*.o
++.deps/
++.dirstamp
++.libs/
++Makefile
++Makefile.in
++
++/aclocal.m4
++/autom4te.cache/
++/build-aux/
++/config.*
++/configure
++/libtool
++/stamp-h1
++
+ /ebtables
++/ebtables-config
+ /ebtables-restore
++/ebtables-save
++/ebtables.8
++/ebtables.sysv
+ /ebtablesd
+ /ebtablesu
+ /static
+diff --git a/INSTALL b/INSTALL
+index e90d5c103bdc4..c43d95c3ed256 100644
+--- a/INSTALL
++++ b/INSTALL
+@@ -1,63 +1,36 @@
+-FOLLOW THESE SIMPLE GUIDELINES:
+--------------------------------
+-
+-Compiling the source code:
+-%make
+-Put the files in the right directories:
+-%make install
+-
+-If you are using the CVS code or need your own kernel includes, do this
+-instead (change the include directory to the appropriate one):
+-%make install KERNEL_INCLUDES=/usr/src/linux/include
+-
+-If you want to make a static binary for ebtables, containing all the
+-extensions, without shared libraries, do this (this will make a
+-binary called 'static', which you can rename):
+-%make static
+-
+-WHAT GETS INSTALLED AND WHAT OPTIONS ARE AVAILABLE?
+----------------------------------------------------
+-
+-- The ebtables manual gets installed in /usr/local/man/man8
+-  To put the manual somewhere else, include MANDIR=<<man-path/man>> as
+-  option on the command line.
+-  The Makefile will append /man8/ebtables.8.
+-- ethertypes is by default placed in /etc/, if you
+-  want to change this, include ETHERTYPESPATH=<<path>>.
+-- The userspace programs ebtables ebtables-save and ebtables-restore are
+-  are copied by default to /usr/local/sbin/ebtables. If you want to put
+-  the executables somewhere else, include BINPATH=<<path>>.
+-- The ebtables initialisation file (enabling use of 'service ebtables') is
+-  copied to /etc/rc.d/init.d (change with option INITDIR)
+-- The ebtables configuration file (ebtables-config) is copied to /etc/sysconfig
+-- ebtables can use a lock file to enable concurrent execution of the ebtables
+-  tool. The standard location of the lock file is /var/lib/ebtables/lock.
+-  Include LOCKFILE=<<path-to-file>> if you want to use another file.
+-
+-That's all
+-
+-You can also use a base directory different from the root directory (/),
+-using the DESTDIR option. See the Makefile for more details.
+-
+-You might need to set LDFLAGS=-Wl,-no-as-needed to build ebtables correctly
+-on your system.
+-
+-ADDITIONAL PROGRAMS:
+-----------------------
+--- examples/ulog/test_ulog.c --
+-
+-Contains an example to receive and parse netlink messages containing
+-packets seen by the ebtables ulog watcher.
+-
+-Compile with:
+-%make test_ulog KERNEL_INCLUDES=/usr/src/linux/include
+-
+-Usage:
+-%examples/ulog/test_ulog NETLINK_GROUP
+-%ebtables -A chain --ulog-nlgroup NETLINK_GROUP
+-
+--- examples/perf_test/perf_test --
+-
+-A test script to compare the performance for the different ways to
+-construct an ebtables table. This is deprecated and should probably
+-be ignored.
++Installation instructions for iptables
++======================================
++
++ebtables uses the well-known configure(autotools) infrastructure.
++
++	$ ./configure
++	$ make
++	# make install
++
++
++Prerequisites
++=============
++
++	* no kernel-source required
++
++	* but obviously a compiler, glibc-devel and linux-kernel-headers
++	  (/usr/include/linux)
++
++
++Configuring and compiling
++=========================
++
++./configure [options]
++
++--prefix=
++
++	The prefix to put all installed files under. It defaults to
++	/usr/local, so the binaries will go into /usr/local/bin, sbin,
++	manpages into /usr/local/share/man, etc.
++
++If you want to enable debugging, use
++
++	./configure CFLAGS="-ggdb3 -O0" CPPFLAGS="-DEBT_DEBUG"
++
++(-O0 is used to turn off instruction reordering, which makes debugging
++much easier.)
+diff --git a/Makefile b/Makefile
+deleted file mode 100644
+index 4d7b10f4916d6..0000000000000
+--- a/Makefile
++++ /dev/null
+@@ -1,214 +0,0 @@
+-# ebtables Makefile
+-
+-PROGNAME:=ebtables
+-PROGRELEASE:=4
+-PROGVERSION_:=2.0.10
+-PROGVERSION:=$(PROGVERSION_)-$(PROGRELEASE)
+-PROGDATE:=December\ 2011
+-LOCKFILE?=/var/lib/ebtables/lock
+-LOCKDIR:=$(shell echo $(LOCKFILE) | sed 's/\(.*\)\/.*/\1/')/
+-
+-# default paths
+-LIBDIR:=/usr/lib
+-MANDIR:=/usr/local/man
+-BINDIR:=/usr/local/sbin
+-ETCDIR:=/etc
+-INITDIR:=/etc/rc.d/init.d
+-SYSCONFIGDIR:=/etc/sysconfig
+-DESTDIR:=
+-
+-CFLAGS:=-Wall -Wunused -Werror
+-CFLAGS_SH_LIB:=-fPIC -O3
+-CC:=gcc
+-
+-ifeq ($(shell uname -m),sparc64)
+-CFLAGS+=-DEBT_MIN_ALIGN=8 -DKERNEL_64_USERSPACE_32
+-endif
+-
+-include extensions/Makefile
+-
+-OBJECTS2:=getethertype.o communication.o libebtc.o \
+-useful_functions.o ebtables.o
+-
+-OBJECTS:=$(OBJECTS2) $(EXT_OBJS) $(EXT_LIBS)
+-
+-KERNEL_INCLUDES?=include/
+-
+-ETHERTYPESPATH?=$(ETCDIR)
+-ETHERTYPESFILE:=$(ETHERTYPESPATH)/ethertypes
+-
+-PIPE_DIR?=/tmp/$(PROGNAME)-v$(PROGVERSION)
+-PIPE=$(PIPE_DIR)/ebtablesd_pipe
+-EBTD_CMDLINE_MAXLN?=2048
+-EBTD_ARGC_MAX?=50
+-
+-PROGSPECS:=-DPROGVERSION=\"$(PROGVERSION)\" \
+-	-DPROGNAME=\"$(PROGNAME)\" \
+-	-DPROGDATE=\"$(PROGDATE)\" \
+-	-D_PATH_ETHERTYPES=\"$(ETHERTYPESFILE)\" \
+-	-DEBTD_ARGC_MAX=$(EBTD_ARGC_MAX) \
+-	-DEBTD_CMDLINE_MAXLN=$(EBTD_CMDLINE_MAXLN) \
+-	-DLOCKFILE=\"$(LOCKFILE)\" \
+-	-DLOCKDIR=\"$(LOCKDIR)\"
+-
+-# You can probably ignore this, ebtables{u,d} are normally not used
+-PROGSPECSD:=-DPROGVERSION=\"$(PROGVERSION)\" \
+-	-DPROGNAME=\"$(PROGNAME)\" \
+-	-DPROGDATE=\"$(PROGDATE)\" \
+-	-D_PATH_ETHERTYPES=\"$(ETHERTYPESFILE)\" \
+-	-DEBTD_CMDLINE_MAXLN=$(EBTD_CMDLINE_MAXLN) \
+-	-DEBTD_ARGC_MAX=$(EBTD_ARGC_MAX) \
+-	-DEBTD_PIPE=\"$(PIPE)\" \
+-	-DEBTD_PIPE_DIR=\"$(PIPE_DIR)\"
+-
+-# Uncomment for debugging (slower)
+-#PROGSPECS+=-DEBT_DEBUG
+-#PROGSPECSD+=-DEBT_DEBUG
+-#CFLAGS+=-ggdb
+-
+-all: ebtables ebtables-restore
+-
+-communication.o: communication.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
+-
+-libebtc.o: libebtc.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
+-
+-useful_functions.o: useful_functions.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
+-
+-getethertype.o: getethertype.c include/ethernetdb.h
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c -o $@ $< -Iinclude/
+-
+-ebtables.o: ebtables.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
+-
+-ebtables-standalone.o: ebtables-standalone.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c $< -o $@ -I$(KERNEL_INCLUDES)
+-
+-libebtc.so: $(OBJECTS2)
+-	$(CC) -shared $(LDFLAGS) -Wl,-soname,libebtc.so -o libebtc.so -lc $(OBJECTS2)
+-
+-ebtables: $(OBJECTS) ebtables-standalone.o libebtc.so
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(LDFLAGS) -o $@ ebtables-standalone.o -I$(KERNEL_INCLUDES) -L. -Lextensions -lebtc $(EXT_LIBSI) \
+-	-Wl,-rpath,$(LIBDIR)
+-
+-ebtablesu: ebtablesu.c
+-	$(CC) $(CFLAGS) $(PROGSPECSD) $< -o $@
+-
+-ebtablesd.o: ebtablesd.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(PROGSPECSD) -c $< -o $@  -I$(KERNEL_INCLUDES)
+-
+-ebtablesd: $(OBJECTS) ebtablesd.o libebtc.so
+-	$(CC) $(CFLAGS) -o $@ ebtablesd.o -I$(KERNEL_INCLUDES) -L. -Lextensions -lebtc $(EXT_LIBSI) \
+-	-Wl,-rpath,$(LIBDIR)
+-
+-ebtables-restore.o: ebtables-restore.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(PROGSPECS) -c $< -o $@  -I$(KERNEL_INCLUDES)
+-
+-ebtables-restore: $(OBJECTS) ebtables-restore.o libebtc.so
+-	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ ebtables-restore.o -I$(KERNEL_INCLUDES) -L. -Lextensions -lebtc $(EXT_LIBSI) \
+-	-Wl,-rpath,$(LIBDIR)
+-
+-.PHONY: daemon
+-daemon: ebtablesd ebtablesu
+-
+-# a little scripting for a static binary, making one for ebtables-restore
+-# should be completely analogous
+-static: extensions/ebt_*.c extensions/ebtable_*.c ebtables.c communication.c ebtables-standalone.c getethertype.c libebtc.c useful_functions.c
+-	$(CC) $(CFLAGS) $(LDFLAGS) $(PROGSPECS) -o $@ $^ -I$(KERNEL_INCLUDES) -Iinclude
+-
+-tmp1:=$(shell printf $(BINDIR) | sed 's/\//\\\//g')
+-tmp2:=$(shell printf $(SYSCONFIGDIR) | sed 's/\//\\\//g')
+-tmp3:=$(shell printf $(PIPE) | sed 's/\//\\\//g')
+-.PHONY: scripts
+-scripts: ebtables-save.in ebtables.sysv.in ebtables-config.in
+-	sed -e 's/[@]sbindir@/$(tmp1)/g' <ebtables-save.in >ebtables-save_
+-	mkdir -p $(DESTDIR)$(BINDIR)
+-	install -m 0755 ebtables-save_ $(DESTDIR)$(BINDIR)/ebtables-save
+-	sed -e 's/[@]sbindir@/$(tmp1)/g' -e 's/[@]sysconfigdir@/$(tmp2)/g' <ebtables.sysv.in >ebtables.sysv_
+-	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(INITDIR); fi
+-	if test -d $(DESTDIR)$(INITDIR); then install -m 0755 ebtables.sysv_ $(DESTDIR)$(INITDIR)/ebtables; fi
+-	sed -e 's/[@]sysconfigdir@/$(tmp2)/g' <ebtables-config >ebtables-config_
+-	if [ "$(DESTDIR)" != "" ]; then mkdir -p $(DESTDIR)$(SYSCONFIGDIR); fi
+-	if test -d $(DESTDIR)$(SYSCONFIGDIR); then install -m 0600 ebtables-config_ $(DESTDIR)$(SYSCONFIGDIR)/ebtables-config; fi
+-	rm -f ebtables-save_ ebtables.sysv_ ebtables-config_
+-
+-tmp4:=$(shell printf $(LOCKFILE) | sed 's/\//\\\//g')
+-$(MANDIR)/man8/ebtables.8: ebtables.8.in
+-	mkdir -p $(DESTDIR)$(@D)
+-	sed -e 's/[@]PACKAGE_VERSION@/$(PROGVERSION)/' -e 's/[@]PACKAGE_DATE@/$(PROGDATE)/' -e 's/[@]LOCKFILE@/$(tmp4)/' <$< >ebtables.8_
+-	install -m 0644 ebtables.8_ $(DESTDIR)$@
+-	rm -f ebtables.8_
+-
+-$(DESTDIR)$(ETHERTYPESFILE): ethertypes
+-	mkdir -p $(@D)
+-	install -m 0644 $< $@
+-
+-.PHONY: exec
+-exec: ebtables ebtables-restore
+-	mkdir -p $(DESTDIR)$(BINDIR)
+-	install -m 0755 $(PROGNAME) $(DESTDIR)$(BINDIR)/$(PROGNAME)
+-	install -m 0755 ebtables-restore $(DESTDIR)$(BINDIR)/ebtables-restore
+-
+-.PHONY: install
+-install: $(MANDIR)/man8/ebtables.8 $(DESTDIR)$(ETHERTYPESFILE) exec scripts
+-	mkdir -p $(DESTDIR)$(LIBDIR)
+-	install -m 0755 extensions/*.so $(DESTDIR)$(LIBDIR)
+-	install -m 0755 *.so $(DESTDIR)$(LIBDIR)
+-
+-.PHONY: clean
+-clean:
+-	rm -f ebtables ebtables-restore ebtablesd ebtablesu static
+-	rm -f *.o *~ *.so
+-	rm -f extensions/*.o extensions/*.c~ extensions/*.so include/*~
+-
+-DIR:=$(PROGNAME)-v$(PROGVERSION)
+-CVSDIRS:=CVS extensions/CVS examples/CVS examples/perf_test/CVS \
+-examples/ulog/CVS include/CVS
+-# This is used to make a new userspace release, some files are altered so
+-# do this on a temporary version
+-.PHONY: release
+-release:
+-	rm -f extensions/ebt_inat.c
+-	rm -rf $(CVSDIRS)
+-	mkdir -p include/linux/netfilter_bridge
+-	install -m 0644 \
+-		$(KERNEL_INCLUDES)/linux/netfilter_bridge.h include/linux/
+-# To keep possible compile error complaints about undefined ETH_P_8021Q
+-# off my back
+-	install -m 0644 \
+-		$(KERNEL_INCLUDES)/linux/if_ether.h include/linux/
+-	install -m 0644 \
+-		$(KERNEL_INCLUDES)/linux/types.h include/linux/
+-	install -m 0644 \
+-		$(KERNEL_INCLUDES)/linux/netfilter_bridge/*.h \
+-		include/linux/netfilter_bridge/
+-	install -m 0644 \
+-		include/ebtables.h include/linux/netfilter_bridge/
+-	make clean
+-	touch *
+-	touch extensions/*
+-	touch include/*
+-	touch include/linux/*
+-	touch include/linux/netfilter_bridge/*
+-	sed -i -e 's/$$(VERSION)/$(PROGVERSION)/' -e 's/$$(DATE)/$(PROGDATE)/' -e 's/$$(LOCKFILE)/$(tmp4)/' <ebtables.8.in >ebtables.8
+-	sed -i -e 's/$$(VERSION)/$(PROGVERSION_)/' -e 's/$$(RELEASE)/$(PROGRELEASE)/' ebtables.spec
+-	cd ..;tar -c $(DIR) | gzip >$(DIR).tar.gz; cd -
+-	rm -rf include/linux
+-
+-# This will make the rpm and put it in /usr/src/redhat/RPMS
+-# (do this as root after make release)
+-.PHONY: rpmbuild
+-rpmbuild:
+-	cp ../$(DIR).tar.gz /usr/src/redhat/SOURCES/
+-	rpmbuild --buildroot $(shell mktemp -td $(DIR)-XXXXX) -bb ebtables.spec
+-
+-.PHONY: test_ulog
+-test_ulog: examples/ulog/test_ulog.c getethertype.o
+-	$(CC) $(CFLAGS)  $< -o test_ulog -I$(KERNEL_INCLUDES) -lc \
+-	getethertype.o
+-	mv test_ulog examples/ulog/
+-
+-.PHONY: examples
+-examples: test_ulog
+diff --git a/Makefile.am b/Makefile.am
+new file mode 100644
+index 0000000000000..14938fea4f252
+--- /dev/null
++++ b/Makefile.am
+@@ -0,0 +1,76 @@
++# -*- Makefile -*-
++
++# For debugging, use ./configure CPPFLAGS=-DEBT_DEBUG CFLAGS="-O0 -ggdb3"
++
++PROGNAME = ${PACKAGE_NAME}
++PROGVERSION = ${PACKAGE_VERSION}
++PROGDATE = December\ 2011
++LOCKDIR = /var/lib/ebtables
++LOCKFILE = ${LOCKDIR}/lock
++INITDIR = /etc/rc.d/init.d
++initddir = ${INITDIR}
++sysconfigdir = ${sysconfdir}/sysconfig
++EBTD_CMDLINE_MAXLN = 2048
++EBTD_ARGC_MAX = 50
++PIPE_DIR = /tmp/${PACKAGE_NAME}-v${PROGVERSION}
++PIPE = ${PIPE_DIR}/ebtablesd_pipe
++
++
++ACLOCAL_AMFLAGS = -I m4
++AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include \
++	-DPROGVERSION=\"${PACKAGE_VERSION}\" -DPROGNAME=\"${PACKAGE_NAME}\" \
++	-DPROGDATE=\"${PROGDATE}\" \
++	-D_PATH_ETHERTYPES=\"${sysconfdir}/ethertypes\" \
++	-DLOCKFILE=\"${LOCKFILE}\" -DLOCKDIR=\"${LOCKDIR}\" \
++	-DEBTD_ARGC_MAX=${EBTD_ARGC_MAX} -DEBTD_CMDLINE_MAXLN=${EBTD_CMDLINE_MAXLN} \
++	-DEBTD_PIPE=\"${PIPE}\" -DEBTD_PIPE_DIR=\"${PIPE_DIR}\"
++AM_CFLAGS = ${regular_CFLAGS}
++
++sbin_PROGRAMS = ebtables ebtablesd ebtablesu ebtables-restore
++EXTRA_PROGRAMS = static examples/ulog/test_ulog
++sysconf_DATA = ethertypes
++sbin_SCRIPTS = ebtables-save
++man8_MANS = ebtables.8
++lib_LTLIBRARIES = libebtc.la
++
++libebtc_la_SOURCES = \
++	communication.c ebtables.c getethertype.c \
++	libebtc.c useful_functions.c \
++	extensions/ebt_802_3.c extensions/ebt_among.c extensions/ebt_arp.c \
++	extensions/ebt_arpreply.c extensions/ebt_ip.c extensions/ebt_ip6.c \
++	extensions/ebt_limit.c extensions/ebt_log.c extensions/ebt_mark.c \
++	extensions/ebt_mark_m.c extensions/ebt_nat.c extensions/ebt_nflog.c \
++	extensions/ebt_pkttype.c extensions/ebt_redirect.c \
++	extensions/ebt_standard.c extensions/ebt_stp.c extensions/ebt_string.c \
++	extensions/ebt_ulog.c extensions/ebt_vlan.c \
++	extensions/ebtable_broute.c extensions/ebtable_filter.c \
++	extensions/ebtable_nat.c
++# Make sure ebtables.c can be built twice
++libebtc_la_CPPFLAGS = ${AM_CPPFLAGS}
++ebtables_SOURCES = ebtables-standalone.c
++ebtables_LDADD = libebtc.la
++ebtablesd_LDADD = libebtc.la
++ebtables_restore_LDADD = libebtc.la
++static_SOURCES = ebtables.c
++static_LDFLAGS = -static
++static_LDADD = libebtc.la
++examples_ulog_test_ulog_SOURCES = examples/ulog/test_ulog.c getethertype.c
++
++daemon: ebtablesd ebtablesu
++exec: ebtables ebtables-restore
++
++CLEANFILES = ebtables-save ebtables.sysv ebtables-config ebtables.8
++
++ebtables-save: ebtables-save.in ${top_builddir}/config.status
++	${AM_V_GEN}sed -e 's![@]sbindir@!${sbindir}!g' <$< >$@
++
++ebtables.sysv: ebtables.sysv.in ${top_builddir}/config.status
++	${AM_V_GEN}sed -e 's![@]sbindir@!${sbindir}!g' -e 's![@]sysconfigdir@!${sysconfigdir}!g' <$< >$@
++
++ebtables-config: ebtables-config.in ${top_builddir}/config.status
++	${AM_V_GEN}sed -e 's![@]sysconfigdir@!${sysconfigdir}!g' <$< >$@
++
++ebtables.8: ebtables.8.in ${top_builddir}/config.status
++	${AM_V_GEN}sed -e 's![@]PACKAGE_VERSION!${PACKAGE_VERSION}!g' \
++		-e 's![@]PACKAGE_DATE@!${PROGDATE}!g' \
++		-e 's![@]LOCKFILE@!${LOCKFILE}!g' <$< >$@
+diff --git a/autogen.sh b/autogen.sh
+new file mode 100755
+index 0000000000000..a0c4395f356fd
+--- /dev/null
++++ b/autogen.sh
+@@ -0,0 +1,4 @@
++#!/bin/sh -e
++
++autoreconf -fi;
++rm -Rf autom4te*.cache;
+diff --git a/configure.ac b/configure.ac
+new file mode 100644
+index 0000000000000..a3bc3c93a279f
+--- /dev/null
++++ b/configure.ac
+@@ -0,0 +1,23 @@
++AC_INIT([ebtables], [2.0.10.4])
++AC_CONFIG_AUX_DIR([build-aux])
++AC_CONFIG_HEADERS([config.h])
++AC_CONFIG_MACRO_DIR([m4])
++AC_PROG_INSTALL
++AM_INIT_AUTOMAKE([-Wall foreign subdir-objects tar-pax])
++AC_PROG_CC
++AM_PROG_CC_C_O
++AC_DISABLE_STATIC
++m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
++AM_PROG_LIBTOOL
++
++regular_CFLAGS="-Wall -Wunused"
++regular_CPPFLAGS=""
++case "$host" in
++	sparc64-*)
++		regular_CPPFLAGS="$regular_CPPFLAGS -DEBT_MIN_ALIGN=8 -DKERNEL_64_USERSPACE_32";;
++esac
++
++AC_SUBST([regular_CFLAGS])
++AC_SUBST([regular_CPPFLAGS])
++AC_CONFIG_FILES([Makefile])
++AC_OUTPUT
+diff --git a/m4/.gitignore b/m4/.gitignore
+new file mode 100644
+index 0000000000000..64d9bbcdd5ce9
+--- /dev/null
++++ b/m4/.gitignore
+@@ -0,0 +1,2 @@
++/libtool.m4
++/lt*.m4
+-- 
+2.21.0
+
diff --git a/SOURCES/0030-ebtablesd-avoid-build-warning.patch b/SOURCES/0030-ebtablesd-avoid-build-warning.patch
new file mode 100644
index 0000000..fff76c7
--- /dev/null
+++ b/SOURCES/0030-ebtablesd-avoid-build-warning.patch
@@ -0,0 +1,52 @@
+From ee7071e6d7d93f10d38f4eb8c9a4c0ca8984c2d0 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Mon, 2 Jul 2018 18:06:11 +0200
+Subject: [PATCH] ebtablesd: avoid build warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ebtablesd.c:55:43: warning: variable ‘ret’ set but not used [-Wunused-but-set-variable]
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ ebtablesd.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/ebtablesd.c b/ebtablesd.c
+index 062a2d6b5afa3..02d51fa115456 100644
+--- a/ebtablesd.c
++++ b/ebtablesd.c
+@@ -52,7 +52,7 @@ int main(int argc_, char *argv_[])
+ 	char *argv[EBTD_ARGC_MAX], *args[4], name[] = "mkdir",
+ 	     mkdir_option[] = "-p", mkdir_dir[] = EBTD_PIPE_DIR,
+ 	     cmdline[EBTD_CMDLINE_MAXLN];
+-	int readfd, base = 0, offset = 0, n = 0, ret = 0, quotemode = 0;
++	int readfd, base = 0, offset = 0, n = 0, quotemode = 0;
+ 
+ 	/* Make sure the pipe directory exists */
+ 	args[0] = name;
+@@ -74,19 +74,16 @@ int main(int argc_, char *argv_[])
+ 
+ 	if (mkfifo(EBTD_PIPE, 0600) < 0 && errno != EEXIST) {
+ 		printf("Error creating FIFO " EBTD_PIPE "\n");
+-		ret = -1;
+ 		goto do_exit;
+ 	}
+ 
+ 	if ((readfd = open(EBTD_PIPE, O_RDONLY | O_NONBLOCK, 0)) == -1) {
+ 		perror("open");
+-		ret = -1;
+ 		goto do_exit;
+ 	}
+ 
+ 	if (signal(SIGPIPE, sigpipe_handler) == SIG_ERR) {
+ 		perror("signal");
+-		ret = -1;
+ 		goto do_exit;
+ 	}
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0031-extensions-among-Fix-bitmask-check.patch b/SOURCES/0031-extensions-among-Fix-bitmask-check.patch
new file mode 100644
index 0000000..602f61a
--- /dev/null
+++ b/SOURCES/0031-extensions-among-Fix-bitmask-check.patch
@@ -0,0 +1,42 @@
+From 4237aad9c04ac6a82756545a49ae8e9bd0fe9fac Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Mon, 12 Nov 2018 17:50:27 +0100
+Subject: [PATCH] extensions: among: Fix bitmask check
+
+Boolean AND was applied instead of binary one, causing the exclamation
+mark to be printed whenever info->bitmask was non-zero. In practice,
+this leads to incorrect output if e.g. --among-src was given with an
+inverted match as well as --among-dst with a non-inverted one. Output
+would then list both matches as inverted.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/ebt_among.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/extensions/ebt_among.c b/extensions/ebt_among.c
+index b1560e8f09e8d..30c098cf69f96 100644
+--- a/extensions/ebt_among.c
++++ b/extensions/ebt_among.c
+@@ -436,14 +436,14 @@ static void print(const struct ebt_u_entry *entry,
+ 
+ 	if (info->wh_dst_ofs) {
+ 		printf("--among-dst ");
+-		if (info->bitmask && EBT_AMONG_DST_NEG) {
++		if (info->bitmask & EBT_AMONG_DST_NEG) {
+ 			printf("! ");
+ 		}
+ 		wormhash_printout(ebt_among_wh_dst(info));
+ 	}
+ 	if (info->wh_src_ofs) {
+ 		printf("--among-src ");
+-		if (info->bitmask && EBT_AMONG_SRC_NEG) {
++		if (info->bitmask & EBT_AMONG_SRC_NEG) {
+ 			printf("! ");
+ 		}
+ 		wormhash_printout(ebt_among_wh_src(info));
+-- 
+2.21.0
+
diff --git a/SOURCES/0032-ebtables-legacy-renaming.patch b/SOURCES/0032-ebtables-legacy-renaming.patch
new file mode 100644
index 0000000..63cec1f
--- /dev/null
+++ b/SOURCES/0032-ebtables-legacy-renaming.patch
@@ -0,0 +1,145 @@
+From 522ae2fa8b610f13ae69835959dea710f808d887 Mon Sep 17 00:00:00 2001
+From: Arturo Borrero Gonzalez <arturo@netfilter.org>
+Date: Wed, 28 Nov 2018 13:47:28 +0100
+Subject: [PATCH] ebtables: legacy renaming
+
+The original ebtables tool is now the legacy version, let's rename it.
+
+A more uptodate client of the ebtables tool is provided in the iptables
+tarball (ebtables-nft). The new tool was formerly known as ebtables-compat.
+
+The new -legacy binary has no problem if called via a symlink with the
+'ebtables' name, so users can still name this binary with whatever name.
+
+Signed-off-by: Arturo Borrero Gonzalez <arturo@netfilter.org>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ Makefile.am                           | 21 +++++++++++----------
+ ebtables.8.in => ebtables-legacy.8.in | 14 +++++++++++++-
+ ebtables-save.in                      |  2 +-
+ include/ebtables_u.h                  |  2 +-
+ 4 files changed, 26 insertions(+), 13 deletions(-)
+ rename ebtables.8.in => ebtables-legacy.8.in (98%)
+
+diff --git a/Makefile.am b/Makefile.am
+index 14938fea4f252..b16a4d6dba269 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -26,11 +26,11 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include \
+ 	-DEBTD_PIPE=\"${PIPE}\" -DEBTD_PIPE_DIR=\"${PIPE_DIR}\"
+ AM_CFLAGS = ${regular_CFLAGS}
+ 
+-sbin_PROGRAMS = ebtables ebtablesd ebtablesu ebtables-restore
++sbin_PROGRAMS = ebtables-legacy ebtablesd ebtablesu ebtables-legacy-restore
+ EXTRA_PROGRAMS = static examples/ulog/test_ulog
+ sysconf_DATA = ethertypes
+-sbin_SCRIPTS = ebtables-save
+-man8_MANS = ebtables.8
++sbin_SCRIPTS = ebtables-legacy-save
++man8_MANS = ebtables-legacy.8
+ lib_LTLIBRARIES = libebtc.la
+ 
+ libebtc_la_SOURCES = \
+@@ -47,21 +47,22 @@ libebtc_la_SOURCES = \
+ 	extensions/ebtable_nat.c
+ # Make sure ebtables.c can be built twice
+ libebtc_la_CPPFLAGS = ${AM_CPPFLAGS}
+-ebtables_SOURCES = ebtables-standalone.c
+-ebtables_LDADD = libebtc.la
++ebtables_legacy_SOURCES = ebtables-standalone.c
++ebtables_legacy_LDADD = libebtc.la
+ ebtablesd_LDADD = libebtc.la
+-ebtables_restore_LDADD = libebtc.la
++ebtables_legacy_restore_SOURCES = ebtables-restore.c
++ebtables_legacy_restore_LDADD = libebtc.la
+ static_SOURCES = ebtables.c
+ static_LDFLAGS = -static
+ static_LDADD = libebtc.la
+ examples_ulog_test_ulog_SOURCES = examples/ulog/test_ulog.c getethertype.c
+ 
+ daemon: ebtablesd ebtablesu
+-exec: ebtables ebtables-restore
++exec: ebtables-legacy ebtables-legacy-restore
+ 
+-CLEANFILES = ebtables-save ebtables.sysv ebtables-config ebtables.8
++CLEANFILES = ebtables-legacy-save ebtables.sysv ebtables-config ebtables-legacy.8
+ 
+-ebtables-save: ebtables-save.in ${top_builddir}/config.status
++ebtables-legacy-save: ebtables-save.in ${top_builddir}/config.status
+ 	${AM_V_GEN}sed -e 's![@]sbindir@!${sbindir}!g' <$< >$@
+ 
+ ebtables.sysv: ebtables.sysv.in ${top_builddir}/config.status
+@@ -70,7 +71,7 @@ ebtables.sysv: ebtables.sysv.in ${top_builddir}/config.status
+ ebtables-config: ebtables-config.in ${top_builddir}/config.status
+ 	${AM_V_GEN}sed -e 's![@]sysconfigdir@!${sysconfigdir}!g' <$< >$@
+ 
+-ebtables.8: ebtables.8.in ${top_builddir}/config.status
++ebtables-legacy.8: ebtables-legacy.8.in ${top_builddir}/config.status
+ 	${AM_V_GEN}sed -e 's![@]PACKAGE_VERSION!${PACKAGE_VERSION}!g' \
+ 		-e 's![@]PACKAGE_DATE@!${PROGDATE}!g' \
+ 		-e 's![@]LOCKFILE@!${LOCKFILE}!g' <$< >$@
+diff --git a/ebtables.8.in b/ebtables-legacy.8.in
+similarity index 98%
+rename from ebtables.8.in
+rename to ebtables-legacy.8.in
+index 3e97c84da0e86..3417045fbd89d 100644
+--- a/ebtables.8.in
++++ b/ebtables-legacy.8.in
+@@ -24,7 +24,7 @@
+ .\"     
+ .\"
+ .SH NAME
+-ebtables (@PACKAGE_VERSION@) \- Ethernet bridge frame table administration
++ebtables-legacy (@PACKAGE_VERSION@) \- Ethernet bridge frame table administration (legacy)
+ .SH SYNOPSIS
+ .BR "ebtables " [ -t " table ] " - [ ACDI "] chain rule specification [match extensions] [watcher extensions] target"
+ .br
+@@ -50,6 +50,18 @@ ebtables (@PACKAGE_VERSION@) \- Ethernet bridge frame table administration
+ .br
+ .BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save
+ .br
++
++.SH LEGACY
++This tool uses the old xtables/setsockopt framework, and is a legacy version
++of ebtables. That means that a new, more modern tool exists with the same
++functionality using the nf_tables framework and you are encouraged to migrate now.
++The new binaries (known as ebtables-nft and formerly known as ebtables-compat)
++uses the same syntax and semantics than this legacy one.
++
++You can still use this legacy tool. You should probably get some specific
++information from your Linux distribution or vendor.
++More docs are available at https://wiki.nftables.org
++
+ .SH DESCRIPTION
+ .B ebtables
+ is an application program used to set up and maintain the
+diff --git a/ebtables-save.in b/ebtables-save.in
+index df141490c20b1..17924a2b8df90 100644
+--- a/ebtables-save.in
++++ b/ebtables-save.in
+@@ -50,7 +50,7 @@ sub process_table {
+ # ========================================================
+ 
+ unless (-x $ebtables) { exit -1 };
+-print "# Generated by ebtables-save v$version on " . `date`;
++print "# Generated by ebtables-save v$version (legacy) on " . `date`;
+ if (defined($ENV{'EBTABLES_SAVE_COUNTER'}) && $ENV{'EBTABLES_SAVE_COUNTER'} eq "yes") {
+     $cnt = "--Lc";
+ }
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index 7f5968dc6f39d..901b28233f140 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -395,7 +395,7 @@ extern int ebt_printstyle_mac;
+ #define BASE_CHAIN (hookmask & (1 << NF_BR_NUMHOOKS))
+ /* Clear the bit in the hook_mask that tells if the rule is on a base chain */
+ #define CLEAR_BASE_CHAIN_BIT (hookmask &= ~(1 << NF_BR_NUMHOOKS))
+-#define PRINT_VERSION printf(PROGNAME" v"PROGVERSION" ("PROGDATE")\n")
++#define PRINT_VERSION printf(PROGNAME" v"PROGVERSION" (legacy) ("PROGDATE")\n")
+ #ifndef PROC_SYS_MODPROBE
+ #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
+ #endif
+-- 
+2.21.0
+
diff --git a/SOURCES/0033-ebtables-drop-.spec-file.patch b/SOURCES/0033-ebtables-drop-.spec-file.patch
new file mode 100644
index 0000000..3925133
--- /dev/null
+++ b/SOURCES/0033-ebtables-drop-.spec-file.patch
@@ -0,0 +1,108 @@
+From df6364dbcbba11b75ede2aab6f54183939a1450b Mon Sep 17 00:00:00 2001
+From: Arturo Borrero Gonzalez <arturo@netfilter.org>
+Date: Tue, 22 Jan 2019 18:41:45 +0100
+Subject: [PATCH] ebtables: drop .spec file
+
+This file is for packging in th RPM format. Clearly don't belong here.
+Also, it is unmaintained.
+
+Signed-off-by: Arturo Borrero Gonzalez <arturo@netfilter.org>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ ebtables.spec | 83 ---------------------------------------------------
+ 1 file changed, 83 deletions(-)
+ delete mode 100644 ebtables.spec
+
+diff --git a/ebtables.spec b/ebtables.spec
+deleted file mode 100644
+index 50095db6f9470..0000000000000
+--- a/ebtables.spec
++++ /dev/null
+@@ -1,83 +0,0 @@
+-# spec file originally from Dag Wieers, altered by Bart De Schuymer
+-
+-%define _sbindir /usr/local/sbin
+-%define _mysysconfdir %{_sysconfdir}/sysconfig
+-
+-Summary: Ethernet Bridge frame table administration tool
+-Name: ebtables
+-Version: 2.0.10
+-Release: 4
+-License: GPL
+-Group: System Environment/Base
+-URL: http://ebtables.sourceforge.net/
+-
+-Packager: Bart De Schuymer <bdschuym@pandora.be>
+-
+-Source: http://dl.sf.net/ebtables/ebtables-v%{version}-%{release}.tar.gz
+-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+-
+-%description
+-Ethernet bridge tables is a firewalling tool to transparantly filter network
+-traffic passing a bridge. The filtering possibilities are limited to link
+-layer filtering and some basic filtering on higher network layers.
+-
+-The ebtables tool can be used together with the other Linux filtering tools,
+-like iptables. There are no incompatibility issues.
+-
+-%prep
+-%setup -n ebtables-v%{version}-%{release}
+-
+-%build
+-%{__make} %{?_smp_mflags} \
+-	CFLAGS="%{optflags}"
+-
+-%install
+-%{__rm} -rf %{buildroot}
+-%{__install} -D -m0755 ebtables %{buildroot}%{_sbindir}/ebtables
+-%{__install} -D -m0755 ebtables-restore %{buildroot}%{_sbindir}/ebtables-restore
+-%{__install} -D -m0644 ethertypes %{buildroot}%{_sysconfdir}/ethertypes
+-%{__install} -D -m0644 ebtables.8 %{buildroot}%{_mandir}/man8/ebtables.8
+-%{__mkdir} -p %{buildroot}%{_libdir}/ebtables/
+-%{__mkdir} -p %{buildroot}%{_sbindir}
+-%{__mkdir} -p %{buildroot}%{_initrddir}
+-%{__mkdir} -p %{buildroot}%{_mysysconfdir}
+-%{__install} -m0755 extensions/*.so %{buildroot}%{_libdir}/ebtables/
+-%{__install} -m0755 *.so %{buildroot}%{_libdir}/ebtables/
+-export __iets=`printf %{_sbindir} | sed 's/\\//\\\\\\//g'`
+-export __iets2=`printf %{_mysysconfdir} | sed 's/\\//\\\\\\//g'`
+-sed -i "s/__EXEC_PATH__/$__iets/g" ebtables-save
+-%{__install} -m 0755 -o root -g root ebtables-save %{buildroot}%{_sbindir}/ebtables-save
+-sed -i "s/__EXEC_PATH__/$__iets/g" ebtables.sysv; sed -i "s/__SYSCONFIG__/$__iets2/g" ebtables.sysv
+-%{__install} -m 0755 -o root -g root ebtables.sysv %{buildroot}%{_initrddir}/ebtables
+-sed -i "s/__SYSCONFIG__/$__iets2/g" ebtables-config
+-%{__install} -m 0600 -o root -g root ebtables-config %{buildroot}%{_mysysconfdir}/ebtables-config
+-unset __iets
+-unset __iets2
+-
+-%clean
+-%{__rm} -rf %{buildroot}
+-
+-%post
+-/sbin/chkconfig --add ebtables
+-
+-%preun
+-if [ $1 -eq 0 ]; then
+-	/sbin/service ebtables stop &>/dev/null || :
+-	/sbin/chkconfig --del ebtables
+-fi
+-
+-%files
+-%defattr(-, root, root, 0755)
+-%doc ChangeLog COPYING INSTALL THANKS
+-%doc %{_mandir}/man8/ebtables.8*
+-%config %{_sysconfdir}/ethertypes
+-%config %{_mysysconfdir}/ebtables-config
+-%config %{_initrddir}/ebtables
+-%{_sbindir}/ebtables
+-%{_sbindir}/ebtables-save
+-%{_sbindir}/ebtables-restore
+-%{_libdir}/ebtables/
+-
+-%changelog
+-* Mon Nov 07 2005 Bart De Schuymer <bdschuym@pandora.be> - 2.0.8-rc1
+-- Initial package.
+-- 
+2.21.0
+
diff --git a/SOURCES/0034-ebtables-drop-sysvinit-script.patch b/SOURCES/0034-ebtables-drop-sysvinit-script.patch
new file mode 100644
index 0000000..4b0ebd2
--- /dev/null
+++ b/SOURCES/0034-ebtables-drop-sysvinit-script.patch
@@ -0,0 +1,204 @@
+From 2fab90f7b61fdd433b81b66a60a0124154231486 Mon Sep 17 00:00:00 2001
+From: Arturo Borrero Gonzalez <arturo@netfilter.org>
+Date: Tue, 22 Jan 2019 18:41:52 +0100
+Subject: [PATCH] ebtables: drop sysvinit script
+
+This configuration file belongs to downstream distributions.
+Also, it's unmaintained.
+
+Signed-off-by: Arturo Borrero Gonzalez <arturo@netfilter.org>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ .gitignore       |   1 -
+ Makefile.am      |   5 +-
+ ebtables.sysv.in | 145 -----------------------------------------------
+ 3 files changed, 1 insertion(+), 150 deletions(-)
+ delete mode 100644 ebtables.sysv.in
+
+diff --git a/.gitignore b/.gitignore
+index 1fff83c78ba13..c1fae5463a355 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -22,7 +22,6 @@ Makefile.in
+ /ebtables-restore
+ /ebtables-save
+ /ebtables.8
+-/ebtables.sysv
+ /ebtablesd
+ /ebtablesu
+ /static
+diff --git a/Makefile.am b/Makefile.am
+index b16a4d6dba269..59ae595ee16de 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -60,14 +60,11 @@ examples_ulog_test_ulog_SOURCES = examples/ulog/test_ulog.c getethertype.c
+ daemon: ebtablesd ebtablesu
+ exec: ebtables-legacy ebtables-legacy-restore
+ 
+-CLEANFILES = ebtables-legacy-save ebtables.sysv ebtables-config ebtables-legacy.8
++CLEANFILES = ebtables-legacy-save ebtables-config ebtables-legacy.8
+ 
+ ebtables-legacy-save: ebtables-save.in ${top_builddir}/config.status
+ 	${AM_V_GEN}sed -e 's![@]sbindir@!${sbindir}!g' <$< >$@
+ 
+-ebtables.sysv: ebtables.sysv.in ${top_builddir}/config.status
+-	${AM_V_GEN}sed -e 's![@]sbindir@!${sbindir}!g' -e 's![@]sysconfigdir@!${sysconfigdir}!g' <$< >$@
+-
+ ebtables-config: ebtables-config.in ${top_builddir}/config.status
+ 	${AM_V_GEN}sed -e 's![@]sysconfigdir@!${sysconfigdir}!g' <$< >$@
+ 
+diff --git a/ebtables.sysv.in b/ebtables.sysv.in
+deleted file mode 100644
+index bbf0e7424cb2b..0000000000000
+--- a/ebtables.sysv.in
++++ /dev/null
+@@ -1,145 +0,0 @@
+-#!/bin/bash
+-#
+-# init script for the Ethernet Bridge filter tables
+-#
+-# Written by Dag Wieers <dag@wieers.com>
+-# Modified by Rok Papez <rok.papez@arnes.si>
+-#             Bart De Schuymer <bdschuym@pandora.be>
+-#
+-# chkconfig: - 15 85
+-# description: Ethernet Bridge filtering tables
+-#
+-# config: @sysconfigdir@/ebtables         (text)
+-#         @sysconfigdir@/ebtables.<table> (binary)
+-
+-source /etc/init.d/functions
+-source /etc/sysconfig/network
+-
+-# Check that networking is up.
+-[ ${NETWORKING} = "no" ] && exit 0
+-
+-[ -x @sbindir@/ebtables ] || exit 1
+-[ -x @sbindir@/ebtables-save ] || exit 1
+-[ -x @sbindir@/ebtables-restore ] || exit 1
+-
+-RETVAL=0
+-prog="ebtables"
+-desc="Ethernet bridge filtering"
+-umask 0077
+-
+-#default configuration
+-EBTABLES_TEXT_FORMAT="yes"
+-EBTABLES_BINARY_FORMAT="yes"
+-EBTABLES_MODULES_UNLOAD="yes"
+-EBTABLES_SAVE_ON_STOP="no"
+-EBTABLES_SAVE_ON_RESTART="no"
+-EBTABLES_SAVE_COUNTER="no"
+-
+-config=@sysconfigdir@/$prog-config
+-[ -f "$config" ] && . "$config"
+-
+-start() {
+-	echo -n $"Starting $desc ($prog): "
+-	if [ "$EBTABLES_BINARY_FORMAT" = "yes" ]; then
+-		for table in $(ls @sysconfigdir@/ebtables.* 2>/dev/null | sed -e 's/.*ebtables\.//' -e '/save/d' ); do
+-			@sbindir@/ebtables -t $table --atomic-file @sysconfigdir@/ebtables.$table --atomic-commit || RETVAL=1
+-		done
+-	else
+-		@sbindir@/ebtables-restore < /etc/sysconfig/ebtables || RETVAL=1
+-	fi
+-
+-	if [ $RETVAL -eq 0 ]; then
+-		success "$prog startup"
+-		rm -f /var/lock/subsys/$prog
+-	else
+-		failure "$prog startup"
+-	fi
+-	echo
+-}
+-
+-stop() {
+-	echo -n $"Stopping $desc ($prog): "
+-	for table in $(grep '^ebtable_' /proc/modules | sed -e 's/ebtable_\([^ ]*\).*/\1/'); do
+-		@sbindir@/ebtables -t $table --init-table || RETVAL=1
+-	done
+-
+-	if [ "$EBTABLES_MODULES_UNLOAD" = "yes" ]; then
+-		for mod in $(grep -E '^(ebt|ebtable)_' /proc/modules | cut -f1 -d' ') ebtables; do
+-			rmmod $mod 2> /dev/null
+-		done
+-	fi
+-
+-	if [ $RETVAL -eq 0 ]; then
+-		success "$prog shutdown"
+-		rm -f /var/lock/subsys/$prog
+-	else
+-		failure "$prog shutdown"
+-	fi
+-	echo
+-}
+-
+-restart() {
+-	stop
+-	start
+-}
+-
+-save() {
+-	echo -n $"Saving $desc ($prog): "
+-	if [ "$EBTABLES_TEXT_FORMAT" = "yes" ]; then
+-		if [ -e @sysconfigdir@/ebtables ]; then
+-			chmod 0600 @sysconfigdir@/ebtables
+-			mv -f @sysconfigdir@/ebtables @sysconfigdir@/ebtables.save
+-		fi
+-		@sbindir@/ebtables-save > @sysconfigdir@/ebtables || RETVAL=1
+-	fi
+-	if [ "$EBTABLES_BINARY_FORMAT" = "yes" ]; then
+-		rm -f @sysconfigdir@/ebtables.*.save
+-		for oldtable in $(ls @sysconfigdir@/ebtables.* 2>/dev/null | grep -vF 'ebtables.save'); do
+-			chmod 0600 $oldtable
+-			mv -f $oldtable $oldtable.save
+-		done
+-		for table in $(grep '^ebtable_' /proc/modules | sed -e 's/ebtable_\([^ ]*\).*/\1/'); do
+-			@sbindir@/ebtables -t $table --atomic-file @sysconfigdir@/ebtables.$table --atomic-save || RETVAL=1
+-			if [ "$EBTABLES_SAVE_COUNTER" = "no" ]; then
+-				@sbindir@/ebtables -t $table --atomic-file @sysconfigdir@/ebtables.$table -Z || RETVAL=1
+-			fi
+-		done
+-	fi
+-
+-	if [ $RETVAL -eq 0 ]; then
+-		success "$prog saved"
+-	else
+-		failure "$prog saved"
+-	fi
+-	echo
+-}
+-
+-case "$1" in
+-  start)
+-	start
+-	;;
+-  stop)
+-	[ "$EBTABLES_SAVE_ON_STOP" = "yes" ] && save
+-	stop
+-	;;
+-  restart|reload)
+-	[ "$EBTABLES_SAVE_ON_RESTART" = "yes" ] && save
+-	restart
+-	;;
+-  condrestart)
+-	[ -e /var/lock/subsys/$prog ] && restart
+-	RETVAL=$?
+-	;;
+-  save)
+-	save
+-	;;
+-  status)
+-	@sbindir@/ebtables-save
+-	RETVAL=$?
+-	;;
+-  *)
+-	echo $"Usage $0 {start|stop|restart|condrestart|save|status}"
+-	RETVAL=1
+-esac
+-
+-exit $RETVAL
+-- 
+2.21.0
+
diff --git a/SOURCES/0035-Print-IPv6-prefixes-in-CIDR-notation.patch b/SOURCES/0035-Print-IPv6-prefixes-in-CIDR-notation.patch
new file mode 100644
index 0000000..04742e7
--- /dev/null
+++ b/SOURCES/0035-Print-IPv6-prefixes-in-CIDR-notation.patch
@@ -0,0 +1,74 @@
+From 5ba6bb92b9ec3545d86d598f07643c399a47c7ad Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 12 Feb 2019 22:51:34 +0100
+Subject: [PATCH] Print IPv6 prefixes in CIDR notation
+
+According to RFC4291, IPv6 prefixes are represented in CIDR notation.
+While the use of a "netmask" notation is not explicitly denied, its
+existence merely stems from applying IPv4 standards to IPv6. This is not
+necessarily correct.
+
+Therefore change printing of IPv6 prefixes to use CIDR notation as long
+as the address mask's bits are left contiguous.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ useful_functions.c | 35 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 30 insertions(+), 5 deletions(-)
+
+diff --git a/useful_functions.c b/useful_functions.c
+index 8a34f820f230b..bf4393712fa44 100644
+--- a/useful_functions.c
++++ b/useful_functions.c
+@@ -416,16 +416,41 @@ char *ebt_ip6_to_numeric(const struct in6_addr *addrp)
+ 	return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
+ }
+ 
++int ebt_ip6mask_to_cidr(const struct in6_addr *k)
++{
++	unsigned int bits = 0;
++	uint32_t a, b, c, d;
++
++	a = ntohl(k->s6_addr32[0]);
++	b = ntohl(k->s6_addr32[1]);
++	c = ntohl(k->s6_addr32[2]);
++	d = ntohl(k->s6_addr32[3]);
++	while (a & 0x80000000U) {
++		++bits;
++		a <<= 1;
++		a  |= (b >> 31) & 1;
++		b <<= 1;
++		b  |= (c >> 31) & 1;
++		c <<= 1;
++		c  |= (d >> 31) & 1;
++		d <<= 1;
++	}
++	if (a != 0 || b != 0 || c != 0 || d != 0)
++		return -1;
++	return bits;
++}
++
+ char *ebt_ip6_mask_to_string(const struct in6_addr *msk)
+ {
+-   	/* /0000:0000:0000:0000:0000:000.000.000.000
+-	 * /0000:0000:0000:0000:0000:0000:0000:0000 */
++	int l = ebt_ip6mask_to_cidr(msk);
+ 	static char buf[51+1];
+-	if (msk->s6_addr32[0] == 0xFFFFFFFFL && msk->s6_addr32[1] == 0xFFFFFFFFL &&
+-	    msk->s6_addr32[2] == 0xFFFFFFFFL && msk->s6_addr32[3] == 0xFFFFFFFFL)
++
++	if (l == 127)
+ 		*buf = '\0';
+-	else
++	else if (l == -1)
+ 		sprintf(buf, "/%s", ebt_ip6_to_numeric(msk));
++	else
++		sprintf(buf, "/%d", l);
+ 	return buf;
+ }
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0036-Adjust-.gitignore-to-renamed-files.patch b/SOURCES/0036-Adjust-.gitignore-to-renamed-files.patch
new file mode 100644
index 0000000..3799f2e
--- /dev/null
+++ b/SOURCES/0036-Adjust-.gitignore-to-renamed-files.patch
@@ -0,0 +1,36 @@
+From 822a5dcdfc473f129ea43c44175bc0da75a1be6c Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 12 Mar 2019 18:13:27 +0100
+Subject: [PATCH] Adjust .gitignore to renamed files
+
+Fixes: 6218f812d894f ("ebtables: legacy renaming")
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ .gitignore | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/.gitignore b/.gitignore
+index c1fae5463a355..9940c85762fa0 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -17,11 +17,11 @@ Makefile.in
+ /libtool
+ /stamp-h1
+ 
+-/ebtables
++/ebtables-legacy
+ /ebtables-config
+-/ebtables-restore
+-/ebtables-save
+-/ebtables.8
++/ebtables-legacy-restore
++/ebtables-legacy-save
++/ebtables-legacy.8
+ /ebtablesd
+ /ebtablesu
+ /static
+-- 
+2.21.0
+
diff --git a/SOURCES/0037-extensions-Drop-Makefile.patch b/SOURCES/0037-extensions-Drop-Makefile.patch
new file mode 100644
index 0000000..f655a2a
--- /dev/null
+++ b/SOURCES/0037-extensions-Drop-Makefile.patch
@@ -0,0 +1,56 @@
+From 38f05e8c8f760f7a6736a959a568b4267bc81978 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 19 Mar 2019 20:09:36 +0100
+Subject: [PATCH] extensions: Drop Makefile
+
+Sources contained in there are built from toplevel Makefile.am. This
+seems like a leftover from commit 131920089dc21 ("build: move to
+automake").
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ extensions/Makefile | 30 ------------------------------
+ 1 file changed, 30 deletions(-)
+ delete mode 100644 extensions/Makefile
+
+diff --git a/extensions/Makefile b/extensions/Makefile
+deleted file mode 100644
+index daa11fce36e5e..0000000000000
+--- a/extensions/Makefile
++++ /dev/null
+@@ -1,30 +0,0 @@
+-#! /usr/bin/make
+-
+-EXT_FUNC+=802_3 nat arp arpreply ip ip6 standard log redirect vlan mark_m mark \
+-          pkttype stp among limit ulog nflog string
+-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)
+-EXT_LIBS+=$(foreach T,$(EXT_FUNC), extensions/libebt_$(T).so)
+-EXT_LIBS+=$(foreach T,$(EXT_TABLES), extensions/libebtable_$(T).so)
+-EXT_LIBSI+=$(foreach T,$(EXT_FUNC), -lebt_$(T))
+-EXT_LIBSI+=$(foreach T,$(EXT_TABLES), -lebtable_$(T))
+-
+-extensions/ebt_%.so: extensions/ebt_%.o
+-	$(CC) $(LDFLAGS) -shared -o $@ -lc $<
+-
+-extensions/libebt_%.so: extensions/ebt_%.so
+-	mv $< $@
+-
+-extensions/ebtable_%.so: extensions/ebtable_%.o
+-	$(CC) $(LDFLAGS) -shared -o $@ -lc $<
+-
+-extensions/libebtable_%.so: extensions/ebtable_%.so
+-	mv $< $@
+-
+-extensions/ebt_%.o: extensions/ebt_%.c include/ebtables_u.h
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
+-
+-extensions/ebtable_%.o: extensions/ebtable_%.c
+-	$(CC) $(CFLAGS) $(CFLAGS_SH_LIB) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
+-
+-- 
+2.21.0
+
diff --git a/SOURCES/0038-Allow-customizing-lockfile-location-at-configure-tim.patch b/SOURCES/0038-Allow-customizing-lockfile-location-at-configure-tim.patch
new file mode 100644
index 0000000..4e6214f
--- /dev/null
+++ b/SOURCES/0038-Allow-customizing-lockfile-location-at-configure-tim.patch
@@ -0,0 +1,94 @@
+From f45756c1ca3b54e8bd45b40b809bd1a8d3cedfdb Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 19 Mar 2019 20:09:37 +0100
+Subject: [PATCH] Allow customizing lockfile location at configure time
+
+Users may pass LOCKFILE=/some/path/to/file when calling configure to
+make libebtc use that path for its lockfile.
+
+To simplify things, drop LOCKDIR completely and instead call dirname()
+when trying to create the parent directory.
+
+Given that we always define LOCKFILE via compiler flag, drop the
+fallback define from libebtc.c.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ Makefile.am  | 4 +---
+ configure.ac | 3 +++
+ libebtc.c    | 7 ++-----
+ 3 files changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 59ae595ee16de..53fcbadbca7b4 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -5,8 +5,6 @@
+ PROGNAME = ${PACKAGE_NAME}
+ PROGVERSION = ${PACKAGE_VERSION}
+ PROGDATE = December\ 2011
+-LOCKDIR = /var/lib/ebtables
+-LOCKFILE = ${LOCKDIR}/lock
+ INITDIR = /etc/rc.d/init.d
+ initddir = ${INITDIR}
+ sysconfigdir = ${sysconfdir}/sysconfig
+@@ -21,7 +19,7 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include \
+ 	-DPROGVERSION=\"${PACKAGE_VERSION}\" -DPROGNAME=\"${PACKAGE_NAME}\" \
+ 	-DPROGDATE=\"${PROGDATE}\" \
+ 	-D_PATH_ETHERTYPES=\"${sysconfdir}/ethertypes\" \
+-	-DLOCKFILE=\"${LOCKFILE}\" -DLOCKDIR=\"${LOCKDIR}\" \
++	-DLOCKFILE=\"${LOCKFILE}\" \
+ 	-DEBTD_ARGC_MAX=${EBTD_ARGC_MAX} -DEBTD_CMDLINE_MAXLN=${EBTD_CMDLINE_MAXLN} \
+ 	-DEBTD_PIPE=\"${PIPE}\" -DEBTD_PIPE_DIR=\"${PIPE_DIR}\"
+ AM_CFLAGS = ${regular_CFLAGS}
+diff --git a/configure.ac b/configure.ac
+index a3bc3c93a279f..00d97734ff9a9 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -10,6 +10,9 @@ AC_DISABLE_STATIC
+ m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+ AM_PROG_LIBTOOL
+ 
++AC_ARG_VAR([LOCKFILE], [Custom libebtc lockfile path (default: /var/lib/ebtables/lock)])
++AS_IF([test "x$LOCKFILE" = x], [LOCKFILE="/var/lib/ebtables/lock"])
++
+ regular_CFLAGS="-Wall -Wunused"
+ regular_CPPFLAGS=""
+ case "$host" in
+diff --git a/libebtc.c b/libebtc.c
+index 92fd76485c723..f2a2b500ea751 100644
+--- a/libebtc.c
++++ b/libebtc.c
+@@ -36,6 +36,7 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <errno.h>
++#include <libgen.h>
+ 
+ static void decrease_chain_jumps(struct ebt_u_replace *replace);
+ static int iterate_entries(struct ebt_u_replace *replace, int type);
+@@ -134,10 +135,6 @@ void ebt_list_extensions()
+ 	}
+ }
+ 
+-#ifndef LOCKFILE
+-#define LOCKDIR "/var/lib/ebtables"
+-#define LOCKFILE LOCKDIR"/lock"
+-#endif
+ int use_lockfd;
+ /* Returns 0 on success, -1 when the file is locked by another process
+  * or -2 on any other error. */
+@@ -148,7 +145,7 @@ static int lock_file()
+ retry:
+ 	fd = open(LOCKFILE, O_CREAT, 00600);
+ 	if (fd < 0) {
+-		if (try == 1 || mkdir(LOCKDIR, 00700))
++		if (try == 1 || mkdir(dirname(LOCKFILE), 00700))
+ 			return -2;
+ 		try = 1;
+ 		goto retry;
+-- 
+2.21.0
+
diff --git a/SOURCES/0039-extensions-Add-AUDIT-target.patch b/SOURCES/0039-extensions-Add-AUDIT-target.patch
new file mode 100644
index 0000000..238cc81
--- /dev/null
+++ b/SOURCES/0039-extensions-Add-AUDIT-target.patch
@@ -0,0 +1,188 @@
+From 2fdf17ff85c1a3044d0e139642237bbc964ee494 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 19 Mar 2019 20:09:38 +0100
+Subject: [PATCH] extensions: Add AUDIT target
+
+This is a barn find from Fedora package, actually spooking around in
+various places in the internet. No idea who wrote it, but it seems to be
+used. So add it for the time being.
+
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ Makefile.am                        |   2 +-
+ extensions/ebt_AUDIT.c             | 110 +++++++++++++++++++++++++++++
+ include/linux/netfilter/xt_AUDIT.h |  30 ++++++++
+ 3 files changed, 141 insertions(+), 1 deletion(-)
+ create mode 100644 extensions/ebt_AUDIT.c
+ create mode 100644 include/linux/netfilter/xt_AUDIT.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 53fcbadbca7b4..904de12773a84 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -40,7 +40,7 @@ libebtc_la_SOURCES = \
+ 	extensions/ebt_mark_m.c extensions/ebt_nat.c extensions/ebt_nflog.c \
+ 	extensions/ebt_pkttype.c extensions/ebt_redirect.c \
+ 	extensions/ebt_standard.c extensions/ebt_stp.c extensions/ebt_string.c \
+-	extensions/ebt_ulog.c extensions/ebt_vlan.c \
++	extensions/ebt_ulog.c extensions/ebt_vlan.c extensions/ebt_AUDIT.c \
+ 	extensions/ebtable_broute.c extensions/ebtable_filter.c \
+ 	extensions/ebtable_nat.c
+ # Make sure ebtables.c can be built twice
+diff --git a/extensions/ebt_AUDIT.c b/extensions/ebt_AUDIT.c
+new file mode 100644
+index 0000000000000..c9befccca94db
+--- /dev/null
++++ b/extensions/ebt_AUDIT.c
+@@ -0,0 +1,110 @@
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <getopt.h>
++#include "../include/ebtables_u.h"
++#include <linux/netfilter/xt_AUDIT.h>
++
++#define AUDIT_TYPE  '1'
++static struct option opts[] =
++{
++	{ "audit-type" , required_argument, 0, AUDIT_TYPE },
++	{ 0 }
++};
++
++static void print_help()
++{
++	printf(
++	"AUDIT target options:\n"
++	" --audit-type TYPE          : Set action type to record.\n");
++}
++
++static void init(struct ebt_entry_target *target)
++{
++	struct xt_AUDIT_info *info = (struct xt_AUDIT_info *) target->data;
++
++	info->type = 0;
++}
++
++static int parse(int c, char **argv, int argc,
++   const struct ebt_u_entry *entry, unsigned int *flags,
++   struct ebt_entry_target **target)
++{
++	struct xt_AUDIT_info *info = (struct xt_AUDIT_info *) (*target)->data;
++
++	switch (c) {
++	case AUDIT_TYPE:
++		ebt_check_option2(flags, AUDIT_TYPE);
++
++		if (!strcasecmp(optarg, "accept"))
++			info->type = XT_AUDIT_TYPE_ACCEPT;
++		else if (!strcasecmp(optarg, "drop"))
++			info->type = XT_AUDIT_TYPE_DROP;
++		else if (!strcasecmp(optarg, "reject"))
++			info->type = XT_AUDIT_TYPE_REJECT;
++		else
++			ebt_print_error2("Bad action type value `%s'", optarg);
++
++		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 hookmask, unsigned int time)
++{
++}
++
++static void print(const struct ebt_u_entry *entry,
++   const struct ebt_entry_target *target)
++{
++	const struct xt_AUDIT_info *info =
++		(const struct xt_AUDIT_info *) target->data;
++
++	printf("--audit-type ");
++
++	switch(info->type) {
++	case XT_AUDIT_TYPE_ACCEPT:
++		printf("accept");
++		break;
++	case XT_AUDIT_TYPE_DROP:
++		printf("drop");
++		break;
++	case XT_AUDIT_TYPE_REJECT:
++		printf("reject");
++		break;
++	}
++}
++
++static int compare(const struct ebt_entry_target *t1,
++   const struct ebt_entry_target *t2)
++{
++	const struct xt_AUDIT_info *info1 =
++		(const struct xt_AUDIT_info *) t1->data;
++	const struct xt_AUDIT_info *info2 =
++		(const struct xt_AUDIT_info *) t2->data;
++
++	return info1->type == info2->type;
++}
++
++static struct ebt_u_target AUDIT_target =
++{
++	.name		= "AUDIT",
++	.size		= sizeof(struct xt_AUDIT_info),
++	.help		= print_help,
++	.init		= init,
++	.parse		= parse,
++	.final_check	= final_check,
++	.print		= print,
++	.compare	= compare,
++	.extra_ops	= opts,
++};
++
++static void _INIT(void)
++{
++	ebt_register_target(&AUDIT_target);
++}
+diff --git a/include/linux/netfilter/xt_AUDIT.h b/include/linux/netfilter/xt_AUDIT.h
+new file mode 100644
+index 0000000000000..44111b242b531
+--- /dev/null
++++ b/include/linux/netfilter/xt_AUDIT.h
+@@ -0,0 +1,30 @@
++/*
++ * Header file for iptables xt_AUDIT target
++ *
++ * (C) 2010-2011 Thomas Graf <tgraf@redhat.com>
++ * (C) 2010-2011 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _XT_AUDIT_TARGET_H
++#define _XT_AUDIT_TARGET_H
++
++#include <linux/types.h>
++
++enum {
++	XT_AUDIT_TYPE_ACCEPT = 0,
++	XT_AUDIT_TYPE_DROP,
++	XT_AUDIT_TYPE_REJECT,
++	__XT_AUDIT_TYPE_MAX,
++};
++
++#define XT_AUDIT_TYPE_MAX (__XT_AUDIT_TYPE_MAX - 1)
++
++struct xt_AUDIT_info {
++	__u8 type; /* XT_AUDIT_TYPE_* */
++};
++
++#endif /* _XT_AUDIT_TARGET_H */
+-- 
+2.21.0
+
diff --git a/SOURCES/0040-Fix-segfault-with-missing-lockfile-directory.patch b/SOURCES/0040-Fix-segfault-with-missing-lockfile-directory.patch
new file mode 100644
index 0000000..084b879
--- /dev/null
+++ b/SOURCES/0040-Fix-segfault-with-missing-lockfile-directory.patch
@@ -0,0 +1,40 @@
+From 97a7193e1838da9ab9631d07f6b3cedf63a5995d Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 9 Apr 2019 14:21:25 +0200
+Subject: [PATCH] Fix segfault with missing lockfile directory
+
+Apparently, dirname() modifies the buffer passed to it. Given a
+read-only location, this leads to a segfault. Use a buffer initialized
+(and tailored) to the content of LOCKFILE macro at compile-time instead.
+
+Fixes: f45756c1ca3b5 ("Allow customizing lockfile location at configure time")
+Signed-off-by: Phil Sutter <phil@nwl.cc>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+(cherry picked from commit c9348e18f3cdd52a7cb1586e03a55cefac08d849)
+Signed-off-by: Phil Sutter <psutter@redhat.com>
+---
+ libebtc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/libebtc.c b/libebtc.c
+index f2a2b500ea751..2a9ab87ac99c0 100644
+--- a/libebtc.c
++++ b/libebtc.c
+@@ -140,12 +140,13 @@ int use_lockfd;
+  * or -2 on any other error. */
+ static int lock_file()
+ {
++	char pathbuf[] = LOCKFILE;
+ 	int fd, try = 0;
+ 
+ retry:
+ 	fd = open(LOCKFILE, O_CREAT, 00600);
+ 	if (fd < 0) {
+-		if (try == 1 || mkdir(dirname(LOCKFILE), 00700))
++		if (try == 1 || mkdir(dirname(pathbuf), 00700))
+ 			return -2;
+ 		try = 1;
+ 		goto retry;
+-- 
+2.21.0
+
diff --git a/SOURCES/ebtables-config b/SOURCES/ebtables-config
new file mode 100644
index 0000000..69d9289
--- /dev/null
+++ b/SOURCES/ebtables-config
@@ -0,0 +1,11 @@
+# Save current firewall rules on stop.
+#   Value: yes|no,  default: no
+# Saves all firewall rules if firewall gets stopped
+# (e.g. on system shutdown).
+EBTABLES_SAVE_ON_STOP="no"
+
+# Save (and restore) rule counters.
+#   Value: yes|no,  default: no
+# Save rule counters when saving a kernel table to a file. If the
+# rule counters were saved, they will be restored when restoring the table.
+EBTABLES_SAVE_COUNTER="no"
diff --git a/SOURCES/ebtables-helper b/SOURCES/ebtables-helper
new file mode 100644
index 0000000..f1dee08
--- /dev/null
+++ b/SOURCES/ebtables-helper
@@ -0,0 +1,105 @@
+#!/bin/bash
+
+# compat for removed initscripts dependency
+
+success() {
+       echo "[  OK  ]"
+       return 0
+}
+
+failure() {
+       echo "[FAILED]"
+       return 1
+}
+
+# internal variables
+EBTABLES_CONFIG=/etc/sysconfig/ebtables-config
+EBTABLES_DATA=/etc/sysconfig/ebtables
+EBTABLES_TABLES="filter nat"
+if ebtables --version | grep -q '(legacy)'; then
+	EBTABLES_TABLES+=" broute"
+fi
+VAR_SUBSYS_EBTABLES=/var/lock/subsys/ebtables
+
+# ebtables-config defaults
+EBTABLES_SAVE_ON_STOP="no"
+EBTABLES_SAVE_ON_RESTART="no"
+EBTABLES_SAVE_COUNTER="no"
+
+# load config if existing
+[ -f "$EBTABLES_CONFIG" ] && . "$EBTABLES_CONFIG"
+
+initialize() {
+	local ret=0
+	for table in $EBTABLES_TABLES; do
+		ebtables -t $table --init-table || ret=1
+	done
+	return $ret
+}
+
+sanitize_dump() {
+	local drop=false
+
+	export EBTABLES_TABLES
+
+	cat $1 | while read line; do
+		case $line in
+		\**)
+			drop=false
+			local table="${line#\*}"
+			local found=false
+			for t in $EBTABLES_TABLES; do
+				if [[ $t == $table ]]; then
+					found=true
+					break
+				fi
+			done
+			$found || drop=true
+			;;
+		esac
+		$drop || echo "$line"
+	done
+}
+
+start() {
+	if [ -f $EBTABLES_DATA ]; then
+		echo -n $"ebtables: loading ruleset from $EBTABLES_DATA: "
+		sanitize_dump $EBTABLES_DATA | ebtables-restore
+	else
+		echo -n $"ebtables: no stored ruleset, initializing empty tables: "
+		initialize
+	fi
+	local ret=$?
+	touch $VAR_SUBSYS_EBTABLES
+	return $ret
+}
+
+save() {
+	echo -n $"ebtables: saving active ruleset to $EBTABLES_DATA: "
+	export EBTABLES_SAVE_COUNTER
+	ebtables-save >$EBTABLES_DATA && success || failure
+}
+
+case $1 in
+	start)
+		[ -f "$VAR_SUBSYS_EBTABLES" ] && exit 0
+		start && success || failure
+		RETVAL=$?
+		;;
+	stop)
+		[ "x$EBTABLES_SAVE_ON_STOP" = "xyes" ] && save
+		echo -n $"ebtables: stopping firewall: "
+		initialize && success || failure
+		RETVAL=$?
+		rm -f $VAR_SUBSYS_EBTABLES
+		;;
+	save)
+		save
+		;;
+	*)
+		echo "usage: ${0##*/} {start|stop|save}" >&2
+		RETVAL=2
+		;;
+esac
+
+exit $RETVAL
diff --git a/SOURCES/ebtables-legacy-save b/SOURCES/ebtables-legacy-save
new file mode 100644
index 0000000..2d7fc4e
--- /dev/null
+++ b/SOURCES/ebtables-legacy-save
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+EBTABLES="/sbin/ebtables"
+
+[ -x "$EBTABLES" ] || exit 1
+
+echo "# Generated by ebtables-save v1.0 on $(date)"
+
+cnt=""
+[ "x$EBTABLES_SAVE_COUNTER" = "xyes" ] && cnt="--Lc"
+
+for table_name in $(grep -E '^ebtable_' /proc/modules | cut -f1 -d' ' | sed s/ebtable_//); do
+    table=$($EBTABLES -t $table_name -L $cnt)
+    [ $? -eq 0 ] || { echo "$table"; exit -1; }
+
+    chain=""
+    rules=""
+    while read line; do
+	[ -z "$line" ] && continue
+
+	case "$line" in 
+	    Bridge\ table:\ *)
+		echo "*${line:14}"
+		;;
+	    Bridge\ chain:\ *)
+		chain="${line:14}"
+		chain="${chain%%,*}"
+		policy="${line##*policy: }"
+		echo ":$chain $policy"
+		;;
+	    *)
+		if [ "$cnt" = "--Lc" ]; then
+		    line=${line/, pcnt \=/ -c}
+		    line=${line/-- bcnt \=/}
+		fi
+		rules="$rules-A $chain $line\n"
+		;;
+	esac
+    done <<EOF
+$table
+EOF
+    echo -e $rules
+done
diff --git a/SOURCES/ebtables.service b/SOURCES/ebtables.service
new file mode 100644
index 0000000..b096f1d
--- /dev/null
+++ b/SOURCES/ebtables.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Ethernet Bridge Filtering tables
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/usr/libexec/ebtables-helper start
+ExecStop=/usr/libexec/ebtables-helper stop
+
+[Install]
+WantedBy=multi-user.target
diff --git a/SOURCES/sources b/SOURCES/sources
new file mode 100644
index 0000000..a7bc584
--- /dev/null
+++ b/SOURCES/sources
@@ -0,0 +1 @@
+SHA512 (ebtables-2.0.11.tar.bz2) = 43a04c6174c8028c501591ef260526297e0f018016f226e2a3bcf80766fddf53d4605c347554d6da7c4ab5e2131584a18da20916ffddcbf2d26ac93b00c5777f
diff --git a/SPECS/ebtables.spec b/SPECS/ebtables.spec
new file mode 100644
index 0000000..467a58e
--- /dev/null
+++ b/SPECS/ebtables.spec
@@ -0,0 +1,440 @@
+%undefine _ld_as_needed
+
+Name:			ebtables
+Version:		2.0.11
+Release:		9%{?dist}
+Summary:		Ethernet Bridge frame table administration tool
+License:		GPLv2+
+URL:			http://ebtables.sourceforge.net/
+
+Source0:		ftp://ftp.netfilter.org/pub/ebtables/ebtables-%{version}.tar.bz2
+Source1:		ebtables-legacy-save
+Source2:		ebtables-helper
+Source3:		ebtables.service
+Source4:		ebtables-config
+
+BuildRequires:		autoconf
+BuildRequires:		automake
+BuildRequires:		libtool
+BuildRequires:		gcc
+BuildRequires:		systemd
+BuildRequires: make
+
+%description
+Ethernet bridge tables is a firewalling tool to transparently filter network
+traffic passing a bridge. The filtering possibilities are limited to link
+layer filtering and some basic filtering on higher network layers.
+
+This tool is the userspace control for the bridge and ebtables kernel
+components (built by default in Fedora kernels).
+
+The ebtables tool can be used together with the other Linux filtering tools,
+like iptables. There are no known incompatibility issues.
+
+%package legacy
+Summary: Legacy user space tool to configure bridge netfilter rules in kernel
+Requires(post):   %{_sbindir}/update-alternatives
+Requires(post):   %{_bindir}/readlink
+Requires(postun): %{_sbindir}/update-alternatives
+Conflicts:        setup < 2.10.4-1
+%if 0%{?rhel} >= 9
+# RHEL-9 provides ebtables via iptables-nft, but doesn't support ebtables
+# alternatives. As such avoid the Provides here so iptables-nft is chosen, not
+# ebtables-legacy.
+%else
+Provides:         ebtables
+%endif
+
+%description legacy
+Ethernet bridge tables is a firewalling tool to transparently filter network
+traffic passing a bridge. The filtering possibilities are limited to link
+layer filtering and some basic filtering on higher network layers.
+
+This tool is the userspace control for the bridge and ebtables kernel
+components (built by default in Fedora kernels).
+
+The ebtables tool can be used together with the other Linux filtering tools,
+like iptables. There are no known incompatibility issues.
+
+Note that it is considered legacy upstream since nftables provides the same
+functionality in a much newer code-base. To aid in migration, there is
+ebtables-nft utility, a drop-in replacement for the legacy one which uses
+nftables internally. It is provided by iptables-nft package.
+
+%package services
+Summary: ebtables systemd services
+%{?systemd_ordering}
+Obsoletes:	ebtables-compat < 2.0.10-39
+
+%description services
+ebtables systemd services
+
+This package provides the systemd ebtables service that has been split
+out of the base package for better integration with alternatives.
+
+%prep
+%autosetup -p1 -n ebtables-%{version}
+# Convert to UTF-8
+f=THANKS; iconv -f iso-8859-1 -t utf-8 $f -o $f.utf8 ; mv $f.utf8 $f
+
+%build
+./autogen.sh
+%configure --disable-silent-rules LOCKFILE=/run/ebtables.lock
+%make_build
+
+%install
+%make_install
+install -D -m 644 %{SOURCE3} %{buildroot}%{_unitdir}/ebtables.service
+install -D -m 755 %{SOURCE2} %{buildroot}%{_libexecdir}/ebtables-helper
+install -D -m 600 %{SOURCE4} %{buildroot}%{_sysconfdir}/sysconfig/ebtables-config
+touch %{buildroot}%{_sysconfdir}/sysconfig/ebtables
+
+# install ebtables-legacy-save bash script
+install -m 755 %{SOURCE1} %{buildroot}%{_sbindir}/ebtables-legacy-save
+
+# No use for libtool archive files
+rm %{buildroot}/%{_libdir}/libebtc.la
+
+# Remove /etc/ethertypes (now part of setup)
+rm -f %{buildroot}%{_sysconfdir}/ethertypes
+
+# Drop these binaries (for now at least)
+rm %{buildroot}/%{_sbindir}/ebtables{d,u}
+
+# Prepare for Alternatives system
+touch %{buildroot}%{_sbindir}/ebtables
+touch %{buildroot}%{_sbindir}/ebtables-save
+touch %{buildroot}%{_sbindir}/ebtables-restore
+touch %{buildroot}%{_mandir}/man8/ebtables.8
+
+%post legacy
+pfx=%{_sbindir}/ebtables
+manpfx=%{_mandir}/man8/ebtables
+for sfx in "" "-restore" "-save"; do
+	if [ "$(readlink -e $pfx$sfx)" == $pfx$sfx ]; then
+		rm -f $pfx$sfx
+	fi
+done
+if [ "$(readlink -e $manpfx.8.gz)" == $manpfx.8.gz ]; then
+	rm -f $manpfx.8.gz
+fi
+%{_sbindir}/update-alternatives --install \
+	$pfx ebtables $pfx-legacy 10 \
+	--slave $pfx-save ebtables-save $pfx-legacy-save \
+	--slave $pfx-restore ebtables-restore $pfx-legacy-restore \
+	--slave $manpfx.8.gz ebtables-man $manpfx-legacy.8.gz
+
+%postun legacy
+if [ $1 -eq 0 ]; then
+	%{_sbindir}/update-alternatives --remove \
+		ebtables %{_sbindir}/ebtables-legacy
+fi
+
+# When upgrading ebtables to ebtables-{legacy,services},
+# postun in ebtables thinks it is uninstalled and removes alternatives.
+# Counter this with a trigger here to have it installed again.
+%triggerpostun legacy -- ebtables
+pfx=%{_sbindir}/ebtables
+manpfx=%{_mandir}/man8/ebtables
+%{_sbindir}/update-alternatives --install \
+	$pfx ebtables $pfx-legacy 10 \
+	--slave $pfx-save ebtables-save $pfx-legacy-save \
+	--slave $pfx-restore ebtables-restore $pfx-legacy-restore \
+	--slave $manpfx.8.gz ebtables-man $manpfx-legacy.8.gz
+
+
+%post services
+%systemd_post ebtables.service
+
+%preun services
+%systemd_preun ebtables.service
+
+%postun services
+%systemd_postun ebtables.service
+
+%files legacy
+%license COPYING
+%doc ChangeLog THANKS
+%{_sbindir}/ebtables-legacy*
+%{_mandir}/*/ebtables-legacy*
+%{_libdir}/libebtc.so*
+%ghost %{_sbindir}/ebtables
+%ghost %{_sbindir}/ebtables-save
+%ghost %{_sbindir}/ebtables-restore
+%ghost %{_mandir}/man8/ebtables.8.gz
+
+%files services
+%{_unitdir}/ebtables.service
+%{_libexecdir}/ebtables-helper
+%config(noreplace) %{_sysconfdir}/sysconfig/ebtables-config
+%ghost %{_sysconfdir}/sysconfig/ebtables
+
+%changelog
+* Tue Jan 26 2021 Eric Garver <egarver@redhat.com> - 2.0.11-9
+- avoid Provides: ebtables for newer RHEL/ELN builds
+
+* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.11-8
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
+
+* Thu Nov  5 2020 Florian Weimer <fweimer@redhat.com> - 2.0.11-7
+- Remove build dependency on autogen
+
+* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.11-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
+
+* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.11-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
+
+* Wed Jan 22 2020 Tom Callaway <spot@fedoraproject.org> - 2.0.11-4
+- add Requires(post): %%{_bindir}/readlink (bz1792805)
+
+* Mon Dec 16 2019 Phil Sutter <psutter@redhat.com> - 2.0.11-3
+- Fix nft-variant reference in package description
+
+* Mon Dec 16 2019 Phil Sutter <psutter@redhat.com> - 2.0.11-2
+- Eliminate implicit dependency on initscripts package
+
+* Mon Dec  2 2019 Tom Callaway <spot@fedoraproject.org> - 2.0.11-1
+- update to 2.0.11 (all of Phil's awesome patches merged)
+
+* Wed Oct 30 2019 Phil Sutter <psutter@redhat.com> - 2.0.10-39
+- Make services sub-package obsolete compat to fix upgrade path
+
+* Tue Oct 22 2019 Phil Sutter <psutter@redhat.com> - 2.0.10-38
+- Drop compat sub-package again
+
+* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-37
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
+
+* Wed Jun 26 2019 Phil Sutter <psutter@redhat.com> - 2.0.10-36
+- Fix segfault with non-existing lock directory
+
+* Wed Apr 24 2019 Phil Sutter <psutter@redhat.com> - 2.0.10-35
+- Workaround missing broute table support in ebtables-nft
+
+* Tue Apr 09 2019 Phil Sutter <psutter@redhat.com> - 2.0.10-34
+- Fix lockfile location
+
+* Thu Apr 04 2019 Phil Sutter <psutter@redhat.com> - 2.0.10-33
+- Fix date in previous changelog entry
+- Use systemd_ordering macro
+
+* Thu Apr 04 2019 Phil Sutter <psutter@redhat.com> - 2.0.10-32
+- Add upstream changes since last release
+- Rename package to ebtables-legacy
+- Split systemd service into services sub-package
+- Rewrite systemd unit helper script for compatibility with ebtables-nft
+- Drop module unloading on service stop, this causes more harm than good
+- Remove save format settings, they are not effective anymore
+- Remove save on restart setting, restart is merely stop && start
+- Complete integration into alternatives
+- Remove needless ldconfig calls
+
+* Thu Feb  7 2019 Tom Callaway <spot@fedoraproject.org> - 2.0.10-31
+- build without as-needed everywhere (stop using Ubuntu patch)
+  Resolves BZ:1672683
+
+* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-30
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
+
+* Mon Jan 21 2019 David Abdurachmanov <david.abdurachmanov@gmail.com> 2.0.10-29
+- Disable --as-needed to resolve segfaults
+
+* Sun Jul 22 2018 Peter Robinson <pbrobinson@fedoraproject.org> 2.0.10-28
+- Add gcc dep, spec cleanups
+
+* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-27
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
+
+* Tue Jul 10 2018 Phil Sutter <psutter@redhat.com> - 2.0.10-26
+- Replace calls to ldconfig with newly introduced macro.
+- Install binaries in /usr/sbin instead of /sbin.
+- Make use of Alternatives system.
+
+* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-25
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-24
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
+
+* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-23
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-22
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Fri Jul 22 2016 Thomas Woerner <twoerner@redhat.com> - 2.0.10-21
+- /etc/ethertypes has been moved into the setup package for F-25+.
+  (RHBZ#1329256)
+
+* Mon May  9 2016 Thomas Woerner <twoerner@redhat.com> - 2.0.10-20
+- add upstream --noflush option patch for ebtables-restore
+
+* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 2.0.10-19
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Mon Jan 18 2016 Tom Callaway <spot@fedoraproject.org> - 2.0.10-18
+- Move lock file to /run/ebtables.lock (bz 1290327)
+
+* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.10-17
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Sat Aug 16 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.10-16
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Tue Jun 24 2014 Tom Callaway <spot@fedoraproject.org> - 2.0.10-15
+- create and own /var/lib/ebtables (bz 1093361)
+
+* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.10-14
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Mon Mar 31 2014 Tom Callaway <spot@fedoraproject.org> - 2.0.10-13
+- use standard optflags and ldflags (bz 1071993)
+
+* Wed Feb 19 2014 Tom Callaway <spot@fedoraproject.org> - 2.0.10-12
+- remove executable bit from systemd service file
+- add RARP type to ethertypes (bz 1060537)
+
+* Wed Aug 21 2013 Tom Callaway <spot@fedoraproject.org> - 2.0.10-11
+- convert to systemd
+
+* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.10-9
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Thu Mar 21 2013 Tom Callaway <spot@fedoraproject.org> - 2.0.10-8
+- add audit module
+
+* Wed Feb 13 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.10-7
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Wed Jul 18 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.10-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Thu Apr  5 2012 Tom Callaway <spot@fedoraproject.org> - 2.0.10-5
+- update to 2.0.10-4 (upstream numbering is goofy)
+- fix missing symbol issue with extension modules (bz810006)
+
+* Thu Feb 16 2012 Thomas Woerner <twoerner@redhat.com> - 2.0.10-4
+- replaced ebtables-save perl script by bash script to get rid of the perl 
+  requirement
+
+* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.10-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Thu Aug 11 2011 Tom Callaway <spot@fedoraproject.org> - 2.0.10-2
+- update to 2.0.10-2
+
+* Mon Jul 11 2011 Tom Callaway <spot@fedoraproject.org> - 2.0.10-1
+- update to 2.0.10-1
+
+* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.9-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Mon Feb 15 2010 Tom "spot" Callaway <tcallawa@redhat.com> - 2.0.9-5
+- update to 2.0.9-2
+
+* Fri Jan 29 2010 Thomas Woerner <twoerner@redhat.com> - 2.0.9-4
+- moved ebtables modules to /lib[64]/ebtables (rhbz#558886)
+
+* Fri Jan 15 2010 Thomas Woerner <twoerner@redhat.com> - 2.0.9-3
+- fixed init script to be lsb conform (rhbz#536828)
+- fixed download link according to package review
+
+* Wed Aug 19 2009 Tom "spot" Callaway <tcallawa@redhat.com> - 2.0.9-2
+- fix source0 url
+
+* Mon Jul 27 2009 Tom "spot" Callaway <tcallawa@redhat.com> - 2.0.9-1
+- update to 2.0.9
+
+* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.8-7
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Tue Feb 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.8-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
+
+* Tue Feb 19 2008 Fedora Release Engineering <rel-eng@fedoraproject.org> - 2.0.8-5
+- Autorebuild for GCC 4.3
+
+* Sun Oct 28 2007 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-4
+- bump to 2.0.8-2 from upstream
+- keep _libdir/ebtables, even though upstream just moved away from it.
+
+* Thu Aug 23 2007 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-3
+- use _libdir/ebtables to match upstream RPATH (bugzilla 248865)
+- correct license tag
+- use upstream init script
+- enable build-id
+- use cflags for all compiles
+- be sane with DESTDIR
+
+* Mon Jul  9 2007 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-2
+- remove "Fedora Core" reference in spec
+
+* Mon Jul  2 2007 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-1
+- final 2.0.8 release
+
+* Wed Jan 17 2007 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.8.rc3
+- fix release order
+
+* Wed Jan 17 2007 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.1.rc3
+- bump to rc3
+
+* Thu Oct 05 2006 Christian Iseli <Christian.Iseli@licr.org> 2.0.8-0.7.rc2
+ - rebuilt for unwind info generation, broken in gcc-4.1.1-21
+
+* Mon Sep 18 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.6.rc2
+- fix versioning
+
+* Thu Sep 14 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.3.rc2
+- fix bugzilla 206257
+
+* Tue Sep 12 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.2.rc2
+- fix for FC-6
+
+* Mon Apr 24 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.1.rc2
+- bump to rc2
+
+* Sun Apr  2 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.5.rc1
+- learn to use "install" correctly. :/
+
+* Sun Apr  2 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.4.rc1
+- package up the shared libs too
+
+* Wed Mar 29 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.3.rc1
+- use -fPIC
+
+* Wed Mar 29 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.2.rc1
+- broken tagging
+
+* Tue Jan 10 2006 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.8-0.1.rc1
+- bump to 2.0.8-rc1
+
+* Mon Jul  4 2005 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.6-7
+- buildsystem error requires artificial release bump
+
+* Mon Jul  4 2005 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.6-6
+- actually touch ghosted files
+
+* Fri Jul  1 2005 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.6-5
+- fix sysv file
+
+* Fri Jul  1 2005 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.6-4
+- remove INSTALL file
+- add some text to description, correct typos
+- fix %%postun
+- add PreReqs
+- add %%ghost config files
+
+* Tue May 31 2005 Tom "spot" Callaway <tcallawa@redhat.com> 2.0.6-3
+- reworked for Fedora Extras
+- add gcc4 fix
+- move init file into SOURCE1
+
+* Thu Dec 02 2004 Dag Wieers <dag@wieers.com> - 2.0.6-2
+- Added patch for gcc 3.4. (Nigel Smith)
+
+* Tue Apr 27 2004 Dag Wieers <dag@wieers.com> - 2.0.6-2
+- Cosmetic changes.
+
+* Tue Apr 27 2004 Dag Wieers <dag@wieers.com> - 2.0.6-1
+- Initial package. (using DAR)