aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej Żenczykowski <maze@google.com>2021-04-02 22:56:05 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-04-02 22:56:05 +0000
commita0c4e21d18eea26129cd498e5b0b4fc29efea9ce (patch)
tree189adc3ab85f970608529f7326429d36883324c2
parent5a7265ae38c0dff54021c1424fd199a3b6a8ac77 (diff)
parent51119072b79a2fe79fe5ee639fbed63d7e3b0c74 (diff)
downloadiptables-a0c4e21d18eea26129cd498e5b0b4fc29efea9ce.tar.gz
Merge tag 'v1.8.7' of git://git.netfilter.org/iptables am: 28a74be8ec am: e3fbb32008 am: 51119072b7
Original change: https://android-review.googlesource.com/c/platform/external/iptables/+/1650935 Change-Id: Ic76a7e8ca9e382dff33157f3868178bece99116d
-rw-r--r--configure.ac6
-rw-r--r--extensions/libarpt_mangle.c13
-rw-r--r--extensions/libebt_arp.c50
-rw-r--r--extensions/libebt_stp.c60
-rw-r--r--extensions/libxt_dccp.c58
-rw-r--r--extensions/libxt_dccp.txlate12
-rw-r--r--extensions/libxt_mac.c15
-rw-r--r--include/xtables.h3
-rwxr-xr-xiptables-test.py11
-rw-r--r--iptables/Makefile.am2
-rw-r--r--iptables/ip6tables.c79
-rw-r--r--iptables/iptables.c80
-rw-r--r--iptables/nft-arp.c115
-rw-r--r--iptables/nft-arp.h7
-rw-r--r--iptables/nft-bridge.c59
-rw-r--r--iptables/nft-cache.c162
-rw-r--r--iptables/nft-cache.h11
-rw-r--r--iptables/nft-chain.c59
-rw-r--r--iptables/nft-chain.h29
-rw-r--r--iptables/nft-ipv4.c12
-rw-r--r--iptables/nft-ipv6.c12
-rw-r--r--iptables/nft-shared.c17
-rw-r--r--iptables/nft-shared.h7
-rw-r--r--iptables/nft.c325
-rw-r--r--iptables/nft.h10
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0001-ebtables-basic_04
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_02
-rwxr-xr-xiptables/tests/shell/testcases/firewalld-restore/0001-firewalld_017
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_04
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_02
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_025
-rw-r--r--iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt4
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0346
-rw-r--r--iptables/xshared.c74
-rw-r--r--iptables/xshared.h20
-rw-r--r--iptables/xtables-arp.c86
-rw-r--r--iptables/xtables-eb-translate.c8
-rw-r--r--iptables/xtables-eb.c60
-rw-r--r--iptables/xtables-monitor.c73
-rw-r--r--iptables/xtables-save.c8
-rw-r--r--iptables/xtables.c80
-rw-r--r--libxtables/xtables.c73
42 files changed, 1204 insertions, 896 deletions
diff --git a/configure.ac b/configure.ac
index 357c5116..6864378a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
-AC_INIT([iptables], [1.8.6])
+AC_INIT([iptables], [1.8.7])
# See libtool.info "Libtool's versioning system"
-libxtables_vcurrent=15
-libxtables_vage=3
+libxtables_vcurrent=16
+libxtables_vage=4
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
diff --git a/extensions/libarpt_mangle.c b/extensions/libarpt_mangle.c
index 2fea6185..a2378a8b 100644
--- a/extensions/libarpt_mangle.c
+++ b/extensions/libarpt_mangle.c
@@ -130,15 +130,6 @@ static void arpmangle_final_check(unsigned int flags)
{
}
-static void print_mac(const unsigned char *mac, int l)
-{
- int j;
-
- for (j = 0; j < l; j++)
- printf("%02x%s", mac[j],
- (j==l-1) ? "" : ":");
-}
-
static const char *ipaddr_to(const struct in_addr *addrp, int numeric)
{
if (numeric)
@@ -159,7 +150,7 @@ arpmangle_print(const void *ip, const struct xt_entry_target *target,
}
if (m->flags & ARPT_MANGLE_SDEV) {
printf(" --mangle-mac-s ");
- print_mac((unsigned char *)m->src_devaddr, 6);
+ xtables_print_mac((unsigned char *)m->src_devaddr);
}
if (m->flags & ARPT_MANGLE_TIP) {
printf(" --mangle-ip-d %s",
@@ -167,7 +158,7 @@ arpmangle_print(const void *ip, const struct xt_entry_target *target,
}
if (m->flags & ARPT_MANGLE_TDEV) {
printf(" --mangle-mac-d ");
- print_mac((unsigned char *)m->tgt_devaddr, 6);
+ xtables_print_mac((unsigned char *)m->tgt_devaddr);
}
if (m->target != NF_ACCEPT) {
printf(" --mangle-target %s",
diff --git a/extensions/libebt_arp.c b/extensions/libebt_arp.c
index a062b7e7..d5035b95 100644
--- a/extensions/libebt_arp.c
+++ b/extensions/libebt_arp.c
@@ -161,54 +161,6 @@ static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
*addr = *addr & *msk;
}
-static int brarp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr = NULL;
-
- static const unsigned char mac_type_unicast[ETH_ALEN];
- static const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
- static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
- static const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, mac_type_unicast, ETH_ALEN);
- memcpy(mask, msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, mac_type_multicast, ETH_ALEN);
- memcpy(mask, mac_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, mac_type_broadcast, ETH_ALEN);
- memcpy(mask, mac_type_broadcast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "BGA") == 0) {
- memcpy(to, mac_type_bridge_group, ETH_ALEN);
- memcpy(mask, msk_type_bridge_group, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int
brarp_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
@@ -317,7 +269,7 @@ brarp_parse(int c, char **argv, int invert, unsigned int *flags,
else
arpinfo->invflags |= EBT_ARP_DST_MAC;
}
- if (brarp_get_mac_and_mask(optarg, maddr, mmask))
+ if (xtables_parse_mac_and_mask(optarg, maddr, mmask))
xtables_error(PARAMETER_PROBLEM, "Problem with ARP MAC address argument");
break;
case ARP_GRAT:
diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c
index 06cf93b8..81ba572c 100644
--- a/extensions/libebt_stp.c
+++ b/extensions/libebt_stp.c
@@ -150,54 +150,6 @@ static void print_range(unsigned int l, unsigned int u)
printf("%u:%u ", l, u);
}
-static int brstp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr = NULL;
-
- static const unsigned char mac_type_unicast[ETH_ALEN];
- static const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
- static const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
- static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
- static const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, mac_type_unicast, ETH_ALEN);
- memcpy(mask, msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, mac_type_multicast, ETH_ALEN);
- memcpy(mask, mac_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, mac_type_broadcast, ETH_ALEN);
- memcpy(mask, mac_type_broadcast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "BGA") == 0) {
- memcpy(to, mac_type_bridge_group, ETH_ALEN);
- memcpy(mask, msk_type_bridge_group, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int
brstp_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
@@ -280,15 +232,15 @@ brstp_parse(int c, char **argv, int invert, unsigned int *flags,
xtables_error(PARAMETER_PROBLEM, "Bad --stp-forward-delay range");
break;
case EBT_STP_ROOTADDR:
- if (brstp_get_mac_and_mask(argv[optind-1],
- (unsigned char *)stpinfo->config.root_addr,
- (unsigned char *)stpinfo->config.root_addrmsk))
+ if (xtables_parse_mac_and_mask(argv[optind-1],
+ stpinfo->config.root_addr,
+ stpinfo->config.root_addrmsk))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-addr address");
break;
case EBT_STP_SENDERADDR:
- if (brstp_get_mac_and_mask(argv[optind-1],
- (unsigned char *)stpinfo->config.sender_addr,
- (unsigned char *)stpinfo->config.sender_addrmsk))
+ if (xtables_parse_mac_and_mask(argv[optind-1],
+ stpinfo->config.sender_addr,
+ stpinfo->config.sender_addrmsk))
xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-addr address");
break;
default:
diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c
index 5e67c264..aea3e20b 100644
--- a/extensions/libxt_dccp.c
+++ b/extensions/libxt_dccp.c
@@ -76,6 +76,9 @@ static const char *const dccp_pkt_types[] = {
[DCCP_PKT_INVALID] = "INVALID",
};
+/* Bits for type values 11-15 */
+#define INVALID_OTHER_TYPE_MASK 0xf800
+
static uint16_t
parse_dccp_types(const char *typestring)
{
@@ -95,6 +98,9 @@ parse_dccp_types(const char *typestring)
xtables_error(PARAMETER_PROBLEM,
"Unknown DCCP type `%s'", ptr);
}
+ if (typemask & (1 << DCCP_PKT_INVALID))
+ typemask |= INVALID_OTHER_TYPE_MASK;
+
free(buffer);
return typemask;
@@ -193,9 +199,13 @@ print_types(uint16_t types, int inverted, int numeric)
if (numeric)
printf("%u", i);
- else
+ else {
printf("%s", dccp_pkt_types[i]);
+ if (i == DCCP_PKT_INVALID)
+ break;
+ }
+
types &= ~(1 << i);
}
}
@@ -288,6 +298,7 @@ static const char *const dccp_pkt_types_xlate[] = {
[DCCP_PKT_RESET] = "reset",
[DCCP_PKT_SYNC] = "sync",
[DCCP_PKT_SYNCACK] = "syncack",
+ [DCCP_PKT_INVALID] = "10-15",
};
static int dccp_type_xlate(const struct xt_dccp_info *einfo,
@@ -296,10 +307,10 @@ static int dccp_type_xlate(const struct xt_dccp_info *einfo,
bool have_type = false, set_need = false;
uint16_t types = einfo->typemask;
- if (types & (1 << DCCP_PKT_INVALID))
- return 0;
-
- xt_xlate_add(xl, " dccp type%s ", einfo->invflags ? " !=" : "");
+ if (types & INVALID_OTHER_TYPE_MASK) {
+ types &= ~INVALID_OTHER_TYPE_MASK;
+ types |= 1 << DCCP_PKT_INVALID;
+ }
if ((types != 0) && !(types == (types & -types))) {
xt_xlate_add(xl, "{");
@@ -335,34 +346,37 @@ static int dccp_xlate(struct xt_xlate *xl,
char *space = "";
int ret = 1;
- xt_xlate_add(xl, "dccp ");
-
if (einfo->flags & XT_DCCP_SRC_PORTS) {
+ xt_xlate_add(xl, "dccp sport%s %u",
+ einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
+ einfo->spts[0]);
+
if (einfo->spts[0] != einfo->spts[1])
- xt_xlate_add(xl, "sport%s %u-%u",
- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
- einfo->spts[0], einfo->spts[1]);
- else
- xt_xlate_add(xl, "sport%s %u",
- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
- einfo->spts[0]);
+ xt_xlate_add(xl, "-%u", einfo->spts[1]);
+
space = " ";
}
if (einfo->flags & XT_DCCP_DEST_PORTS) {
+ xt_xlate_add(xl, "%sdccp dport%s %u", space,
+ einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
+ einfo->dpts[0]);
+
if (einfo->dpts[0] != einfo->dpts[1])
- xt_xlate_add(xl, "%sdport%s %u-%u", space,
- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
- einfo->dpts[0], einfo->dpts[1]);
- else
- xt_xlate_add(xl, "%sdport%s %u", space,
- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
- einfo->dpts[0]);
+ xt_xlate_add(xl, "-%u", einfo->dpts[1]);
+
+ space = " ";
}
- if (einfo->flags & XT_DCCP_TYPE)
+ if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) {
+ xt_xlate_add(xl, "%sdccp type%s ", space,
+ einfo->invflags & XT_DCCP_TYPE ? " !=" : "");
ret = dccp_type_xlate(einfo, xl);
+ space = " ";
+ }
+
+ /* FIXME: no dccp option support in nftables yet */
if (einfo->flags & XT_DCCP_OPTION)
ret = 0;
diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate
index b47dc65f..ea853f6a 100644
--- a/extensions/libxt_dccp.txlate
+++ b/extensions/libxt_dccp.txlate
@@ -7,8 +7,14 @@ nft add rule ip filter INPUT dccp dport 100-200 counter
iptables-translate -A INPUT -p dccp -m dccp ! --dport 100
nft add rule ip filter INPUT dccp dport != 100 counter
-iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK
-nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack} counter
+iptables-translate -A INPUT -p dccp -m dccp --dccp-types CLOSE
+nft add rule ip filter INPUT dccp type close counter
+
+iptables-translate -A INPUT -p dccp -m dccp --dccp-types INVALID
+nft add rule ip filter INPUT dccp type 10-15 counter
+
+iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK,INVALID
+nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15} counter
iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100
-nft add rule ip filter INPUT dccp sport 200 dport 100 counter
+nft add rule ip filter INPUT dccp sport 200 dccp dport 100 counter
diff --git a/extensions/libxt_mac.c b/extensions/libxt_mac.c
index b6d717bc..b90eef20 100644
--- a/extensions/libxt_mac.c
+++ b/extensions/libxt_mac.c
@@ -37,15 +37,6 @@ static void mac_parse(struct xt_option_call *cb)
macinfo->invert = 1;
}
-static void print_mac(const unsigned char *macaddress)
-{
- unsigned int i;
-
- printf(" %02X", macaddress[0]);
- for (i = 1; i < ETH_ALEN; ++i)
- printf(":%02X", macaddress[i]);
-}
-
static void
mac_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
@@ -56,7 +47,7 @@ mac_print(const void *ip, const struct xt_entry_match *match, int numeric)
if (info->invert)
printf(" !");
- print_mac(info->srcaddr);
+ xtables_print_mac(info->srcaddr);
}
static void mac_save(const void *ip, const struct xt_entry_match *match)
@@ -66,8 +57,8 @@ static void mac_save(const void *ip, const struct xt_entry_match *match)
if (info->invert)
printf(" !");
- printf(" --mac-source");
- print_mac(info->srcaddr);
+ printf(" --mac-source ");
+ xtables_print_mac(info->srcaddr);
}
static void print_mac_xlate(const unsigned char *macaddress,
diff --git a/include/xtables.h b/include/xtables.h
index 5044dd08..df1eaee3 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -557,6 +557,9 @@ extern void xtables_save_string(const char *value);
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
extern void xtables_print_num(uint64_t number, unsigned int format);
+extern int xtables_parse_mac_and_mask(const char *from, void *to, void *mask);
+extern int xtables_print_well_known_mac_and_mask(const void *mac,
+ const void *mask);
extern void xtables_print_mac(const unsigned char *macaddress);
extern void xtables_print_mac_and_mask(const unsigned char *mac,
const unsigned char *mask);
diff --git a/iptables-test.py b/iptables-test.py
index 6b6eb611..ca5efb1b 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -310,7 +310,7 @@ def show_missing():
#
def main():
parser = argparse.ArgumentParser(description='Run iptables tests')
- parser.add_argument('filename', nargs='?',
+ parser.add_argument('filename', nargs='*',
metavar='path/to/file.t',
help='Run only this test')
parser.add_argument('-H', '--host', action='store_true',
@@ -359,13 +359,20 @@ def main():
return
if args.filename:
- file_list = [args.filename]
+ file_list = args.filename
else:
file_list = [os.path.join(EXTENSIONS_PATH, i)
for i in os.listdir(EXTENSIONS_PATH)
if i.endswith('.t')]
file_list.sort()
+ if not args.netns:
+ try:
+ import unshare
+ unshare.unshare(unshare.CLONE_NEWNET)
+ except:
+ print("Cannot run in own namespace, connectivity might break")
+
for filename in file_list:
file_tests, file_passed = run_test_file(filename, args.netns)
if file_tests:
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 4bf5742c..f7895210 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -38,7 +38,7 @@ xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \
nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
xtables-monitor.c nft-cache.c \
xtables-arp-standalone.c xtables-arp.c \
- nft-bridge.c nft-cmd.c \
+ nft-bridge.c nft-cmd.c nft-chain.c \
xtables-eb-standalone.c xtables-eb.c \
xtables-eb-translate.c \
xtables-translate.c
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index 576c2cf8..c95355b0 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -45,10 +45,6 @@
#include "ip6tables-multi.h"
#include "xshared.h"
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c'};
-
static const char unsupported_rev[] = " [unsupported revision]";
static struct option original_opts[] = {
@@ -100,36 +96,6 @@ struct xtables_globals ip6tables_globals = {
.compat_rev = xtables_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' '},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'},
-};
-
static const unsigned int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -264,51 +230,6 @@ ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 88ef6cf6..7d618311 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -41,11 +41,6 @@
#include <fcntl.h>
#include "xshared.h"
-#define OPT_FRAGMENT 0x00800U
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
-
static const char unsupported_rev[] = " [unsupported revision]";
static struct option original_opts[] = {
@@ -99,36 +94,6 @@ struct xtables_globals iptables_globals = {
.compat_rev = xtables_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c -f */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-};
-
static const int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -263,51 +228,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 67f4529d..c82ffdc9 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -134,34 +134,34 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
int ret = 0;
if (fw->arp.iniface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_IN);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
add_iniface(r, fw->arp.iniface, op);
}
if (fw->arp.outiface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_OUT);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
add_outiface(r, fw->arp.outiface, op);
}
if (fw->arp.arhrd != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHRD) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHRD);
+ fw->arp.invflags & IPT_INV_ARPHRD) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
add_payload(r, offsetof(struct arphdr, ar_hrd), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arhrd, op);
}
if (fw->arp.arpro != 0 ||
- fw->arp.invflags & ARPT_INV_ARPPRO) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPPRO);
+ fw->arp.invflags & IPT_INV_PROTO) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
add_payload(r, offsetof(struct arphdr, ar_pro), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arpro, op);
}
if (fw->arp.arhln != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHLN) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHLN);
+ fw->arp.invflags & IPT_INV_ARPHLN) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
add_proto(r, offsetof(struct arphdr, ar_hln), 1,
fw->arp.arhln, op);
}
@@ -169,16 +169,17 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
if (fw->arp.arpop != 0 ||
- fw->arp.invflags & ARPT_INV_ARPOP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPOP);
+ fw->arp.invflags & IPT_INV_ARPOP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
add_payload(r, offsetof(struct arphdr, ar_op), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arpop, op);
}
if (need_devaddr(&fw->arp.src_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCDEVADDR);
- add_addr(r, sizeof(struct arphdr),
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr),
&fw->arp.src_devaddr.addr,
&fw->arp.src_devaddr.mask,
fw->arp.arhln, op);
@@ -187,17 +188,19 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (fw->arp.src.s_addr != 0 ||
fw->arp.smsk.s_addr != 0 ||
- fw->arp.invflags & ARPT_INV_SRCIP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCIP);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln,
+ fw->arp.invflags & IPT_INV_SRCIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln,
&fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
sizeof(struct in_addr), op);
}
if (need_devaddr(&fw->arp.tgt_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTDEVADDR);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
&fw->arp.tgt_devaddr.addr,
&fw->arp.tgt_devaddr.mask,
fw->arp.arhln, op);
@@ -205,9 +208,10 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (fw->arp.tgt.s_addr != 0 ||
fw->arp.tmsk.s_addr != 0 ||
- fw->arp.invflags & ARPT_INV_TGTIP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTIP);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
+ fw->arp.invflags & IPT_INV_DSTIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
&fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
sizeof(struct in_addr), op);
}
@@ -236,28 +240,6 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
return ret;
}
-static uint16_t ipt_to_arpt_flags(uint8_t invflags)
-{
- uint16_t result = 0;
-
- if (invflags & IPT_INV_VIA_IN)
- result |= ARPT_INV_VIA_IN;
-
- if (invflags & IPT_INV_VIA_OUT)
- result |= ARPT_INV_VIA_OUT;
-
- if (invflags & IPT_INV_SRCIP)
- result |= ARPT_INV_SRCIP;
-
- if (invflags & IPT_INV_DSTIP)
- result |= ARPT_INV_TGTIP;
-
- if (invflags & IPT_INV_PROTO)
- result |= ARPT_INV_ARPPRO;
-
- return result;
-}
-
static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
void *data)
{
@@ -269,7 +251,7 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
fw->arp.outiface, fw->arp.outiface_mask,
&flags);
- fw->arp.invflags |= ipt_to_arpt_flags(flags);
+ fw->arp.invflags |= flags;
}
static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
@@ -303,7 +285,8 @@ static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx,
memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(info->mask, 0xff, ETH_ALEN);
+ memset(info->mask, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
return inv;
@@ -325,33 +308,33 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
fw->arp.arhrd = ar_hrd;
fw->arp.arhrd_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPHRD;
+ fw->arp.invflags |= IPT_INV_ARPHRD;
break;
case offsetof(struct arphdr, ar_pro):
get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
fw->arp.arpro = ar_pro;
fw->arp.arpro_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPPRO;
+ fw->arp.invflags |= IPT_INV_PROTO;
break;
case offsetof(struct arphdr, ar_op):
get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
fw->arp.arpop = ar_op;
fw->arp.arpop_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPOP;
+ fw->arp.invflags |= IPT_INV_ARPOP;
break;
case offsetof(struct arphdr, ar_hln):
get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv);
fw->arp.arhln = ar_hln;
fw->arp.arhln_mask = 0xff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPOP;
+ fw->arp.invflags |= IPT_INV_ARPOP;
break;
default:
if (ctx->payload.offset == sizeof(struct arphdr)) {
if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr))
- fw->arp.invflags |= ARPT_INV_SRCDEVADDR;
+ fw->arp.invflags |= IPT_INV_SRCDEVADDR;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln) {
get_cmp_data(e, &addr, sizeof(addr), &inv);
@@ -360,16 +343,18 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &fw->arp.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- fw->arp.smsk.s_addr = 0xffffffff;
+ memset(&fw->arp.smsk, 0xff,
+ min(ctx->payload.len,
+ sizeof(struct in_addr)));
}
if (inv)
- fw->arp.invflags |= ARPT_INV_SRCIP;
+ fw->arp.invflags |= IPT_INV_SRCIP;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln +
sizeof(struct in_addr)) {
if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr))
- fw->arp.invflags |= ARPT_INV_TGTDEVADDR;
+ fw->arp.invflags |= IPT_INV_TGTDEVADDR;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln +
sizeof(struct in_addr) +
@@ -380,11 +365,13 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &fw->arp.tmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- fw->arp.tmsk.s_addr = 0xffffffff;
+ memset(&fw->arp.tmsk, 0xff,
+ min(ctx->payload.len,
+ sizeof(struct in_addr)));
}
if (inv)
- fw->arp.invflags |= ARPT_INV_TGTIP;
+ fw->arp.invflags |= IPT_INV_DSTIP;
}
break;
}
@@ -439,7 +426,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
else strcat(iface, "any");
}
if (print_iface) {
- printf("%s%s-i %s", sep, fw->arp.invflags & ARPT_INV_VIA_IN ?
+ printf("%s%s-i %s", sep, fw->arp.invflags & IPT_INV_VIA_IN ?
"! " : "", iface);
sep = " ";
}
@@ -457,13 +444,13 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
else strcat(iface, "any");
}
if (print_iface) {
- printf("%s%s-o %s", sep, fw->arp.invflags & ARPT_INV_VIA_OUT ?
+ printf("%s%s-o %s", sep, fw->arp.invflags & IPT_INV_VIA_OUT ?
"! " : "", iface);
sep = " ";
}
if (fw->arp.smsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCIP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
@@ -480,7 +467,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devsrc;
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCDEVADDR
? "! " : "");
printf("--src-mac ");
xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
@@ -489,7 +476,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
after_devsrc:
if (fw->arp.tmsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTIP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_DSTIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
@@ -506,7 +493,7 @@ after_devsrc:
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devdst;
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_TGTDEVADDR
? "! " : "");
printf("--dst-mac ");
xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
@@ -516,7 +503,7 @@ after_devsrc:
after_devdst:
if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHLN
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN
? "! " : "");
printf("--h-length %d", fw->arp.arhln);
if (fw->arp.arhln_mask != 255)
@@ -527,7 +514,7 @@ after_devdst:
if (fw->arp.arpop_mask != 0) {
int tmp = ntohs(fw->arp.arpop);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPOP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
? "! " : "");
if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC))
printf("--opcode %s", arp_opcodes[tmp-1]);
@@ -542,7 +529,7 @@ after_devdst:
if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) {
uint16_t tmp = ntohs(fw->arp.arhrd);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHRD
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD
? "! " : "");
if (tmp == 1 && !(format & FMT_NUMERIC))
printf("--h-type %s", "Ethernet");
@@ -556,7 +543,7 @@ after_devdst:
if (fw->arp.arpro_mask != 0) {
int tmp = ntohs(fw->arp.arpro);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPPRO
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_PROTO
? "! " : "");
if (tmp == 0x0800 && !(format & FMT_NUMERIC))
printf("--proto-type %s", "IPv4");
diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h
index 3411fc3d..0d93a31f 100644
--- a/iptables/nft-arp.h
+++ b/iptables/nft-arp.h
@@ -4,4 +4,11 @@
extern char *arp_opcodes[];
#define NUMOPCODES 9
+/* define invflags which won't collide with IPT ones */
+#define IPT_INV_SRCDEVADDR 0x0080
+#define IPT_INV_TGTDEVADDR 0x0100
+#define IPT_INV_ARPHLN 0x0200
+#define IPT_INV_ARPOP 0x0400
+#define IPT_INV_ARPHRD 0x0800
+
#endif
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index dbf11eb5..d98fd527 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -58,44 +58,11 @@ void ebt_cs_clean(struct iptables_command_state *cs)
}
}
-static void ebt_print_mac(const unsigned char *mac)
-{
- int j;
-
- for (j = 0; j < ETH_ALEN; j++)
- printf("%02x%s", mac[j], (j==ETH_ALEN-1) ? "" : ":");
-}
-
-static bool mac_all_ones(const unsigned char *mac)
-{
- static const char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
- return memcmp(mac, hlpmsk, sizeof(hlpmsk)) == 0;
-}
-
/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
{
-
- if (!memcmp(mac, eb_mac_type_unicast, 6) &&
- !memcmp(mask, eb_msk_type_unicast, 6))
- printf("Unicast");
- else if (!memcmp(mac, eb_mac_type_multicast, 6) &&
- !memcmp(mask, eb_msk_type_multicast, 6))
- printf("Multicast");
- else if (!memcmp(mac, eb_mac_type_broadcast, 6) &&
- !memcmp(mask, eb_msk_type_broadcast, 6))
- printf("Broadcast");
- else if (!memcmp(mac, eb_mac_type_bridge_group, 6) &&
- !memcmp(mask, eb_msk_type_bridge_group, 6))
- printf("BGA");
- else {
- ebt_print_mac(mac);
- if (!mac_all_ones(mask)) {
- printf("/");
- ebt_print_mac(mask);
- }
- }
+ if (xtables_print_well_known_mac_and_mask(mac, mask))
+ xtables_print_mac_and_mask(mac, mask);
}
static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
@@ -159,20 +126,16 @@ static int nft_bridge_add(struct nft_handle *h,
if (fw->bitmask & EBT_ISOURCE) {
op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
- add_payload(r, offsetof(struct ethhdr, h_source), 6,
- NFT_PAYLOAD_LL_HEADER);
- if (!mac_all_ones(fw->sourcemsk))
- add_bitwise(r, fw->sourcemsk, 6);
- add_cmp_ptr(r, op, fw->sourcemac, 6);
+ add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_source),
+ fw->sourcemac, fw->sourcemsk, ETH_ALEN, op);
}
if (fw->bitmask & EBT_IDEST) {
op = nft_invflags2cmp(fw->invflags, EBT_IDEST);
- add_payload(r, offsetof(struct ethhdr, h_dest), 6,
- NFT_PAYLOAD_LL_HEADER);
- if (!mac_all_ones(fw->destmsk))
- add_bitwise(r, fw->destmsk, 6);
- add_cmp_ptr(r, op, fw->destmac, 6);
+ add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_dest),
+ fw->destmac, fw->destmsk, ETH_ALEN, op);
}
if ((fw->bitmask & EBT_NOPROTO) == 0) {
@@ -258,7 +221,8 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&fw->destmsk, 0xff, ETH_ALEN);
+ memset(&fw->destmsk, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
fw->bitmask |= EBT_IDEST;
break;
@@ -272,7 +236,8 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&fw->sourcemsk, 0xff, ETH_ALEN);
+ memset(&fw->sourcemsk, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
fw->bitmask |= EBT_ISOURCE;
break;
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index 32cfd6cf..6b6e6da4 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -24,6 +24,7 @@
#include "nft.h"
#include "nft-cache.h"
+#include "nft-chain.h"
static void cache_chain_list_insert(struct list_head *list, const char *name)
{
@@ -153,9 +154,7 @@ static int fetch_table_cache(struct nft_handle *h)
if (!h->tables[i].name)
continue;
- h->cache->table[type].chains = nftnl_chain_list_alloc();
- if (!h->cache->table[type].chains)
- return 0;
+ h->cache->table[type].chains = nft_chain_list_alloc();
h->cache->table[type].sets = nftnl_set_list_alloc();
if (!h->cache->table[type].sets)
@@ -165,6 +164,83 @@ static int fetch_table_cache(struct nft_handle *h)
return 1;
}
+static uint32_t djb_hash(const char *key)
+{
+ uint32_t i, hash = 5381;
+
+ for (i = 0; i < strlen(key); i++)
+ hash = ((hash << 5) + hash) + key[i];
+
+ return hash;
+}
+
+static struct hlist_head *chain_name_hlist(struct nft_handle *h,
+ const struct builtin_table *t,
+ const char *chain)
+{
+ int key = djb_hash(chain) % CHAIN_NAME_HSIZE;
+
+ return &h->cache->table[t->type].chains->names[key];
+}
+
+struct nft_chain *
+nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
+{
+ const struct builtin_table *t;
+ struct hlist_node *node;
+ struct nft_chain *c;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return NULL;
+
+ hlist_for_each_entry(c, node, chain_name_hlist(h, t, chain), hnode) {
+ if (!strcmp(nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME),
+ chain))
+ return c;
+ }
+ return NULL;
+}
+
+int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
+ struct nftnl_chain *c)
+{
+ const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ struct nft_chain *nc = nft_chain_alloc(c);
+
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
+ uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
+
+ if (hooknum >= NF_INET_NUMHOOKS) {
+ nft_chain_free(nc);
+ return -EINVAL;
+ }
+
+ if (h->cache->table[t->type].base_chains[hooknum]) {
+ nft_chain_free(nc);
+ return -EEXIST;
+ }
+
+ h->cache->table[t->type].base_chains[hooknum] = nc;
+ } else {
+ struct nft_chain_list *clist = h->cache->table[t->type].chains;
+ struct list_head *pos = &clist->list;
+ struct nft_chain *cur;
+ const char *n;
+
+ list_for_each_entry(cur, &clist->list, head) {
+ n = nftnl_chain_get_str(cur->nftnl, NFTNL_CHAIN_NAME);
+ if (strcmp(cname, n) <= 0) {
+ pos = &cur->head;
+ break;
+ }
+ }
+ list_add_tail(&nc->head, pos);
+ }
+ hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
+ return 0;
+}
+
struct nftnl_chain_list_cb_data {
struct nft_handle *h;
const struct builtin_table *t;
@@ -174,7 +250,6 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_chain_list_cb_data *d = data;
const struct builtin_table *t = d->t;
- struct nftnl_chain_list *list;
struct nft_handle *h = d->h;
struct nftnl_chain *c;
const char *tname;
@@ -196,8 +271,8 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
goto out;
}
- list = h->cache->table[t->type].chains;
- nftnl_chain_list_add_tail(c, list);
+ if (nft_cache_add_chain(h, t, c))
+ goto out;
return MNL_CB_OK;
out:
@@ -414,8 +489,9 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
-static int nft_rule_list_update(struct nftnl_chain *c, void *data)
+static int nft_rule_list_update(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = data;
char buf[16536];
struct nlmsghdr *nlh;
@@ -455,21 +531,16 @@ static int fetch_rule_cache(struct nft_handle *h,
{
int i;
- if (t) {
- struct nftnl_chain_list *list =
- h->cache->table[t->type].chains;
-
- return nftnl_chain_list_foreach(list, nft_rule_list_update, h);
- }
+ if (t)
+ return nft_chain_foreach(h, t->name, nft_rule_list_update, h);
for (i = 0; i < NFT_TABLE_MAX; i++) {
- enum nft_table_type type = h->tables[i].type;
if (!h->tables[i].name)
continue;
- if (nftnl_chain_list_foreach(h->cache->table[type].chains,
- nft_rule_list_update, h))
+ if (nft_chain_foreach(h, h->tables[i].name,
+ nft_rule_list_update, h))
return -1;
}
return 0;
@@ -535,31 +606,25 @@ static int ____flush_rule_cache(struct nftnl_rule *r, void *data)
return 0;
}
-static int __flush_rule_cache(struct nftnl_chain *c, void *data)
+static int __flush_rule_cache(struct nft_chain *c, void *data)
{
- return nftnl_rule_foreach(c, ____flush_rule_cache, NULL);
+ return nftnl_rule_foreach(c->nftnl, ____flush_rule_cache, NULL);
}
int flush_rule_cache(struct nft_handle *h, const char *table,
- struct nftnl_chain *c)
+ struct nft_chain *c)
{
- const struct builtin_table *t;
-
if (c)
return __flush_rule_cache(c, NULL);
- t = nft_table_builtin_find(h, table);
- if (!t || !h->cache->table[t->type].chains)
- return 0;
-
- return nftnl_chain_list_foreach(h->cache->table[t->type].chains,
- __flush_rule_cache, NULL);
+ nft_chain_foreach(h, table, __flush_rule_cache, NULL);
+ return 0;
}
-static int __flush_chain_cache(struct nftnl_chain *c, void *data)
+static int __flush_chain_cache(struct nft_chain *c, void *data)
{
- nftnl_chain_list_del(c);
- nftnl_chain_free(c);
+ nft_chain_list_del(c);
+ nft_chain_free(c);
return 0;
}
@@ -572,6 +637,19 @@ static int __flush_set_cache(struct nftnl_set *s, void *data)
return 0;
}
+static void flush_base_chain_cache(struct nft_chain **base_chains)
+{
+ int i;
+
+ for (i = 0; i < NF_INET_NUMHOOKS; i++) {
+ if (!base_chains[i])
+ continue;
+ hlist_del(&base_chains[i]->hnode);
+ nft_chain_free(base_chains[i]);
+ base_chains[i] = NULL;
+ }
+}
+
static int flush_cache(struct nft_handle *h, struct nft_cache *c,
const char *tablename)
{
@@ -582,9 +660,10 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
table = nft_table_builtin_find(h, tablename);
if (!table)
return 0;
- if (c->table[table->type].chains)
- nftnl_chain_list_foreach(c->table[table->type].chains,
- __flush_chain_cache, NULL);
+
+ flush_base_chain_cache(c->table[table->type].base_chains);
+ nft_chain_foreach(h, tablename, __flush_chain_cache, NULL);
+
if (c->table[table->type].sets)
nftnl_set_list_foreach(c->table[table->type].sets,
__flush_set_cache, NULL);
@@ -595,10 +674,12 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
if (h->tables[i].name == NULL)
continue;
+ flush_base_chain_cache(c->table[i].base_chains);
if (c->table[i].chains) {
- nftnl_chain_list_free(c->table[i].chains);
+ nft_chain_list_free(c->table[i].chains);
c->table[i].chains = NULL;
}
+
if (c->table[i].sets) {
nftnl_set_list_free(c->table[i].sets);
c->table[i].sets = NULL;
@@ -689,16 +770,3 @@ nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
return h->cache->table[t->type].sets;
}
-
-struct nftnl_chain_list *
-nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain)
-{
- const struct builtin_table *t;
-
- t = nft_table_builtin_find(h, table);
- if (!t)
- return NULL;
-
- return h->cache->table[t->type].chains;
-}
-
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index 76f9fbb6..20d96bee 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -2,7 +2,9 @@
#define _NFT_CACHE_H_
struct nft_handle;
+struct nft_chain;
struct nft_cmd;
+struct builtin_table;
void nft_cache_level_set(struct nft_handle *h, int level,
const struct nft_cmd *cmd);
@@ -10,11 +12,14 @@ void nft_rebuild_cache(struct nft_handle *h);
void nft_release_cache(struct nft_handle *h);
void flush_chain_cache(struct nft_handle *h, const char *tablename);
int flush_rule_cache(struct nft_handle *h, const char *table,
- struct nftnl_chain *c);
+ struct nft_chain *c);
void nft_cache_build(struct nft_handle *h);
+int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
+ struct nftnl_chain *c);
+
+struct nft_chain *
+nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
-struct nftnl_chain_list *
-nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain);
struct nftnl_set_list *
nft_set_list_get(struct nft_handle *h, const char *table, const char *set);
diff --git a/iptables/nft-chain.c b/iptables/nft-chain.c
new file mode 100644
index 00000000..e954170f
--- /dev/null
+++ b/iptables/nft-chain.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Red Hat GmbH. Author: Phil Sutter <phil@nwl.cc>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <stdlib.h>
+#include <xtables.h>
+
+#include "nft-chain.h"
+
+struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl)
+{
+ struct nft_chain *c = xtables_malloc(sizeof(*c));
+
+ INIT_LIST_HEAD(&c->head);
+ c->nftnl = nftnl;
+
+ return c;
+}
+
+void nft_chain_free(struct nft_chain *c)
+{
+ if (c->nftnl)
+ nftnl_chain_free(c->nftnl);
+ free(c);
+}
+
+struct nft_chain_list *nft_chain_list_alloc(void)
+{
+ struct nft_chain_list *list = xtables_malloc(sizeof(*list));
+ int i;
+
+ INIT_LIST_HEAD(&list->list);
+ for (i = 0; i < CHAIN_NAME_HSIZE; i++)
+ INIT_HLIST_HEAD(&list->names[i]);
+
+ return list;
+}
+
+void nft_chain_list_del(struct nft_chain *c)
+{
+ list_del(&c->head);
+ hlist_del(&c->hnode);
+}
+
+void nft_chain_list_free(struct nft_chain_list *list)
+{
+ struct nft_chain *c, *c2;
+
+ list_for_each_entry_safe(c, c2, &list->list, head) {
+ nft_chain_list_del(c);
+ nft_chain_free(c);
+ }
+ free(list);
+}
diff --git a/iptables/nft-chain.h b/iptables/nft-chain.h
new file mode 100644
index 00000000..137f4b7f
--- /dev/null
+++ b/iptables/nft-chain.h
@@ -0,0 +1,29 @@
+#ifndef _NFT_CHAIN_H_
+#define _NFT_CHAIN_H_
+
+#include <libnftnl/chain.h>
+#include <libiptc/linux_list.h>
+
+struct nft_handle;
+
+struct nft_chain {
+ struct list_head head;
+ struct hlist_node hnode;
+ struct nftnl_chain *nftnl;
+};
+
+#define CHAIN_NAME_HSIZE 512
+
+struct nft_chain_list {
+ struct list_head list;
+ struct hlist_head names[CHAIN_NAME_HSIZE];
+};
+
+struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl);
+void nft_chain_free(struct nft_chain *c);
+
+struct nft_chain_list *nft_chain_list_alloc(void);
+void nft_chain_list_free(struct nft_chain_list *list);
+void nft_chain_list_del(struct nft_chain *c);
+
+#endif /* _NFT_CHAIN_H_ */
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index afdecf97..fdc15c6f 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -50,13 +50,15 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP);
- add_addr(r, offsetof(struct iphdr, saddr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct iphdr, saddr),
&cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr,
sizeof(struct in_addr), op);
}
if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP);
- add_addr(r, offsetof(struct iphdr, daddr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct iphdr, daddr),
&cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr,
sizeof(struct in_addr), op);
}
@@ -199,7 +201,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- cs->fw.ip.smsk.s_addr = 0xffffffff;
+ memset(&cs->fw.ip.smsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in_addr)));
}
if (inv)
@@ -212,7 +215,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- cs->fw.ip.dmsk.s_addr = 0xffffffff;
+ memset(&cs->fw.ip.dmsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in_addr)));
}
if (inv)
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index 4008b7ea..130ad3e6 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -51,7 +51,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_SRCIP);
- add_addr(r, offsetof(struct ip6_hdr, ip6_src),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct ip6_hdr, ip6_src),
&cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
sizeof(struct in6_addr), op);
}
@@ -59,7 +60,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_DSTIP);
- add_addr(r, offsetof(struct ip6_hdr, ip6_dst),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct ip6_hdr, ip6_dst),
&cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
sizeof(struct in6_addr), op);
}
@@ -146,7 +148,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&cs->fw6.ipv6.smsk, 0xff, sizeof(struct in6_addr));
+ memset(&cs->fw6.ipv6.smsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in6_addr)));
}
if (inv)
@@ -159,7 +162,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&cs->fw6.ipv6.dmsk, 0xff, sizeof(struct in6_addr));
+ memset(&cs->fw6.ipv6.dmsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in6_addr)));
}
if (inv)
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 7741d23b..10553ab2 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -20,7 +20,6 @@
#include <xtables.h>
-#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/xt_comment.h>
#include <linux/netfilter/xt_limit.h>
@@ -162,20 +161,26 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
add_cmp_ptr(r, op, iface, iface_len + 1);
}
-void add_addr(struct nftnl_rule *r, int offset,
+void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op)
{
const unsigned char *m = mask;
+ bool bitwise = false;
int i;
- add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
-
for (i = 0; i < len; i++) {
- if (m[i] != 0xff)
+ if (m[i] != 0xff) {
+ bitwise = m[i] != 0;
break;
+ }
}
- if (i != len)
+ if (!bitwise)
+ len = i;
+
+ add_payload(r, offset, len, base);
+
+ if (bitwise)
add_bitwise(r, mask, len);
add_cmp_ptr(r, op, data, len);
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 4440fd17..da4ba9d2 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -8,6 +8,7 @@
#include <libnftnl/chain.h>
#include <linux/netfilter_arp/arp_tables.h>
+#include <linux/netfilter/nf_tables.h>
#include "xshared.h"
@@ -121,7 +122,7 @@ void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op);
void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op);
void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op);
void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op);
-void add_addr(struct nftnl_rule *r, int offset,
+void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op);
void add_proto(struct nftnl_rule *r, int offset, size_t len,
uint8_t proto, uint32_t op);
@@ -247,4 +248,8 @@ void xtables_restore_parse(struct nft_handle *h,
const struct nft_xt_restore_parse *p);
void nft_check_xt_legacy(int family, bool is_ipt_save);
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
#endif
diff --git a/iptables/nft.c b/iptables/nft.c
index 39882a44..bde4ca72 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -688,7 +688,8 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
static void nft_chain_builtin_add(struct nft_handle *h,
const struct builtin_table *table,
- const struct builtin_chain *chain)
+ const struct builtin_chain *chain,
+ bool fake)
{
struct nftnl_chain *c;
@@ -696,8 +697,9 @@ static void nft_chain_builtin_add(struct nft_handle *h,
if (c == NULL)
return;
- batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
- nftnl_chain_list_add_tail(c, h->cache->table[table->type].chains);
+ if (!fake)
+ batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
+ nft_cache_add_chain(h, table, c);
}
/* find if built-in table already exists */
@@ -738,9 +740,6 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
return found ? &t->chains[i] : NULL;
}
-static struct nftnl_chain *
-nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
-
static void nft_chain_builtin_init(struct nft_handle *h,
const struct builtin_table *table)
{
@@ -751,29 +750,57 @@ static void nft_chain_builtin_init(struct nft_handle *h,
if (nft_chain_find(h, table->name, table->chains[i].name))
continue;
- nft_chain_builtin_add(h, table, &table->chains[i]);
+ nft_chain_builtin_add(h, table, &table->chains[i], false);
}
}
-static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
+static const struct builtin_table *
+nft_xt_builtin_table_init(struct nft_handle *h, const char *table)
{
const struct builtin_table *t;
if (!h->cache_init)
- return 0;
+ return NULL;
t = nft_table_builtin_find(h, table);
if (t == NULL)
- return -1;
+ return NULL;
if (nft_table_builtin_add(h, t) < 0)
+ return NULL;
+
+ return t;
+}
+
+static int nft_xt_builtin_init(struct nft_handle *h, const char *table,
+ const char *chain)
+{
+ const struct builtin_table *t;
+ const struct builtin_chain *c;
+
+ if (!h->cache_init)
+ return 0;
+
+ t = nft_xt_builtin_table_init(h, table);
+ if (!t)
return -1;
if (h->cache_req.level < NFT_CL_CHAINS)
return 0;
- nft_chain_builtin_init(h, t);
+ if (!chain) {
+ nft_chain_builtin_init(h, t);
+ return 0;
+ }
+
+ c = nft_chain_builtin_find(t, chain);
+ if (!c)
+ return -1;
+
+ if (h->cache->table[t->type].base_chains[c->hook])
+ return 0;
+ nft_chain_builtin_add(h, t, c, false);
return 0;
}
@@ -785,6 +812,40 @@ static bool nft_chain_builtin(struct nftnl_chain *c)
return nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) != NULL;
}
+static int __nft_xt_fake_builtin_chains(struct nft_handle *h,
+ const char *table, void *data)
+{
+ const char *chain = data ? *(const char **)data : NULL;
+ const struct builtin_table *t;
+ struct nft_chain **bcp;
+ int i;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return -1;
+
+ bcp = h->cache->table[t->type].base_chains;
+ for (i = 0; i < NF_INET_NUMHOOKS && t->chains[i].name; i++) {
+ if (bcp[t->chains[i].hook])
+ continue;
+
+ if (chain && strcmp(chain, t->chains[i].name))
+ continue;
+
+ nft_chain_builtin_add(h, t, &t->chains[i], true);
+ }
+ return 0;
+}
+
+int nft_xt_fake_builtin_chains(struct nft_handle *h,
+ const char *table, const char *chain)
+{
+ if (table)
+ return __nft_xt_fake_builtin_chains(h, table, &chain);
+
+ return nft_for_each_table(h, __nft_xt_fake_builtin_chains, &chain);
+}
+
int nft_restart(struct nft_handle *h)
{
mnl_socket_close(h->nl);
@@ -877,7 +938,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
}
/* if this built-in table does not exists, create it */
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table, chain);
_c = nft_chain_builtin_find(_t, chain);
if (_c != NULL) {
@@ -1391,10 +1452,10 @@ int
nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
{
- struct nftnl_chain *c;
+ struct nft_chain *c;
int type;
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table, chain);
nft_fn = nft_rule_append;
@@ -1421,7 +1482,7 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
errno = ENOENT;
return 0;
}
- nftnl_chain_rule_add_tail(r, c);
+ nftnl_chain_rule_add_tail(r, c->nftnl);
}
return 1;
@@ -1543,8 +1604,9 @@ static const char *policy_name[NF_ACCEPT+1] = {
[NF_ACCEPT] = "ACCEPT",
};
-int nft_chain_save(struct nftnl_chain *c, void *data)
+int nft_chain_save(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = data;
const char *policy = NULL;
@@ -1567,13 +1629,13 @@ struct nft_rule_save_data {
unsigned int format;
};
-static int nft_rule_save_cb(struct nftnl_chain *c, void *data)
+static int nft_rule_save_cb(struct nft_chain *c, void *data)
{
struct nft_rule_save_data *d = data;
struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
- iter = nftnl_rule_iter_create(c);
+ iter = nftnl_rule_iter_create(c->nftnl);
if (iter == NULL)
return 1;
@@ -1593,14 +1655,9 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
.h = h,
.format = format,
};
- struct nftnl_chain_list *list;
int ret;
- list = nft_chain_list_get(h, table, NULL);
- if (!list)
- return 0;
-
- ret = nftnl_chain_list_foreach(list, nft_rule_save_cb, &d);
+ ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d);
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1653,9 +1710,9 @@ struct nft_rule_flush_data {
bool verbose;
};
-static int nft_rule_flush_cb(struct nftnl_chain *c, void *data)
+static int nft_rule_flush_cb(struct nft_chain *c, void *data)
{
- const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ const char *chain = nftnl_chain_get_str(c->nftnl, NFTNL_CHAIN_NAME);
struct nft_rule_flush_data *d = data;
batch_chain_flush(d->h, d->table, chain);
@@ -1672,14 +1729,13 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
.table = table,
.verbose = verbose,
};
- struct nftnl_chain_list *list;
- struct nftnl_chain *c = NULL;
+ struct nft_chain *c = NULL;
int ret = 0;
nft_fn = nft_rule_flush;
if (chain || verbose)
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table, chain);
else if (!nft_table_find(h, table))
return 1;
@@ -1698,26 +1754,20 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
return 1;
}
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL) {
- ret = 1;
- goto err;
- }
+ ret = nft_chain_foreach(h, table, nft_rule_flush_cb, &d);
- ret = nftnl_chain_list_foreach(list, nft_rule_flush_cb, &d);
-err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
}
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table)
{
- struct nftnl_chain_list *list;
+ const struct builtin_table *t;
struct nftnl_chain *c;
nft_fn = nft_chain_user_add;
- nft_xt_builtin_init(h, table);
+ t = nft_xt_builtin_table_init(h, table);
if (nft_chain_exists(h, table, chain)) {
errno = EEXIST;
@@ -1736,9 +1786,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
return 0;
- list = nft_chain_list_get(h, table, chain);
- if (list)
- nftnl_chain_list_add(c, list);
+ nft_cache_add_chain(h, t, c);
/* the core expects 1 for success and 0 for error */
return 1;
@@ -1746,15 +1794,16 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
{
- struct nftnl_chain_list *list;
+ const struct builtin_table *t;
struct obj_update *obj;
struct nftnl_chain *c;
+ struct nft_chain *nc;
bool created = false;
- nft_xt_builtin_init(h, table);
+ t = nft_xt_builtin_table_init(h, table);
- c = nft_chain_find(h, table, chain);
- if (!c) {
+ nc = nft_chain_find(h, table, chain);
+ if (!nc) {
c = nftnl_chain_alloc();
if (!c)
return 0;
@@ -1763,10 +1812,10 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true;
- list = nft_chain_list_get(h, table, chain);
- if (list)
- nftnl_chain_list_add(c, list);
+ nft_cache_add_chain(h, t, c);
} else {
+ c = nc->nftnl;
+
/* If the chain should vanish meanwhile, kernel genid changes
* and the transaction is refreshed enabling the chain add
* object. With the handle still set, kernel interprets it as a
@@ -1798,9 +1847,10 @@ struct chain_user_del_data {
int builtin_err;
};
-static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
+static int __nft_chain_user_del(struct nft_chain *nc, void *data)
{
struct chain_user_del_data *d = data;
+ struct nftnl_chain *c = nc->nftnl;
struct nft_handle *h = d->handle;
/* don't delete built-in chain */
@@ -1811,12 +1861,17 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
fprintf(stdout, "Deleting chain `%s'\n",
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
+
/* XXX This triggers a fast lookup from the kernel. */
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
return -1;
- nftnl_chain_list_del(c);
+ /* nftnl_chain is freed when deleting the batch object */
+ nc->nftnl = NULL;
+
+ nft_chain_list_del(nc);
+ nft_chain_free(nc);
return 0;
}
@@ -1827,18 +1882,13 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
.handle = h,
.verbose = verbose,
};
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
+ struct nft_chain *c;
int ret = 0;
nft_fn = nft_chain_user_del;
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL)
- return 0;
-
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c) {
errno = ENOENT;
return 0;
@@ -1850,24 +1900,12 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain,
goto out;
}
- ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d);
+ ret = nft_chain_foreach(h, table, __nft_chain_user_del, &d);
out:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
}
-static struct nftnl_chain *
-nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
-{
- struct nftnl_chain_list *list;
-
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL)
- return NULL;
-
- return nftnl_chain_list_lookup_byname(list, chain);
-}
-
bool nft_chain_exists(struct nft_handle *h,
const char *table, const char *chain)
{
@@ -1887,6 +1925,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
const char *table, const char *newname)
{
struct nftnl_chain *c;
+ struct nft_chain *nc;
uint64_t handle;
nft_fn = nft_chain_user_rename;
@@ -1896,16 +1935,13 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0;
}
- /* Config load changed errno. Ensure genuine info for our callers. */
- errno = 0;
-
/* Find the old chain to be renamed */
- c = nft_chain_find(h, table, chain);
- if (c == NULL) {
+ nc = nft_chain_find(h, table, chain);
+ if (nc == NULL) {
errno = ENOENT;
return 0;
}
- handle = nftnl_chain_get_u64(c, NFTNL_CHAIN_HANDLE);
+ handle = nftnl_chain_get_u64(nc->nftnl, NFTNL_CHAIN_HANDLE);
/* Now prepare the new name for the chain */
c = nftnl_chain_alloc();
@@ -2054,9 +2090,10 @@ out:
}
static struct nftnl_rule *
-nft_rule_find(struct nft_handle *h, struct nftnl_chain *c,
+nft_rule_find(struct nft_handle *h, struct nft_chain *nc,
struct nftnl_rule *rule, int rulenum)
{
+ struct nftnl_chain *c = nc->nftnl;
struct nftnl_rule *r;
struct nftnl_rule_iter *iter;
bool found = false;
@@ -2085,8 +2122,8 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c,
int nft_rule_check(struct nft_handle *h, const char *chain,
const char *table, struct nftnl_rule *rule, bool verbose)
{
- struct nftnl_chain *c;
struct nftnl_rule *r;
+ struct nft_chain *c;
nft_fn = nft_rule_check;
@@ -2111,8 +2148,8 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
const char *table, struct nftnl_rule *rule, bool verbose)
{
int ret = 0;
- struct nftnl_chain *c;
struct nftnl_rule *r;
+ struct nft_chain *c;
nft_fn = nft_rule_delete;
@@ -2172,9 +2209,9 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
bool verbose)
{
struct nftnl_rule *r = NULL;
- struct nftnl_chain *c;
+ struct nft_chain *c;
- nft_xt_builtin_init(h, table);
+ nft_xt_builtin_init(h, table, chain);
nft_fn = nft_rule_insert;
@@ -2207,7 +2244,7 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
if (r)
nftnl_chain_rule_insert_at(new_rule, r);
else
- nftnl_chain_rule_add(new_rule, c);
+ nftnl_chain_rule_add(new_rule, c->nftnl);
return 1;
err:
@@ -2218,8 +2255,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
const char *table, int rulenum, bool verbose)
{
int ret = 0;
- struct nftnl_chain *c;
struct nftnl_rule *r;
+ struct nft_chain *c;
nft_fn = nft_rule_delete_num;
@@ -2246,8 +2283,8 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
int rulenum, bool verbose)
{
int ret = 0;
- struct nftnl_chain *c;
struct nftnl_rule *r;
+ struct nft_chain *c;
nft_fn = nft_rule_replace;
@@ -2326,8 +2363,9 @@ static int nft_rule_count(struct nft_handle *h, struct nftnl_chain *c)
}
static void __nft_print_header(struct nft_handle *h,
- struct nftnl_chain *c, unsigned int format)
+ struct nft_chain *nc, unsigned int format)
{
+ struct nftnl_chain *c = nc->nftnl;
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM);
uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
@@ -2355,7 +2393,7 @@ struct nft_rule_list_cb_data {
unsigned int num, unsigned int format);
};
-static int nft_rule_list_cb(struct nftnl_chain *c, void *data)
+static int nft_rule_list_cb(struct nft_chain *c, void *data)
{
struct nft_rule_list_cb_data *d = data;
@@ -2367,7 +2405,7 @@ static int nft_rule_list_cb(struct nftnl_chain *c, void *data)
__nft_print_header(d->h, c, d->format);
}
- return __nft_rule_list(d->h, c, d->rulenum, d->format, d->cb);
+ return __nft_rule_list(d->h, c->nftnl, d->rulenum, d->format, d->cb);
}
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
@@ -2380,10 +2418,9 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
.rulenum = rulenum,
.cb = ops->print_rule,
};
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
+ struct nft_chain *c;
- nft_xt_builtin_init(h, table);
+ nft_xt_fake_builtin_chains(h, table, chain);
nft_assert_table_compatible(h, table, chain);
if (chain) {
@@ -2400,14 +2437,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
return 1;
}
- list = nft_chain_list_get(h, table, chain);
- if (!list)
- return 0;
-
if (ops->print_table_header)
ops->print_table_header(table);
- nftnl_chain_list_foreach(list, nft_rule_list_cb, &d);
+ nft_chain_foreach(h, table, nft_rule_list_cb, &d);
return 1;
}
@@ -2418,8 +2451,44 @@ list_save(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
}
-static int nft_rule_list_chain_save(struct nftnl_chain *c, void *data)
+int nft_chain_foreach(struct nft_handle *h, const char *table,
+ int (*cb)(struct nft_chain *c, void *data),
+ void *data)
{
+ const struct builtin_table *t;
+ struct nft_chain_list *list;
+ struct nft_chain *c, *c_bak;
+ int i, ret;
+
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return -1;
+
+ for (i = 0; i < NF_INET_NUMHOOKS; i++) {
+ c = h->cache->table[t->type].base_chains[i];
+ if (!c)
+ continue;
+
+ ret = cb(c, data);
+ if (ret < 0)
+ return ret;
+ }
+
+ list = h->cache->table[t->type].chains;
+ if (!list)
+ return -1;
+
+ list_for_each_entry_safe(c, c_bak, &list->list, head) {
+ ret = cb(c, data);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int nft_rule_list_chain_save(struct nft_chain *nc, void *data)
+{
+ struct nftnl_chain *c = nc->nftnl;
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
int *counters = data;
@@ -2449,24 +2518,19 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
.save_fmt = true,
.cb = list_save,
};
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
+ struct nft_chain *c;
int ret = 0;
- nft_xt_builtin_init(h, table);
+ nft_xt_fake_builtin_chains(h, table, chain);
nft_assert_table_compatible(h, table, chain);
- list = nft_chain_list_get(h, table, chain);
- if (!list)
- return 0;
-
if (counters < 0)
d.format = FMT_C_COUNTS;
else if (counters == 0)
d.format = FMT_NOCOUNTS;
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c)
return 0;
@@ -2477,10 +2541,10 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
}
/* Dump policies and custom chains first */
- nftnl_chain_list_foreach(list, nft_rule_list_chain_save, &counters);
+ nft_chain_foreach(h, table, nft_rule_list_chain_save, &counters);
/* Now dump out rules in this table */
- ret = nftnl_chain_list_foreach(list, nft_rule_list_cb, &d);
+ ret = nft_chain_foreach(h, table, nft_rule_list_cb, &d);
return ret == 0 ? 1 : 0;
}
@@ -2489,7 +2553,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
{
struct iptables_command_state cs = {};
struct nftnl_rule *r, *new_rule;
- struct nftnl_chain *c;
+ struct nft_chain *c;
int ret = 0;
nft_fn = nft_rule_delete;
@@ -2631,7 +2695,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
static void nft_refresh_transaction(struct nft_handle *h)
{
const char *tablename, *chainname;
- const struct nftnl_chain *c;
+ const struct nft_chain *c;
struct obj_update *n, *tmp;
bool exists;
@@ -2928,7 +2992,7 @@ err_free_rule:
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy)
{
- struct nftnl_chain *c = nft_chain_find(h, table, chain);
+ struct nft_chain *c = nft_chain_find(h, table, chain);
int pval;
if (!c)
@@ -2943,14 +3007,15 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
else
return 0;
- nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval);
+ nftnl_chain_set_u32(c->nftnl, NFTNL_CHAIN_POLICY, pval);
return 1;
}
static void nft_bridge_commit_prepare(struct nft_handle *h)
{
const struct builtin_table *t;
- struct nftnl_chain_list *list;
+ struct nft_chain_list *list;
+ struct nft_chain *c;
int i;
for (i = 0; i < NFT_TABLE_MAX; i++) {
@@ -2963,7 +3028,9 @@ static void nft_bridge_commit_prepare(struct nft_handle *h)
if (!list)
continue;
- nftnl_chain_list_foreach(list, ebt_add_policy_rule, h);
+ list_for_each_entry(c, &list->list, head) {
+ ebt_add_policy_rule(c->nftnl, h);
+ }
}
}
@@ -3064,7 +3131,7 @@ static int nft_prepare(struct nft_handle *h)
cmd->chain, cmd->policy);
break;
case NFT_COMPAT_SET_ADD:
- nft_xt_builtin_init(h, cmd->table);
+ nft_xt_builtin_table_init(h, cmd->table);
batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set);
ret = 1;
break;
@@ -3271,8 +3338,9 @@ struct chain_zero_data {
bool verbose;
};
-static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
+static int __nft_chain_zero_counters(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
struct chain_zero_data *d = data;
struct nft_handle *h = d->handle;
struct nftnl_rule_iter *iter;
@@ -3280,7 +3348,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
if (d->verbose)
fprintf(stdout, "Zeroing chain `%s'\n",
- nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
+ nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
/* zero base chain counters. */
@@ -3345,20 +3413,15 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose)
{
- struct nftnl_chain_list *list;
struct chain_zero_data d = {
.handle = h,
.verbose = verbose,
};
- struct nftnl_chain *c;
+ struct nft_chain *c;
int ret = 0;
- list = nft_chain_list_get(h, table, chain);
- if (list == NULL)
- goto err;
-
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c) {
errno = ENOENT;
return 0;
@@ -3368,7 +3431,7 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
goto err;
}
- ret = nftnl_chain_list_foreach(list, __nft_chain_zero_counters, &d);
+ ret = nft_chain_foreach(h, table, __nft_chain_zero_counters, &d);
err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -3418,8 +3481,9 @@ static int nft_is_rule_compatible(struct nftnl_rule *rule, void *data)
return nftnl_expr_foreach(rule, nft_is_expr_compatible, NULL);
}
-static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
+static int nft_is_chain_compatible(struct nft_chain *nc, void *data)
{
+ struct nftnl_chain *c = nc->nftnl;
const struct builtin_table *table;
const struct builtin_chain *chain;
const char *tname, *cname, *type;
@@ -3457,16 +3521,13 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data)
bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain)
{
- struct nftnl_chain_list *clist;
-
- clist = nft_chain_list_get(h, table, chain);
- if (clist == NULL)
- return false;
+ if (chain) {
+ struct nft_chain *c = nft_chain_find(h, table, chain);
- if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h))
- return false;
+ return c && !nft_is_chain_compatible(c, h);
+ }
- return true;
+ return !nft_chain_foreach(h, table, nft_is_chain_compatible, h);
}
void nft_assert_table_compatible(struct nft_handle *h,
diff --git a/iptables/nft.h b/iptables/nft.h
index 128e09be..0910f82a 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -4,6 +4,7 @@
#include "xshared.h"
#include "nft-shared.h"
#include "nft-cache.h"
+#include "nft-chain.h"
#include "nft-cmd.h"
#include <libiptc/linux_list.h>
@@ -39,7 +40,8 @@ enum nft_cache_level {
struct nft_cache {
struct {
- struct nftnl_chain_list *chains;
+ struct nft_chain *base_chains[NF_INET_NUMHOOKS];
+ struct nft_chain_list *chains;
struct nftnl_set_list *sets;
bool exists;
} table[NFT_TABLE_MAX];
@@ -134,6 +136,7 @@ bool nft_table_find(struct nft_handle *h, const char *tablename);
int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list);
int nft_table_flush(struct nft_handle *h, const char *table);
const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table);
+int nft_xt_fake_builtin_chains(struct nft_handle *h, const char *table, const char *chain);
/*
* Operations with chains.
@@ -141,7 +144,7 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c
struct nftnl_chain;
int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters);
-int nft_chain_save(struct nftnl_chain *c, void *data);
+int nft_chain_save(struct nft_chain *c, void *data);
int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table);
int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose);
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table);
@@ -151,6 +154,9 @@ const struct builtin_chain *nft_chain_builtin_find(const struct builtin_table *t
bool nft_chain_exists(struct nft_handle *h, const char *table, const char *chain);
void nft_bridge_chain_postprocess(struct nft_handle *h,
struct nftnl_chain *c);
+int nft_chain_foreach(struct nft_handle *h, const char *table,
+ int (*cb)(struct nft_chain *c, void *data),
+ void *data);
/*
diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
index 0c1eb4ca..6f11bd12 100755
--- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
+++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
@@ -86,4 +86,8 @@ if [ $? -eq 0 ]; then
exit 1
fi
+$XT_MULTI ebtables -t filter -E FOO BAZ || exit 1
+$XT_MULTI ebtables -t filter -L | grep -q FOO && exit 1
+$XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
+
$XT_MULTI ebtables -t $t -F || exit 0
diff --git a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
index b84f63a7..ccdef19c 100755
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
@@ -70,8 +70,8 @@ DUMP='*filter
:INPUT ACCEPT
:FORWARD DROP
:OUTPUT ACCEPT
-:foo ACCEPT
:bar RETURN
+:foo ACCEPT
-A INPUT -p IPv4 -i lo -j ACCEPT
-A FORWARD -j foo
-A OUTPUT -s Broadcast -j DROP
diff --git a/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0 b/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
index 0174b03f..4900554e 100755
--- a/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
+++ b/iptables/tests/shell/testcases/firewalld-restore/0001-firewalld_0
@@ -230,21 +230,8 @@ for table in nat mangle raw filter;do
$XT_MULTI iptables-save -t $table | grep -v '^#' >> "$tmpfile"
done
-case "$XT_MULTI" in
-*xtables-nft-multi)
- # nft-multi displays chain names in different order, work around this for now
- tmpfile2=$(mktemp)
- sort "$tmpfile" > "$tmpfile2"
- sort $(dirname "$0")/dumps/ipt-save-completed.txt > "$tmpfile"
- diff -u $tmpfile $tmpfile2
- RET=$?
- rm -f "$tmpfile2"
- ;;
-*)
- diff -u $tmpfile $(dirname "$0")/dumps/ipt-save-completed.txt
- RET=$?
- ;;
-esac
+diff -u $tmpfile $(dirname "$0")/dumps/ipt-save-completed.txt
+RET=$?
rm -f "$tmpfile"
diff --git a/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0 b/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
index 029db223..e705b28c 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_0
@@ -18,7 +18,7 @@ EXPECT="*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -j ACCEPT
COMMIT"
-diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort)
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save | grep -v '^#')
$XT_MULTI iptables-restore <<EOF
*filter
@@ -39,4 +39,4 @@ COMMIT
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -j ACCEPT
COMMIT"
-diff -u -Z <(echo -e "$EXPECT" | sort) <($XT_MULTI iptables-save | grep -v '^#' | sort)
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
index 94bed0ec..fc8559c5 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
@@ -59,7 +59,7 @@ Flushing chain \`secfoo'
Deleting chain \`secfoo'"
for ipt in iptables-restore ip6tables-restore; do
- diff -u -Z <(sort <<< "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP" | sort)
+ diff -u -Z <(echo "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP")
done
DUMP="*filter
diff --git a/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0 b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0
new file mode 100755
index 00000000..cf73de32
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# A bug in extension registration would leave unsupported older extension
+# revisions in pending list and get compatibility checked again for each rule
+# using them. With SELinux enabled, the resulting socket() call per rule leads
+# to significant slowdown (~50% performance in worst cases).
+
+set -e
+
+strace --version >/dev/null || { echo "skip for missing strace"; exit 0; }
+
+RULESET="$(
+ echo "*filter"
+ for ((i = 0; i < 100; i++)); do
+ echo "-A FORWARD -m conntrack --ctstate NEW"
+ done
+ echo "COMMIT"
+)"
+
+cmd="$XT_MULTI iptables-restore"
+socketcount=$(strace -esocket $cmd <<< "$RULESET" 2>&1 | wc -l)
+
+# unpatched iptables-restore would open 111 sockets,
+# patched only 12 but keep a certain margin for future changes
+[[ $socketcount -lt 20 ]]
diff --git a/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt b/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt
index bfb6bdda..6e42de78 100644
--- a/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt
+++ b/iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt
@@ -40,8 +40,8 @@
-A OUTPUT -s 127.0.0.1/32 -d 127.0.0.1/32 -o lo -j ACCEPT
-A OUTPUT -o wlan0 -j wlanout
-A OUTPUT -j block
--A WLAN -s 192.168.200.4/32 -m mac --mac-source 00:00:F1:05:A0:E0 -j RETURN
--A WLAN -s 192.168.200.9/32 -m mac --mac-source 00:00:F1:05:99:85 -j RETURN
+-A WLAN -s 192.168.200.4/32 -m mac --mac-source 00:00:f1:05:a0:e0 -j RETURN
+-A WLAN -s 192.168.200.9/32 -m mac --mac-source 00:00:f1:05:99:85 -j RETURN
-A WLAN -m limit --limit 12/min -j LOG --log-prefix "UNKNOWN WLAN dropped:"
-A WLAN -j DROP
-A accept_log -i ppp0 -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 1/sec -j LOG --log-prefix "TCPConnect on ppp0:"
diff --git a/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
new file mode 100755
index 00000000..41588a10
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
@@ -0,0 +1,346 @@
+#!/bin/bash -x
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+set -e
+
+nft flush ruleset
+
+(
+ echo "*filter"
+ for plen in "" 32 30 24 16 8 0; do
+ addr="10.1.2.3${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ echo "COMMIT"
+) | $XT_MULTI iptables-restore
+
+(
+ echo "*filter"
+ for plen in "" 128 124 120 112 88 80 64 48 16 8 0; do
+ addr="feed:c0ff:ee00:0102:0304:0506:0708:090A${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ echo "COMMIT"
+) | $XT_MULTI ip6tables-restore
+
+masks="
+ff:ff:ff:ff:ff:ff
+ff:ff:ff:ff:ff:f0
+ff:ff:ff:ff:ff:00
+ff:ff:ff:ff:00:00
+ff:ff:ff:00:00:00
+ff:ff:00:00:00:00
+ff:00:00:00:00:00
+"
+(
+ echo "*filter"
+ for plen in "" 32 30 24 16 8 0; do
+ addr="10.1.2.3${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ for mask in $masks; do
+ echo "-A OUTPUT --destination-mac fe:ed:00:c0:ff:ee/$mask"
+ done
+ echo "COMMIT"
+) | $XT_MULTI arptables-restore
+
+(
+ echo "*filter"
+ for mask in $masks; do
+ echo "-A OUTPUT -d fe:ed:00:c0:ff:ee/$mask"
+ done
+ echo "COMMIT"
+) | $XT_MULTI ebtables-restore
+
+EXPECT="ip filter OUTPUT 4
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 5 4
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 6 5
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfcffffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 7 6
+ [ payload load 3b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 8 7
+ [ payload load 2b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0000010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 9 8
+ [ payload load 1b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 10 9
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 4
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 5 4
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 6 5
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffff 0xffffffff 0xffffffff 0xf0ffffff ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 7 6
+ [ payload load 15b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 8 7
+ [ payload load 14b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00000807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 9 8
+ [ payload load 11b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00050403 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 10 9
+ [ payload load 10b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00000403 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 11 10
+ [ payload load 8b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 12 11
+ [ payload load 6b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x000000ee ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 13 12
+ [ payload load 2b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 14 13
+ [ payload load 1b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 15 14
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 3
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 4 3
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 5 4
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfcffffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 6 5
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 3b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 7 6
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 2b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 8 7
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 1b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 9 8
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 10 9
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000eeff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 11 10
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 12 11
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 5b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x000000ff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 13 12
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 14 13
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 3b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 15 14
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 2b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 16 15
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 1b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 4
+ [ payload load 6b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000eeff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 5 4
+ [ payload load 6b @ link header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 6 5
+ [ payload load 5b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x000000ff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 7 6
+ [ payload load 4b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 8 7
+ [ payload load 3b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 9 8
+ [ payload load 2b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 10 9
+ [ payload load 1b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+"
+
+# print nothing but:
+# - lines with bytecode (starting with ' [')
+# - empty lines (so printed diff is not a complete mess)
+filter() {
+ awk '/^( \[|$)/{print}'
+}
+
+diff -u -Z <(filter <<< "$EXPECT") <(nft --debug=netlink list ruleset | filter)
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 7d97637f..71f68990 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -779,3 +779,77 @@ int parse_rulenumber(const char *rule)
return rulenum;
}
+
+/* Table of legal combinations of commands and options. If any of the
+ * given commands make an option legal, that option is legal (applies to
+ * CMD_LIST and CMD_ZERO only).
+ * Key:
+ * + compulsory
+ * x illegal
+ * optional
+ */
+static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
+/* Well, it's better than "Re: Linux vs FreeBSD" */
+{
+ /* -n -s -d -p -j -v -x -i -o --line -c -f 2 3 l 4 5 6 */
+/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
+/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x','x','x','x','x','x','x'},
+/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x','x','x','x','x','x','x'},
+/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
+};
+
+void generic_opt_check(int command, int options)
+{
+ int i, j, legal = 0;
+
+ /* Check that commands are valid with options. Complicated by the
+ * fact that if an option is legal with *any* command given, it is
+ * legal overall (ie. -z and -l).
+ */
+ for (i = 0; i < NUMBER_OF_OPT; i++) {
+ legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
+
+ for (j = 0; j < NUMBER_OF_CMD; j++) {
+ if (!(command & (1<<j)))
+ continue;
+
+ if (!(options & (1<<i))) {
+ if (commands_v_options[j][i] == '+')
+ xtables_error(PARAMETER_PROBLEM,
+ "You need to supply the `-%c' "
+ "option for this command\n",
+ optflags[i]);
+ } else {
+ if (commands_v_options[j][i] != 'x')
+ legal = 1;
+ else if (legal == 0)
+ legal = -1;
+ }
+ }
+ if (legal == -1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal option `-%c' with this command\n",
+ optflags[i]);
+ }
+}
+
+char opt2char(int option)
+{
+ const char *ptr;
+
+ for (ptr = optflags; option > 1; option >>= 1, ptr++)
+ ;
+
+ return *ptr;
+}
diff --git a/iptables/xshared.h b/iptables/xshared.h
index c41bd054..9159b2b1 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -30,15 +30,20 @@ enum {
OPT_VIANAMEOUT = 1 << 8,
OPT_LINENUMBERS = 1 << 9,
OPT_COUNTERS = 1 << 10,
+ OPT_FRAGMENT = 1 << 11,
/* below are for arptables only */
- OPT_S_MAC = 1 << 11,
- OPT_D_MAC = 1 << 12,
- OPT_H_LENGTH = 1 << 13,
- OPT_OPCODE = 1 << 14,
- OPT_H_TYPE = 1 << 15,
- OPT_P_TYPE = 1 << 16,
+ OPT_S_MAC = 1 << 12,
+ OPT_D_MAC = 1 << 13,
+ OPT_H_LENGTH = 1 << 14,
+ OPT_OPCODE = 1 << 15,
+ OPT_H_TYPE = 1 << 16,
+ OPT_P_TYPE = 1 << 17,
};
+#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
+static const char optflags[]
+= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f', 2, 3, 'l', 4, 5, 6 };
+
enum {
CMD_NONE = 0,
CMD_INSERT = 1 << 0,
@@ -216,4 +221,7 @@ void add_command(unsigned int *cmd, const int newcmd,
const int othercmds, int invert);
int parse_rulenumber(const char *rule);
+void generic_opt_check(int command, int options);
+char opt2char(int option);
+
#endif /* IPTABLES_XSHARED_H */
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 8632774d..4a89ae95 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -53,10 +53,6 @@
#include "nft-arp.h"
#include <linux/netfilter_arp/arp_tables.h>
-#define NUMBER_OF_OPT 16
-static const char optflags[NUMBER_OF_OPT]
-= { 'n', 's', 'd', 2, 3, 7, 8, 4, 5, 6, 'j', 'v', 'i', 'o', '0', 'c'};
-
static struct option original_opts[] = {
{ "append", 1, 0, 'A' },
{ "delete", 1, 0, 'D' },
@@ -113,74 +109,29 @@ struct xtables_globals arptables_globals = {
static int inverse_for_options[] =
{
/* -n */ 0,
-/* -s */ ARPT_INV_SRCIP,
-/* -d */ ARPT_INV_TGTIP,
+/* -s */ IPT_INV_SRCIP,
+/* -d */ IPT_INV_DSTIP,
/* -p */ 0,
/* -j */ 0,
/* -v */ 0,
/* -x */ 0,
-/* -i */ ARPT_INV_VIA_IN,
-/* -o */ ARPT_INV_VIA_OUT,
+/* -i */ IPT_INV_VIA_IN,
+/* -o */ IPT_INV_VIA_OUT,
/*--line*/ 0,
/* -c */ 0,
-/* 2 */ ARPT_INV_SRCDEVADDR,
-/* 3 */ ARPT_INV_TGTDEVADDR,
-/* -l */ ARPT_INV_ARPHLN,
-/* 4 */ ARPT_INV_ARPOP,
-/* 5 */ ARPT_INV_ARPHRD,
-/* 6 */ ARPT_INV_ARPPRO,
+/* -f */ 0,
+/* 2 */ IPT_INV_SRCDEVADDR,
+/* 3 */ IPT_INV_TGTDEVADDR,
+/* -l */ IPT_INV_ARPHLN,
+/* 4 */ IPT_INV_ARPOP,
+/* 5 */ IPT_INV_ARPHRD,
+/* 6 */ IPT_INV_PROTO,
};
/***********************************************/
/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
/***********************************************/
-static unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
-static unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
-static unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-static unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-static unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-static unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-
-/*
- * put the mac address into 6 (ETH_ALEN) bytes
- */
-static int getmac_and_mask(char *from, char *to, char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr;
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, mac_type_unicast, ETH_ALEN);
- memcpy(mask, msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, mac_type_multicast, ETH_ALEN);
- memcpy(mask, msk_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, mac_type_broadcast, ETH_ALEN);
- memcpy(mask, msk_type_broadcast, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
{
char *p, *buffer;
@@ -327,15 +278,6 @@ printhelp(void)
}
}
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
static int
check_inverse(const char option[], int *invert, int *optidx, int argc)
{
@@ -686,7 +628,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
check_inverse(optarg, &invert, &optind, argc);
set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags,
invert);
- if (getmac_and_mask(argv[optind - 1],
+ if (xtables_parse_mac_and_mask(argv[optind - 1],
cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"source mac");
@@ -697,7 +639,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags,
invert);
- if (getmac_and_mask(argv[optind - 1],
+ if (xtables_parse_mac_and_mask(argv[optind - 1],
cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask))
xtables_error(PARAMETER_PROBLEM, "Problem with specified "
"destination mac");
@@ -901,7 +843,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
&dmasks, &ndaddrs);
if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
+ (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
" source or destination IP addresses");
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
index 96b2730f..83ae77cb 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -397,7 +397,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_ISOURCE;
- if (ebt_get_mac_and_mask(optarg, cs.eb.sourcemac, cs.eb.sourcemsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.sourcemac,
+ cs.eb.sourcemsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
cs.eb.bitmask |= EBT_SOURCEMAC;
break;
@@ -406,7 +408,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_IDEST;
- if (ebt_get_mac_and_mask(optarg, cs.eb.destmac, cs.eb.destmsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.destmac,
+ cs.eb.destmsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
cs.eb.bitmask |= EBT_DESTMAC;
break;
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 6641a21a..cfa9317c 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -55,57 +55,6 @@
* 1: the inverse '!' of the option has already been specified */
int ebt_invert = 0;
-unsigned char eb_mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
-unsigned char eb_msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
-unsigned char eb_mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-unsigned char eb_msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
-unsigned char eb_mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-unsigned char eb_msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
-unsigned char eb_mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
-unsigned char eb_msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
-
-int ebt_get_mac_and_mask(const char *from, unsigned char *to,
- unsigned char *mask)
-{
- char *p;
- int i;
- struct ether_addr *addr = NULL;
-
- if (strcasecmp(from, "Unicast") == 0) {
- memcpy(to, eb_mac_type_unicast, ETH_ALEN);
- memcpy(mask, eb_msk_type_unicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Multicast") == 0) {
- memcpy(to, eb_mac_type_multicast, ETH_ALEN);
- memcpy(mask, eb_msk_type_multicast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "Broadcast") == 0) {
- memcpy(to, eb_mac_type_broadcast, ETH_ALEN);
- memcpy(mask, eb_msk_type_broadcast, ETH_ALEN);
- return 0;
- }
- if (strcasecmp(from, "BGA") == 0) {
- memcpy(to, eb_mac_type_bridge_group, ETH_ALEN);
- memcpy(mask, eb_msk_type_bridge_group, ETH_ALEN);
- return 0;
- }
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- if (!(addr = ether_aton(p + 1)))
- return -1;
- memcpy(mask, addr, ETH_ALEN);
- } else
- memset(mask, 0xff, ETH_ALEN);
- if (!(addr = ether_aton(from)))
- return -1;
- memcpy(to, addr, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++)
- to[i] &= mask[i];
- return 0;
-}
-
static int ebt_check_inverse2(const char option[], int argc, char **argv)
{
if (!option)
@@ -853,6 +802,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
else if (strchr(argv[optind], ' ') != NULL)
xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");
+ errno = 0;
ret = nft_cmd_chain_user_rename(h, chain, *table,
argv[optind]);
if (ret != 0 && errno == ENOENT)
@@ -1037,7 +987,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_ISOURCE;
- if (ebt_get_mac_and_mask(optarg, cs.eb.sourcemac, cs.eb.sourcemsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.sourcemac,
+ cs.eb.sourcemsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
cs.eb.bitmask |= EBT_SOURCEMAC;
break;
@@ -1046,7 +998,9 @@ print_zero:
if (ebt_check_inverse2(optarg, argc, argv))
cs.eb.invflags |= EBT_IDEST;
- if (ebt_get_mac_and_mask(optarg, cs.eb.destmac, cs.eb.destmsk))
+ if (xtables_parse_mac_and_mask(optarg,
+ cs.eb.destmac,
+ cs.eb.destmsk))
xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
cs.eb.bitmask |= EBT_DESTMAC;
break;
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 4008cc00..4b980980 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -106,6 +106,7 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
printf("-0 ");
break;
default:
+ puts("");
goto err_free;
}
@@ -227,12 +228,12 @@ static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args)
exit(EXIT_FAILURE);
}
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, NLM_F_DUMP, 0);
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, 0, 0);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
- nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
+ nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, handle);
nftnl_rule_nlmsg_build_payload(nlh, r);
nftnl_rule_free(r);
@@ -248,24 +249,21 @@ static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args)
}
portid = mnl_socket_get_portid(nl);
- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
- perror("mnl_socket_send");
- exit(EXIT_FAILURE);
- }
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_send");
+ exit(EXIT_FAILURE);
+ }
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- while (ret > 0) {
+ if (ret > 0) {
args->is_event = false;
- ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args);
- if (ret <= 0)
- break;
- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- }
- if (ret == -1) {
- perror("error");
- exit(EXIT_FAILURE);
- }
- mnl_socket_close(nl);
+ ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args);
+ }
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+ mnl_socket_close(nl);
}
static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *args)
@@ -276,14 +274,14 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
uint32_t mark;
char name[IFNAMSIZ];
- printf("PACKET: %d %08x ", args->nfproto, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
+ family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
+ printf("PACKET: %d %08x ", family, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
printf("IN=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_IIF), name));
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
printf("OUT=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_OIF), name));
- family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
nfproto = family;
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) {
nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO);
@@ -308,6 +306,9 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
printf("MACDST=%s ", ether_ntoa((const void *)eh->h_dest));
printf("MACPROTO=%04x ", ntohs(eh->h_proto));
break;
+ case ARPHRD_LOOPBACK:
+ printf("LOOPBACK ");
+ break;
default:
printf("LL=0x%x ", type);
for (i = 0 ; i < len; i++)
@@ -436,9 +437,18 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
mark = nftnl_trace_get_u32(nlt, NFTNL_TRACE_MARK);
if (mark)
printf("MARK=0x%x ", mark);
+ puts("");
+}
+
+static void trace_print_hdr(const struct nftnl_trace *nlt)
+{
+ printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY),
+ nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE),
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
}
-static void print_verdict(struct nftnl_trace *nlt, uint32_t verdict)
+static void print_verdict(const struct nftnl_trace *nlt, uint32_t verdict)
{
const char *chain;
@@ -499,38 +509,41 @@ static int trace_cb(const struct nlmsghdr *nlh, struct cb_arg *arg)
arg->nfproto != nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY))
goto err_free;
- printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY),
- nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
- nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE),
- nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
-
switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) {
case NFT_TRACETYPE_RULE:
verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT);
- printf(":rule:0x%llx:", (unsigned long long)nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE));
- print_verdict(nlt, verdict);
- if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE))
- trace_print_rule(nlt, arg);
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
trace_print_packet(nlt, arg);
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) {
+ trace_print_hdr(nlt);
+ printf(":rule:0x%" PRIx64":", nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE));
+ print_verdict(nlt, verdict);
+ printf(" ");
+ trace_print_rule(nlt, arg);
+ }
break;
case NFT_TRACETYPE_POLICY:
+ trace_print_hdr(nlt);
printf(":policy:");
verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY);
print_verdict(nlt, verdict);
+ puts("");
break;
case NFT_TRACETYPE_RETURN:
+ trace_print_hdr(nlt);
printf(":return:");
trace_print_return(nlt);
+ puts("");
break;
}
- puts("");
err_free:
nftnl_trace_free(nlt);
err:
+ fflush(stdout);
return MNL_CB_OK;
}
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 92b0c911..d7901c65 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -68,7 +68,6 @@ struct do_output_data {
static int
__do_output(struct nft_handle *h, const char *tablename, void *data)
{
- struct nftnl_chain_list *chain_list;
struct do_output_data *d = data;
time_t now;
@@ -81,10 +80,6 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
return 0;
}
- chain_list = nft_chain_list_get(h, tablename, NULL);
- if (!chain_list)
- return 0;
-
now = time(NULL);
printf("# Generated by %s v%s on %s", prog_name,
prog_vers, ctime(&now));
@@ -92,7 +87,7 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
printf("*%s\n", tablename);
/* Dump out chain names first,
* thereby preventing dependency conflicts */
- nftnl_chain_list_foreach(chain_list, nft_chain_save, h);
+ nft_chain_foreach(h, tablename, nft_chain_save, h);
nft_rule_save(h, tablename, d->format);
if (d->commit)
printf("COMMIT\n");
@@ -241,6 +236,7 @@ xtables_save_main(int family, int argc, char *argv[],
nft_cache_level_set(&h, NFT_CL_RULES, NULL);
nft_cache_build(&h);
+ nft_xt_fake_builtin_chains(&h, tablename, NULL);
ret = do_output(&h, tablename, &d);
nft_fini(&h);
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 9d2e441e..9779bd83 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -43,11 +43,6 @@
#include "nft-shared.h"
#include "nft.h"
-#define OPT_FRAGMENT 0x00800U
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
-
static struct option original_opts[] = {
{.name = "append", .has_arg = 1, .val = 'A'},
{.name = "delete", .has_arg = 1, .val = 'D'},
@@ -99,36 +94,6 @@ struct xtables_globals xtables_globals = {
.compat_rev = nft_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c -f */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-};
-
static const int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -262,51 +227,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 66b333b0..9d309e33 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -2139,6 +2139,79 @@ void xtables_print_num(uint64_t number, unsigned int format)
printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
}
+#include <netinet/ether.h>
+
+static const unsigned char mac_type_unicast[ETH_ALEN] = {};
+static const unsigned char msk_type_unicast[ETH_ALEN] = {1};
+static const unsigned char mac_type_multicast[ETH_ALEN] = {1};
+static const unsigned char msk_type_multicast[ETH_ALEN] = {1};
+#define ALL_ONE_MAC {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+static const unsigned char mac_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
+static const unsigned char msk_type_broadcast[ETH_ALEN] = ALL_ONE_MAC;
+static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01, 0x80, 0xc2};
+static const unsigned char msk_type_bridge_group[ETH_ALEN] = ALL_ONE_MAC;
+#undef ALL_ONE_MAC
+
+int xtables_parse_mac_and_mask(const char *from, void *to, void *mask)
+{
+ char *p;
+ int i;
+ struct ether_addr *addr = NULL;
+
+ if (strcasecmp(from, "Unicast") == 0) {
+ memcpy(to, mac_type_unicast, ETH_ALEN);
+ memcpy(mask, msk_type_unicast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "Multicast") == 0) {
+ memcpy(to, mac_type_multicast, ETH_ALEN);
+ memcpy(mask, msk_type_multicast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "Broadcast") == 0) {
+ memcpy(to, mac_type_broadcast, ETH_ALEN);
+ memcpy(mask, msk_type_broadcast, ETH_ALEN);
+ return 0;
+ }
+ if (strcasecmp(from, "BGA") == 0) {
+ memcpy(to, mac_type_bridge_group, ETH_ALEN);
+ memcpy(mask, msk_type_bridge_group, ETH_ALEN);
+ return 0;
+ }
+ if ( (p = strrchr(from, '/')) != NULL) {
+ *p = '\0';
+ if (!(addr = ether_aton(p + 1)))
+ return -1;
+ memcpy(mask, addr, ETH_ALEN);
+ } else
+ memset(mask, 0xff, ETH_ALEN);
+ if (!(addr = ether_aton(from)))
+ return -1;
+ memcpy(to, addr, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++)
+ ((char *)to)[i] &= ((char *)mask)[i];
+ return 0;
+}
+
+int xtables_print_well_known_mac_and_mask(const void *mac, const void *mask)
+{
+ if (!memcmp(mac, mac_type_unicast, ETH_ALEN) &&
+ !memcmp(mask, msk_type_unicast, ETH_ALEN))
+ printf("Unicast");
+ else if (!memcmp(mac, mac_type_multicast, ETH_ALEN) &&
+ !memcmp(mask, msk_type_multicast, ETH_ALEN))
+ printf("Multicast");
+ else if (!memcmp(mac, mac_type_broadcast, ETH_ALEN) &&
+ !memcmp(mask, msk_type_broadcast, ETH_ALEN))
+ printf("Broadcast");
+ else if (!memcmp(mac, mac_type_bridge_group, ETH_ALEN) &&
+ !memcmp(mask, msk_type_bridge_group, ETH_ALEN))
+ printf("BGA");
+ else
+ return -1;
+ return 0;
+}
+
void xtables_print_mac(const unsigned char *macaddress)
{
unsigned int i;