summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore16
-rw-r--r--INCOMPATIBILITIES14
-rw-r--r--Makefile.am8
-rw-r--r--configure.ac30
-rw-r--r--etc/xtables.conf74
-rw-r--r--extensions/GNUmakefile.in205
-rw-r--r--extensions/dscp_helper.c4
-rw-r--r--extensions/generic.txlate120
-rw-r--r--extensions/libarpt_mangle.c189
-rw-r--r--extensions/libarpt_mangle.t4
-rw-r--r--extensions/libarpt_mangle.txlate6
-rw-r--r--extensions/libarpt_standard.t9
-rw-r--r--extensions/libebt_802_3.c93
-rw-r--r--extensions/libebt_802_3.t8
-rw-r--r--extensions/libebt_among.c50
-rw-r--r--extensions/libebt_among.t12
-rw-r--r--extensions/libebt_arp.c357
-rw-r--r--extensions/libebt_arp.t18
-rw-r--r--extensions/libebt_arpreply.c52
-rw-r--r--extensions/libebt_arpreply.t4
-rw-r--r--extensions/libebt_dnat.c64
-rw-r--r--extensions/libebt_dnat.txlate12
-rw-r--r--extensions/libebt_ip.c503
-rw-r--r--extensions/libebt_ip.t26
-rw-r--r--extensions/libebt_ip.txlate24
-rw-r--r--extensions/libebt_ip6.c404
-rw-r--r--extensions/libebt_ip6.t26
-rw-r--r--extensions/libebt_ip6.txlate22
-rw-r--r--extensions/libebt_limit.txlate6
-rw-r--r--extensions/libebt_log.c139
-rw-r--r--extensions/libebt_log.t6
-rw-r--r--extensions/libebt_log.txlate10
-rw-r--r--extensions/libebt_mark.c142
-rw-r--r--extensions/libebt_mark.txlate11
-rw-r--r--extensions/libebt_mark.xlate11
-rw-r--r--extensions/libebt_mark_m.c73
-rw-r--r--extensions/libebt_mark_m.t4
-rw-r--r--extensions/libebt_mark_m.txlate12
-rw-r--r--extensions/libebt_nflog.c91
-rw-r--r--extensions/libebt_nflog.t2
-rw-r--r--extensions/libebt_nflog.txlate8
-rw-r--r--extensions/libebt_pkttype.c49
-rw-r--r--extensions/libebt_pkttype.t14
-rw-r--r--extensions/libebt_pkttype.txlate14
-rw-r--r--extensions/libebt_redirect.c46
-rw-r--r--extensions/libebt_redirect.t2
-rw-r--r--extensions/libebt_redirect.txlate8
-rw-r--r--extensions/libebt_snat.c74
-rw-r--r--extensions/libebt_snat.t2
-rw-r--r--extensions/libebt_snat.txlate8
-rw-r--r--extensions/libebt_standard.t12
-rw-r--r--extensions/libebt_stp.c319
-rw-r--r--extensions/libebt_stp.t63
-rw-r--r--extensions/libebt_vlan.c121
-rw-r--r--extensions/libebt_vlan.t12
-rw-r--r--extensions/libebt_vlan.txlate10
-rw-r--r--extensions/libip6t_DNAT.c411
-rw-r--r--extensions/libip6t_DNAT.t4
-rw-r--r--extensions/libip6t_DNAT.txlate11
-rw-r--r--extensions/libip6t_DNPT.man4
-rw-r--r--extensions/libip6t_LOG.c250
-rw-r--r--extensions/libip6t_LOG.txlate6
-rw-r--r--extensions/libip6t_MASQUERADE.c188
-rw-r--r--extensions/libip6t_MASQUERADE.txlate15
-rw-r--r--extensions/libip6t_NETMAP.t2
-rw-r--r--extensions/libip6t_REDIRECT.c170
-rw-r--r--extensions/libip6t_REDIRECT.t6
-rw-r--r--extensions/libip6t_REDIRECT.txlate5
-rw-r--r--extensions/libip6t_REJECT.man7
-rw-r--r--extensions/libip6t_REJECT.t2
-rw-r--r--extensions/libip6t_REJECT.txlate6
-rw-r--r--extensions/libip6t_SNAT.c317
-rw-r--r--extensions/libip6t_SNAT.t6
-rw-r--r--extensions/libip6t_SNAT.txlate8
-rw-r--r--extensions/libip6t_SNPT.man4
-rw-r--r--extensions/libip6t_ah.c22
-rw-r--r--extensions/libip6t_ah.t6
-rw-r--r--extensions/libip6t_ah.txlate18
-rw-r--r--extensions/libip6t_dst.c14
-rw-r--r--extensions/libip6t_frag.c57
-rw-r--r--extensions/libip6t_frag.t6
-rw-r--r--extensions/libip6t_frag.txlate18
-rw-r--r--extensions/libip6t_hbh.c7
-rw-r--r--extensions/libip6t_hbh.txlate4
-rw-r--r--extensions/libip6t_hl.txlate4
-rw-r--r--extensions/libip6t_icmp6.c97
-rw-r--r--extensions/libip6t_icmp6.t4
-rw-r--r--extensions/libip6t_icmp6.txlate6
-rw-r--r--extensions/libip6t_ipv6header.c2
-rw-r--r--extensions/libip6t_mh.c24
-rw-r--r--extensions/libip6t_mh.t6
-rw-r--r--extensions/libip6t_mh.txlate13
-rw-r--r--extensions/libip6t_rt.c40
-rw-r--r--extensions/libip6t_rt.t6
-rw-r--r--extensions/libip6t_rt.txlate19
-rw-r--r--extensions/libip6t_standard.t3
-rw-r--r--extensions/libipt_CLUSTERIP.c10
-rw-r--r--extensions/libipt_CLUSTERIP.t4
-rw-r--r--extensions/libipt_DNAT.c555
-rw-r--r--extensions/libipt_DNAT.t4
-rw-r--r--extensions/libipt_DNAT.txlate14
-rw-r--r--extensions/libipt_LOG.c250
-rw-r--r--extensions/libipt_LOG.txlate4
-rw-r--r--extensions/libipt_MASQUERADE.c190
-rw-r--r--extensions/libipt_MASQUERADE.txlate15
-rw-r--r--extensions/libipt_NETMAP.t2
-rw-r--r--extensions/libipt_REDIRECT.c174
-rw-r--r--extensions/libipt_REDIRECT.t6
-rw-r--r--extensions/libipt_REDIRECT.txlate5
-rw-r--r--extensions/libipt_REJECT.man7
-rw-r--r--extensions/libipt_REJECT.t2
-rw-r--r--extensions/libipt_REJECT.txlate6
-rw-r--r--extensions/libipt_SNAT.c325
-rw-r--r--extensions/libipt_SNAT.t6
-rw-r--r--extensions/libipt_SNAT.txlate10
-rw-r--r--extensions/libipt_ULOG.man4
-rw-r--r--extensions/libipt_ah.c22
-rw-r--r--extensions/libipt_ah.t6
-rw-r--r--extensions/libipt_ah.txlate12
-rw-r--r--extensions/libipt_icmp.c113
-rw-r--r--extensions/libipt_icmp.t11
-rw-r--r--extensions/libipt_icmp.txlate8
-rw-r--r--extensions/libipt_realm.txlate8
-rw-r--r--extensions/libipt_ttl.c4
-rw-r--r--extensions/libipt_ttl.txlate4
-rw-r--r--extensions/libxt_AUDIT.txlate6
-rw-r--r--extensions/libxt_CLASSIFY.txlate6
-rw-r--r--extensions/libxt_CONNMARK.c15
-rw-r--r--extensions/libxt_CONNMARK.man4
-rw-r--r--extensions/libxt_CONNMARK.t8
-rw-r--r--extensions/libxt_CONNMARK.txlate17
-rw-r--r--extensions/libxt_CONNSECMARK.c3
-rw-r--r--extensions/libxt_CT.c2
-rw-r--r--extensions/libxt_CT.man4
-rw-r--r--extensions/libxt_DNAT.man17
-rw-r--r--extensions/libxt_DNAT.txlate35
-rw-r--r--extensions/libxt_DSCP.t2
-rw-r--r--extensions/libxt_DSCP.txlate4
-rw-r--r--extensions/libxt_HMARK.c60
-rw-r--r--extensions/libxt_HMARK.man2
-rw-r--r--extensions/libxt_IDLETIMER.t2
-rw-r--r--extensions/libxt_LED.man4
-rw-r--r--extensions/libxt_LOG.c204
-rw-r--r--extensions/libxt_LOG.man3
-rw-r--r--extensions/libxt_MARK.c87
-rw-r--r--extensions/libxt_MARK.t4
-rw-r--r--extensions/libxt_MARK.txlate27
-rw-r--r--extensions/libxt_MASQUERADE.man16
-rw-r--r--extensions/libxt_NAT.c646
-rw-r--r--extensions/libxt_NFLOG.c22
-rw-r--r--extensions/libxt_NFLOG.man4
-rw-r--r--extensions/libxt_NFLOG.t12
-rw-r--r--extensions/libxt_NFLOG.txlate10
-rw-r--r--extensions/libxt_NFQUEUE.c2
-rw-r--r--extensions/libxt_NFQUEUE.man13
-rw-r--r--extensions/libxt_NFQUEUE.t14
-rw-r--r--extensions/libxt_NFQUEUE.txlate6
-rw-r--r--extensions/libxt_NOTRACK.txlate2
-rw-r--r--extensions/libxt_REDIRECT.man5
-rw-r--r--extensions/libxt_REDIRECT.t17
-rw-r--r--extensions/libxt_REDIRECT.txlate29
-rw-r--r--extensions/libxt_SECMARK.c90
-rw-r--r--extensions/libxt_SECMARK.t4
-rw-r--r--extensions/libxt_SET.man4
-rw-r--r--extensions/libxt_SNAT.man16
-rw-r--r--extensions/libxt_SYNPROXY.man4
-rw-r--r--extensions/libxt_SYNPROXY.txlate2
-rw-r--r--extensions/libxt_TCPMSS.c1
-rw-r--r--extensions/libxt_TCPMSS.t2
-rw-r--r--extensions/libxt_TCPMSS.txlate4
-rw-r--r--extensions/libxt_TCPOPTSTRIP.c13
-rw-r--r--extensions/libxt_TEE.txlate8
-rw-r--r--extensions/libxt_TOS.c33
-rw-r--r--extensions/libxt_TOS.man2
-rw-r--r--extensions/libxt_TOS.t12
-rw-r--r--extensions/libxt_TOS.txlate19
-rw-r--r--extensions/libxt_TPROXY.c59
-rw-r--r--extensions/libxt_TPROXY.txlate20
-rw-r--r--extensions/libxt_TRACE.man4
-rw-r--r--extensions/libxt_TRACE.txlate2
-rw-r--r--extensions/libxt_addrtype.txlate8
-rw-r--r--extensions/libxt_bpf.c3
-rw-r--r--extensions/libxt_bpf.man8
-rw-r--r--extensions/libxt_cgroup.man2
-rw-r--r--extensions/libxt_cgroup.txlate4
-rw-r--r--extensions/libxt_cluster.man8
-rw-r--r--extensions/libxt_cluster.txlate18
-rw-r--r--extensions/libxt_comment.c7
-rw-r--r--extensions/libxt_comment.txlate6
-rw-r--r--extensions/libxt_connbytes.c4
-rw-r--r--extensions/libxt_connbytes.t6
-rw-r--r--extensions/libxt_connbytes.txlate10
-rw-r--r--extensions/libxt_connlabel.man10
-rw-r--r--extensions/libxt_connlabel.txlate4
-rw-r--r--extensions/libxt_connlimit.c49
-rw-r--r--extensions/libxt_connlimit.man31
-rw-r--r--extensions/libxt_connlimit.t12
-rw-r--r--extensions/libxt_connlimit.txlate15
-rw-r--r--extensions/libxt_connmark.t4
-rw-r--r--extensions/libxt_connmark.txlate10
-rw-r--r--extensions/libxt_conntrack.c62
-rw-r--r--extensions/libxt_conntrack.t28
-rw-r--r--extensions/libxt_conntrack.txlate43
-rw-r--r--extensions/libxt_cpu.man6
-rw-r--r--extensions/libxt_cpu.txlate4
-rw-r--r--extensions/libxt_dccp.c57
-rw-r--r--extensions/libxt_dccp.t10
-rw-r--r--extensions/libxt_dccp.txlate18
-rw-r--r--extensions/libxt_devgroup.c4
-rw-r--r--extensions/libxt_devgroup.man2
-rw-r--r--extensions/libxt_devgroup.txlate12
-rw-r--r--extensions/libxt_dscp.man2
-rw-r--r--extensions/libxt_dscp.t2
-rw-r--r--extensions/libxt_dscp.txlate4
-rw-r--r--extensions/libxt_ecn.c2
-rw-r--r--extensions/libxt_ecn.txlate20
-rw-r--r--extensions/libxt_esp.c26
-rw-r--r--extensions/libxt_esp.t7
-rw-r--r--extensions/libxt_esp.txlate20
-rw-r--r--extensions/libxt_hashlimit.c15
-rw-r--r--extensions/libxt_hashlimit.man6
-rw-r--r--extensions/libxt_hashlimit.t6
-rw-r--r--extensions/libxt_hashlimit.txlate4
-rw-r--r--extensions/libxt_helper.c8
-rw-r--r--extensions/libxt_helper.man10
-rw-r--r--extensions/libxt_helper.txlate4
-rw-r--r--extensions/libxt_icmp.h249
-rw-r--r--extensions/libxt_ipcomp.c9
-rw-r--r--extensions/libxt_ipcomp.c.man3
-rw-r--r--extensions/libxt_ipcomp.t7
-rw-r--r--extensions/libxt_ipcomp.txlate4
-rw-r--r--extensions/libxt_iprange.c16
-rw-r--r--extensions/libxt_iprange.txlate10
-rw-r--r--extensions/libxt_length.t5
-rw-r--r--extensions/libxt_length.txlate8
-rw-r--r--extensions/libxt_limit.c54
-rw-r--r--extensions/libxt_limit.man2
-rw-r--r--extensions/libxt_limit.txlate6
-rw-r--r--extensions/libxt_mac.c19
-rw-r--r--extensions/libxt_mac.txlate4
-rw-r--r--extensions/libxt_mark.t3
-rw-r--r--extensions/libxt_mark.txlate4
-rw-r--r--extensions/libxt_multiport.c50
-rw-r--r--extensions/libxt_multiport.txlate11
-rw-r--r--extensions/libxt_nfacct.man4
-rw-r--r--extensions/libxt_osf.man40
-rw-r--r--extensions/libxt_owner.man2
-rw-r--r--extensions/libxt_owner.txlate6
-rw-r--r--extensions/libxt_pkttype.c2
-rw-r--r--extensions/libxt_pkttype.txlate6
-rw-r--r--extensions/libxt_policy.txlate4
-rw-r--r--extensions/libxt_quota.txlate4
-rw-r--r--extensions/libxt_rateest.man16
-rw-r--r--extensions/libxt_recent.t4
-rw-r--r--extensions/libxt_rpfilter.txlate6
-rw-r--r--extensions/libxt_sctp.c116
-rw-r--r--extensions/libxt_sctp.man15
-rw-r--r--extensions/libxt_sctp.t4
-rw-r--r--extensions/libxt_sctp.txlate32
-rw-r--r--extensions/libxt_set.c65
-rw-r--r--extensions/libxt_set.h17
-rw-r--r--extensions/libxt_socket.c34
-rw-r--r--extensions/libxt_socket.man2
-rw-r--r--extensions/libxt_socket.txlate17
-rw-r--r--extensions/libxt_standard.t17
-rw-r--r--extensions/libxt_statistic.c8
-rw-r--r--extensions/libxt_statistic.txlate6
-rw-r--r--extensions/libxt_string.c17
-rw-r--r--extensions/libxt_string.man20
-rw-r--r--extensions/libxt_string.t21
-rw-r--r--extensions/libxt_tcp.c79
-rw-r--r--extensions/libxt_tcp.t15
-rw-r--r--extensions/libxt_tcp.txlate30
-rw-r--r--extensions/libxt_tcpmss.c16
-rw-r--r--extensions/libxt_tcpmss.t4
-rw-r--r--extensions/libxt_tcpmss.txlate11
-rw-r--r--extensions/libxt_time.c12
-rw-r--r--extensions/libxt_time.man2
-rw-r--r--extensions/libxt_time.txlate18
-rw-r--r--extensions/libxt_tos.t8
-rw-r--r--extensions/libxt_u32.man16
-rw-r--r--extensions/libxt_udp.c49
-rw-r--r--extensions/libxt_udp.t15
-rw-r--r--extensions/libxt_udp.txlate14
-rw-r--r--include/Makefile.am8
-rw-r--r--include/libipq/libipq.h8
-rw-r--r--include/libiptc/libxtc.h2
-rw-r--r--include/libipulog/libipulog.h39
-rw-r--r--include/linux/const.h36
-rw-r--r--include/linux/kernel.h29
-rw-r--r--include/linux/netfilter/nf_log.h15
-rw-r--r--include/linux/netfilter/nf_tables.h542
-rw-r--r--include/linux/netfilter/xt_LOG.h20
-rw-r--r--include/linux/netfilter/xt_SECMARK.h6
-rw-r--r--include/linux/netfilter_arp/arpt_mangle.h2
-rw-r--r--include/linux/netfilter_bridge/ebt_ip.h15
-rw-r--r--include/linux/netfilter_ipv4/ipt_LOG.h19
-rw-r--r--include/linux/netfilter_ipv6/ip6t_LOG.h19
-rw-r--r--include/linux/sysinfo.h25
-rw-r--r--include/xtables.h94
-rwxr-xr-xiptables-test.py465
-rw-r--r--iptables/.gitignore5
-rw-r--r--iptables/Makefile.am110
-rw-r--r--iptables/arptables-nft-restore.84
-rw-r--r--iptables/arptables-nft-save.82
-rw-r--r--iptables/arptables-nft.8156
-rw-r--r--iptables/ebtables-nft.8244
-rw-r--r--iptables/ip6tables-apply.81
-rw-r--r--iptables/ip6tables-restore.81
-rw-r--r--iptables/ip6tables-save.81
-rw-r--r--iptables/ip6tables-standalone.c3
-rw-r--r--iptables/ip6tables.81
-rw-r--r--iptables/ip6tables.c1043
-rwxr-xr-xiptables/iptables-apply17
-rw-r--r--iptables/iptables-apply.8.in4
-rw-r--r--iptables/iptables-restore.8.in33
-rw-r--r--iptables/iptables-restore.c86
-rw-r--r--iptables/iptables-save.8.in18
-rw-r--r--iptables/iptables-save.c11
-rw-r--r--iptables/iptables-standalone.c2
-rw-r--r--iptables/iptables-xml.c30
-rw-r--r--iptables/iptables.8.in74
-rw-r--r--iptables/iptables.c1039
-rw-r--r--iptables/nft-arp.c869
-rw-r--r--iptables/nft-arp.h7
-rw-r--r--iptables/nft-bridge.c706
-rw-r--r--iptables/nft-bridge.h14
-rw-r--r--iptables/nft-cache.c300
-rw-r--r--iptables/nft-cache.h14
-rw-r--r--iptables/nft-chain.c59
-rw-r--r--iptables/nft-chain.h30
-rw-r--r--iptables/nft-cmd.c68
-rw-r--r--iptables/nft-cmd.h14
-rw-r--r--iptables/nft-ipv4.c471
-rw-r--r--iptables/nft-ipv6.c417
-rw-r--r--iptables/nft-ruleparse-arp.c174
-rw-r--r--iptables/nft-ruleparse-bridge.c422
-rw-r--r--iptables/nft-ruleparse-ipv4.c133
-rw-r--r--iptables/nft-ruleparse-ipv6.c110
-rw-r--r--iptables/nft-ruleparse.c1177
-rw-r--r--iptables/nft-ruleparse.h136
-rw-r--r--iptables/nft-shared.c817
-rw-r--r--iptables/nft-shared.h195
-rw-r--r--iptables/nft.c1157
-rw-r--r--iptables/nft.h41
-rwxr-xr-xiptables/tests/shell/run-tests.sh9
-rwxr-xr-xiptables/tests/shell/testcases/chain/0003rename_040
-rwxr-xr-xiptables/tests/shell/testcases/chain/0003rename_112
-rwxr-xr-xiptables/tests/shell/testcases/chain/0004extra-base_037
-rwxr-xr-xiptables/tests/shell/testcases/chain/0005base-delete_034
-rwxr-xr-xiptables/tests/shell/testcases/chain/0006rename-segfault_019
-rwxr-xr-xiptables/tests/shell/testcases/chain/0007counters_078
-rwxr-xr-xiptables/tests/shell/testcases/chain/0008rename-segfault2_032
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0001-ebtables-basic_04
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_022
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_02
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0006-flush_047
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0007-chain-policies_041
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0008-ebtables-among_0106
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0009-broute-bug_025
-rwxr-xr-xiptables/tests/shell/testcases/ebtables/0010-change-counters_045
-rwxr-xr-xiptables/tests/shell/testcases/firewalld-restore/0001-firewalld_017
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0002-verbose-output_023
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0003-list-rules_06
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0004-address-masks_024
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0005-rule-check_017
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0002-parameters_03
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_016
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0007-flush-noflush_04
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0008-restore-counters_07
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_09
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_025
-rwxr-xr-xiptables/tests/shell/testcases/ipt-save/0001load-dumps_01
-rwxr-xr-xiptables/tests/shell/testcases/ipt-save/0006iptables-xml_010
-rwxr-xr-xiptables/tests/shell/testcases/ipt-save/0007-overhead_037
-rw-r--r--iptables/tests/shell/testcases/ipt-save/dumps/ipt-save-filter.txt4
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0002-verbose-output_011
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0003-list-rules_06
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_03
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0007-zero-counters_079
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0008-unprivileged_066
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0009-unknown-arg_031
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0010-wait_055
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_010
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0009-needless-bitwise_09
-rw-r--r--iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt26
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0010-native-delinearize_09
-rw-r--r--iptables/tests/shell/testcases/nft-only/0010-nft-native.txt41
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0011-zero-needs-compat_012
-rw-r--r--iptables/xshared.c1588
-rw-r--r--iptables/xshared.h215
-rw-r--r--iptables/xtables-arp-standalone.c65
-rw-r--r--iptables/xtables-arp.c929
-rw-r--r--iptables/xtables-eb-translate.c540
-rw-r--r--iptables/xtables-eb.c1129
-rw-r--r--iptables/xtables-legacy-multi.c4
-rw-r--r--iptables/xtables-monitor.8.in8
-rw-r--r--iptables/xtables-monitor.c85
-rw-r--r--iptables/xtables-multi.h5
-rw-r--r--iptables/xtables-nft-multi.c1
-rw-r--r--iptables/xtables-nft.816
-rw-r--r--iptables/xtables-restore.c87
-rw-r--r--iptables/xtables-save.c31
-rw-r--r--iptables/xtables-standalone.c57
-rw-r--r--iptables/xtables-translate.849
-rw-r--r--iptables/xtables-translate.c140
-rw-r--r--iptables/xtables.c959
-rw-r--r--libipq/Makefile.am3
-rw-r--r--libipq/ipq_create_handle.32
-rw-r--r--libipq/ipq_set_mode.32
-rw-r--r--libiptc/Makefile.am3
-rw-r--r--libiptc/libiptc.c27
-rw-r--r--libiptc/linux_stddef.h39
-rw-r--r--libxtables/Makefile.am3
-rw-r--r--libxtables/xtables.c430
-rw-r--r--libxtables/xtoptions.c176
-rw-r--r--utils/.gitignore1
-rw-r--r--utils/Makefile.am11
-rw-r--r--utils/nfbpf_compile.8.in2
-rw-r--r--utils/nfbpf_compile.c10
-rw-r--r--utils/nfnl_osf.8.in4
-rwxr-xr-xxlate-test.py263
422 files changed, 14655 insertions, 15557 deletions
diff --git a/.gitignore b/.gitignore
index e5595264..ec4e44ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,8 @@
*.a
+*.gcda
+*.gcno
+*.gcno.gcov.json.gz
+*.gcov
*.la
*.lo
*.so
@@ -16,6 +20,7 @@ Makefile.in
/build-aux/
/config.*
/configure
+/configure~
/libtool
/stamp-h1
/iptables/iptables-apply.8
@@ -25,3 +30,14 @@ Makefile.in
# vim/nano swap file
*.swp
+
+/tags
+
+# make check results
+/test-suite.log
+/iptables-test.py.log
+/iptables-test.py.trs
+/xlate-test.py.log
+/xlate-test.py.trs
+iptables/tests/shell/run-tests.sh.log
+iptables/tests/shell/run-tests.sh.trs
diff --git a/INCOMPATIBILITIES b/INCOMPATIBILITIES
deleted file mode 100644
index ddb24087..00000000
--- a/INCOMPATIBILITIES
+++ /dev/null
@@ -1,14 +0,0 @@
-INCOMPATIBILITIES:
-
-- The REJECT target has an '--reject-with admin-prohib' option which used
- with kernels that do not support it, will result in a plain DROP instead
- of REJECT. Use with caution.
- Kernels that do support it:
- 2.4 - since 2.4.22-pre9
- 2.6 - all
-
-- There are some issues related to upgrading from 1.2.x to 1.3.x on a system
- with dynamic ruleset changes during runtime. (Please see
- https://bugzilla.netfilter.org/bugzilla/show_bug.cgi?id=334).
- After upgrading from 1.2 to 1.3, it suggest go do an iptables-save, then
- iptables-restore to ensure your dynamic rule changes continue to work.
diff --git a/Makefile.am b/Makefile.am
index 799bf8b8..299ab46d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
# -*- Makefile -*-
ACLOCAL_AMFLAGS = -I m4
-AUTOMAKE_OPTIONS = foreign subdir-objects
+AUTOMAKE_OPTIONS = foreign subdir-objects dist-xz no-dist-gzip
SUBDIRS = libiptc libxtables
if ENABLE_DEVEL
@@ -16,6 +16,8 @@ SUBDIRS += extensions
# Depends on extensions/libext.a:
SUBDIRS += iptables
+EXTRA_DIST = autogen.sh iptables-test.py xlate-test.py
+
if ENABLE_NFTABLES
confdir = $(sysconfdir)
dist_conf_DATA = etc/ethertypes
@@ -26,8 +28,10 @@ tarball:
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
pushd ${top_srcdir} && git archive --prefix=${PACKAGE_TARNAME}-${PACKAGE_VERSION}/ HEAD | tar -C /tmp -x && popd;
pushd /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION} && ./autogen.sh && popd;
- tar -C /tmp -cjf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/;
+ tar -C /tmp -cJf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.xz --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/;
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
config.status: extensions/GNUmakefile.in \
include/xtables-version.h.in
+
+TESTS = xlate-test.py iptables-test.py iptables/tests/shell/run-tests.sh
diff --git a/configure.ac b/configure.ac
index 357c5116..d99fa3b9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
-AC_INIT([iptables], [1.8.6])
+AC_INIT([iptables], [1.8.10])
# See libtool.info "Libtool's versioning system"
-libxtables_vcurrent=15
-libxtables_vage=3
+libxtables_vcurrent=19
+libxtables_vage=7
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
@@ -12,9 +12,8 @@ AC_PROG_INSTALL
AM_INIT_AUTOMAKE([-Wall])
AC_PROG_CC
AM_PROG_CC_C_O
-AC_DISABLE_STATIC
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
-AM_PROG_LIBTOOL
+LT_INIT([disable-static])
AC_ARG_WITH([kernel],
AS_HELP_STRING([--with-kernel=PATH],
@@ -72,6 +71,9 @@ AC_ARG_WITH([xt-lock-name], AS_HELP_STRING([--with-xt-lock-name=PATH],
[Path to the xtables lock [[/run/xtables.lock]]]),
[xt_lock_name="$withval"],
[xt_lock_name="/run/xtables.lock"])
+AC_ARG_ENABLE([profiling],
+ AS_HELP_STRING([--enable-profiling], [build for use of gcov/gprof]),
+ [enable_profiling="$enableval"], [enable_profiling="no"])
AC_MSG_CHECKING([whether $LD knows -Wl,--no-undefined])
saved_LDFLAGS="$LDFLAGS";
@@ -111,14 +113,15 @@ AM_CONDITIONAL([ENABLE_SYNCONF], [test "$enable_nfsynproxy" = "yes"])
AM_CONDITIONAL([ENABLE_NFTABLES], [test "$enable_nftables" = "yes"])
AM_CONDITIONAL([ENABLE_CONNLABEL], [test "$enable_connlabel" = "yes"])
-if test "x$enable_bpfc" = "xyes" || test "x$enable_nfsynproxy" = "xyes"; then
- AC_CHECK_LIB(pcap, pcap_compile,, AC_MSG_ERROR(missing libpcap library required by bpf compiler or nfsynproxy tool))
-fi
-
PKG_CHECK_MODULES([libnfnetlink], [libnfnetlink >= 1.0],
[nfnetlink=1], [nfnetlink=0])
AM_CONDITIONAL([HAVE_LIBNFNETLINK], [test "$nfnetlink" = 1])
+if test "x$enable_bpfc" = "xyes" || test "x$enable_nfsynproxy" = "xyes"; then
+ PKG_CHECK_MODULES([libpcap], [libpcap], [], [
+ AC_MSG_ERROR(missing libpcap library required by bpf compiler or nfsynproxy tool)])
+fi
+
if test "x$enable_nftables" = "xyes"; then
PKG_CHECK_MODULES([libmnl], [libmnl >= 1.0], [mnl=1], [mnl=0])
@@ -131,7 +134,7 @@ if test "x$enable_nftables" = "xyes"; then
exit 1
fi
- PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.1.6], [nftables=1], [nftables=0])
+ PKG_CHECK_MODULES([libnftnl], [libnftnl >= 1.2.6], [nftables=1], [nftables=0])
if test "$nftables" = 0;
then
@@ -189,6 +192,11 @@ if [[ -n "$ksourcedir" ]]; then
fi;
pkgdatadir='${datadir}/xtables';
+if test "x$enable_profiling" = "xyes"; then
+ regular_CFLAGS+=" -fprofile-arcs -ftest-coverage"
+ regular_LDFLAGS+=" -lgcov --coverage"
+fi
+
define([EXPAND_VARIABLE],
[$2=[$]$1
if test $prefix = 'NONE'; then
@@ -206,6 +214,7 @@ eval "$2=[$]$2"
AC_SUBST([regular_CFLAGS])
AC_SUBST([regular_CPPFLAGS])
AC_SUBST([noundef_LDFLAGS])
+AC_SUBST([regular_LDFLAGS])
AC_SUBST([kinclude_CPPFLAGS])
AC_SUBST([kbuilddir])
AC_SUBST([ksourcedir])
@@ -251,6 +260,7 @@ Iptables Configuration:
nfsynproxy util support: ${enable_nfsynproxy}
nftables support: ${enable_nftables}
connlabel support: ${enable_connlabel}
+ profiling support: ${enable_profiling}
Build parameters:
Put plugins into executable (static): ${enable_static}
diff --git a/etc/xtables.conf b/etc/xtables.conf
deleted file mode 100644
index 3c54ced0..00000000
--- a/etc/xtables.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-family ipv4 {
- table raw {
- chain PREROUTING hook NF_INET_PRE_ROUTING prio -300
- chain OUTPUT hook NF_INET_LOCAL_OUT prio -300
- }
-
- table mangle {
- chain PREROUTING hook NF_INET_PRE_ROUTING prio -150
- chain INPUT hook NF_INET_LOCAL_IN prio -150
- chain FORWARD hook NF_INET_FORWARD prio -150
- chain OUTPUT hook NF_INET_LOCAL_OUT prio -150
- chain POSTROUTING hook NF_INET_POST_ROUTING prio -150
- }
-
- table filter {
- chain INPUT hook NF_INET_LOCAL_IN prio 0
- chain FORWARD hook NF_INET_FORWARD prio 0
- chain OUTPUT hook NF_INET_LOCAL_OUT prio 0
- }
-
- table nat {
- chain PREROUTING hook NF_INET_PRE_ROUTING prio -100
- chain INPUT hook NF_INET_LOCAL_IN prio 100
- chain OUTPUT hook NF_INET_LOCAL_OUT prio -100
- chain POSTROUTING hook NF_INET_POST_ROUTING prio 100
- }
-
- table security {
- chain INPUT hook NF_INET_LOCAL_IN prio 50
- chain FORWARD hook NF_INET_FORWARD prio 50
- chain OUTPUT hook NF_INET_LOCAL_OUT prio 50
- }
-}
-
-family ipv6 {
- table raw {
- chain PREROUTING hook NF_INET_PRE_ROUTING prio -300
- chain OUTPUT hook NF_INET_LOCAL_OUT prio -300
- }
-
- table mangle {
- chain PREROUTING hook NF_INET_PRE_ROUTING prio -150
- chain INPUT hook NF_INET_LOCAL_IN prio -150
- chain FORWARD hook NF_INET_FORWARD prio -150
- chain OUTPUT hook NF_INET_LOCAL_OUT prio -150
- chain POSTROUTING hook NF_INET_POST_ROUTING prio -150
- }
-
- table filter {
- chain INPUT hook NF_INET_LOCAL_IN prio 0
- chain FORWARD hook NF_INET_FORWARD prio 0
- chain OUTPUT hook NF_INET_LOCAL_OUT prio 0
- }
-
- table nat {
- chain PREROUTING hook NF_INET_PRE_ROUTING prio -100
- chain INPUT hook NF_INET_LOCAL_IN prio 100
- chain OUTPUT hook NF_INET_LOCAL_OUT prio -100
- chain POSTROUTING hook NF_INET_POST_ROUTING prio 100
- }
-
- table security {
- chain INPUT hook NF_INET_LOCAL_IN prio 50
- chain FORWARD hook NF_INET_FORWARD prio 50
- chain OUTPUT hook NF_INET_LOCAL_OUT prio 50
- }
-}
-
-family arp {
- table filter {
- chain INPUT hook NF_ARP_IN prio 0
- chain OUTPUT hook NF_ARP_OUT prio 0
- }
-}
diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in
index 956ccb38..20c2b7bc 100644
--- a/extensions/GNUmakefile.in
+++ b/extensions/GNUmakefile.in
@@ -22,19 +22,34 @@ regular_CPPFLAGS = @regular_CPPFLAGS@
kinclude_CPPFLAGS = @kinclude_CPPFLAGS@
AM_CFLAGS = ${regular_CFLAGS}
-AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_builddir} -I${top_srcdir}/include -I${top_srcdir} ${kinclude_CPPFLAGS} ${CPPFLAGS} @libnetfilter_conntrack_CFLAGS@ @libnftnl_CFLAGS@
+AM_CPPFLAGS = ${regular_CPPFLAGS} \
+ -I${top_builddir}/include \
+ -I${top_builddir} \
+ -I${top_srcdir}/include \
+ -I${top_srcdir} \
+ ${kinclude_CPPFLAGS} \
+ ${CPPFLAGS} \
+ @libnetfilter_conntrack_CFLAGS@ \
+ @libnftnl_CFLAGS@
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
-AM_LDFLAGS = @noundef_LDFLAGS@
-
-ifeq (${V},)
-AM_LIBTOOL_SILENT = --silent
-AM_VERBOSE_CC = @echo " CC " $@;
-AM_VERBOSE_CCLD = @echo " CCLD " $@;
-AM_VERBOSE_CXX = @echo " CXX " $@;
-AM_VERBOSE_CXXLD = @echo " CXXLD " $@;
-AM_VERBOSE_AR = @echo " AR " $@;
-AM_VERBOSE_GEN = @echo " GEN " $@;
-endif
+AM_LDFLAGS = @noundef_LDFLAGS@ @regular_LDFLAGS@
+
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+am__v_AR_0 = @echo " AR " $@;
+am__v_CC_0 = @echo " CC " $@;
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_LN_0 = @echo " LN " $@;
+am__v_AR_ = ${am__v_AR_@AM_DEFAULT_V@}
+am__v_CC_ = ${am__v_CC_@AM_DEFAULT_V@}
+am__v_CCLD_ = ${am__v_CCLD_@AM_DEFAULT_V@}
+am__v_GEN_ = ${am__v_GEN_@AM_DEFAULT_V@}
+am__v_LN_ = ${am__v_LN_@AM_DEFAULT_V@}
+AM_V_AR = ${am__v_AR_@AM_V@}
+AM_V_CC = ${am__v_CC_@AM_V@}
+AM_V_CCLD = ${am__v_CCLD_@AM_V@}
+AM_V_GEN = ${am__v_GEN_@AM_V@}
+AM_V_LN = ${am__v_LN_@AM_V@}
#
# Wildcard module list
@@ -42,7 +57,7 @@ endif
pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c)))
@ENABLE_NFTABLES_TRUE@ pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c)))
@ENABLE_NFTABLES_TRUE@ pfa_build_mod := $(patsubst ${srcdir}/libarpt_%.c,%,$(sort $(wildcard ${srcdir}/libarpt_*.c)))
-pfx_symlinks := NOTRACK state
+pfx_symlinks := NOTRACK state REDIRECT MASQUERADE SNAT DNAT
@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c)))
@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c)))
pfx_build_mod := $(filter-out @blacklist_modules@ @blacklist_x_modules@,${pfx_build_mod})
@@ -79,7 +94,7 @@ targets_install :=
.SECONDARY:
-.PHONY: all install uninstall clean distclean FORCE
+.PHONY: all install uninstall clean distclean FORCE dvi check installcheck
all: ${targets}
@@ -106,13 +121,14 @@ uninstall:
}
clean:
- rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c;
+ rm -f *.o *.oo *.so *.a matches.man targets.man
+ rm -f initext.c initext4.c initext6.c initextb.c initexta.c
rm -f .*.d .*.dd;
distclean: clean
init%.o: init%.c
- ${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init ${CFLAGS} -o $@ -c $<;
+ ${AM_V_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init ${CFLAGS} -o $@ -c $<;
-include .*.d
@@ -121,15 +137,23 @@ init%.o: init%.c
# Shared libraries
#
lib%.so: lib%.oo
- ${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} ${LDFLAGS} -shared -o $@ $< -L../libxtables/.libs -lxtables ${$*_LIBADD};
+ ${AM_V_CCLD} ${CCLD} ${AM_LDFLAGS} ${LDFLAGS} -shared -o $@ $< -L../libxtables/.libs -lxtables ${$*_LIBADD};
lib%.oo: ${srcdir}/lib%.c
- ${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
+ ${AM_V_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
libxt_NOTRACK.so: libxt_CT.so
- ln -fs $< $@
+ ${AM_V_LN} ln -fs $< $@
libxt_state.so: libxt_conntrack.so
- ln -fs $< $@
+ ${AM_V_LN} ln -fs $< $@
+libxt_REDIRECT.so: libxt_NAT.so
+ ${AM_V_LN} ln -fs $< $@
+libxt_MASQUERADE.so: libxt_NAT.so
+ ${AM_V_LN} ln -fs $< $@
+libxt_SNAT.so: libxt_NAT.so
+ ${AM_V_LN} ln -fs $< $@
+libxt_DNAT.so: libxt_NAT.so
+ ${AM_V_LN} ln -fs $< $@
# Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD
xt_RATEEST_LIBADD = -lm
@@ -144,22 +168,22 @@ xt_connlabel_LIBADD = @libnetfilter_conntrack_LIBS@
# handling code in the Makefiles.
#
lib%.o: ${srcdir}/lib%.c
- ${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<;
+ ${AM_V_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<;
libext.a: initext.o ${libext_objs}
- ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+ ${AM_V_AR} ${AR} crs $@ $^;
libext_ebt.a: initextb.o ${libext_ebt_objs}
- ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+ ${AM_V_AR} ${AR} crs $@ $^;
libext_arpt.a: initexta.o ${libext_arpt_objs}
- ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+ ${AM_V_AR} ${AR} crs $@ $^;
libext4.a: initext4.o ${libext4_objs}
- ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+ ${AM_V_AR} ${AR} crs $@ $^;
libext6.a: initext6.o ${libext6_objs}
- ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+ ${AM_V_AR} ${AR} crs $@ $^;
initext_func := $(addprefix xt_,${pfx_build_mod})
initextb_func := $(addprefix ebt_,${pfb_build_mod})
@@ -167,141 +191,76 @@ initexta_func := $(addprefix arpt_,${pfa_build_mod})
initext4_func := $(addprefix ipt_,${pf4_build_mod})
initext6_func := $(addprefix ip6t_,${pf6_build_mod})
-.initext.dd: FORCE
- @echo "${initext_func}" >$@.tmp; \
- cmp -s $@ $@.tmp || mv $@.tmp $@; \
- rm -f $@.tmp;
-
-.initextb.dd: FORCE
- @echo "${initextb_func}" >$@.tmp; \
- cmp -s $@ $@.tmp || mv $@.tmp $@; \
- rm -f $@.tmp;
-
-.initexta.dd: FORCE
- @echo "${initexta_func}" >$@.tmp; \
- cmp -s $@ $@.tmp || mv $@.tmp $@; \
- rm -f $@.tmp;
-
-.initext4.dd: FORCE
- @echo "${initext4_func}" >$@.tmp; \
- cmp -s $@ $@.tmp || mv $@.tmp $@; \
- rm -f $@.tmp;
+initexts := ext exta extb ext4 ext6
+initext_depfiles = $(patsubst %,.init%.dd,${initexts})
+initext_sources = $(patsubst %,init%.c,${initexts})
-.initext6.dd: FORCE
- @echo "${initext6_func}" >$@.tmp; \
+${initext_depfiles}: FORCE
+ @echo "$(value $(patsubst .%.dd,%,$@)_func)" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
-initext.c: .initext.dd
- ${AM_VERBOSE_GEN}
+${initext_sources}: %.c: .%.dd
+ ${AM_V_GEN}
@( \
+ initext_func="$(value $(basename $@)_func)"; \
+ funcname="init_extensions$(patsubst initext%.c,%,$@)"; \
echo "" >$@; \
- for i in ${initext_func}; do \
+ for i in $${initext_func}; do \
echo "extern void lib$${i}_init(void);" >>$@; \
done; \
- echo "void init_extensions(void);" >>$@; \
- echo "void init_extensions(void)" >>$@; \
+ echo "void $${funcname}(void);" >>$@; \
+ echo "void $${funcname}(void)" >>$@; \
echo "{" >>$@; \
- for i in ${initext_func}; do \
+ for i in $${initext_func}; do \
echo " ""lib$${i}_init();" >>$@; \
done; \
echo "}" >>$@; \
);
-initextb.c: .initextb.dd
- ${AM_VERBOSE_GEN}
- @( \
- echo "" >$@; \
- for i in ${initextb_func}; do \
- echo "extern void lib$${i}_init(void);" >>$@; \
- done; \
- echo "void init_extensionsb(void);" >>$@; \
- echo "void init_extensionsb(void)" >>$@; \
- echo "{" >>$@; \
- for i in ${initextb_func}; do \
- echo " ""lib$${i}_init();" >>$@; \
- done; \
- echo "}" >>$@; \
- );
-
-initexta.c: .initexta.dd
- ${AM_VERBOSE_GEN}
- @( \
- echo "" >$@; \
- for i in ${initexta_func}; do \
- echo "extern void lib$${i}_init(void);" >>$@; \
- done; \
- echo "void init_extensionsa(void);" >>$@; \
- echo "void init_extensionsa(void)" >>$@; \
- echo "{" >>$@; \
- for i in ${initexta_func}; do \
- echo " ""lib$${i}_init();" >>$@; \
- done; \
- echo "}" >>$@; \
- );
-
-initext4.c: .initext4.dd
- ${AM_VERBOSE_GEN}
- @( \
- echo "" >$@; \
- for i in ${initext4_func}; do \
- echo "extern void lib$${i}_init(void);" >>$@; \
- done; \
- echo "void init_extensions4(void);" >>$@; \
- echo "void init_extensions4(void)" >>$@; \
- echo "{" >>$@; \
- for i in ${initext4_func}; do \
- echo " ""lib$${i}_init();" >>$@; \
- done; \
- echo "}" >>$@; \
- );
-
-initext6.c: .initext6.dd
- ${AM_VERBOSE_GEN}
- @( \
- echo "" >$@; \
- for i in ${initext6_func}; do \
- echo "extern void lib$${i}_init(void);" >>$@; \
- done; \
- echo "void init_extensions6(void);" >>$@; \
- echo "void init_extensions6(void)" >>$@; \
- echo "{" >>$@; \
- for i in ${initext6_func}; do \
- echo " ""lib$${i}_init();" >>$@; \
- done; \
- echo "}" >>$@; \
- );
-
#
# Manual pages
#
ex_matches = $(shell echo ${1} | LC_ALL=POSIX grep -Eo '\b[[:lower:][:digit:]_]+\b')
ex_targets = $(shell echo ${1} | LC_ALL=POSIX grep -Eo '\b[[:upper:][:digit:]_]+\b')
man_run = \
- ${AM_VERBOSE_GEN} \
+ ${AM_V_GEN} \
for ext in $(sort ${1}); do \
f="${srcdir}/libxt_$$ext.man"; \
if [ -f "$$f" ]; then \
- echo -e "\t+ $$f" >&2; \
+ printf "\t+ $$f\n" >&2; \
echo ".SS $$ext"; \
cat "$$f" || exit $$?; \
fi; \
f="${srcdir}/libip6t_$$ext.man"; \
if [ -f "$$f" ]; then \
- echo -e "\t+ $$f" >&2; \
+ printf "\t+ $$f\n" >&2; \
echo ".SS $$ext (IPv6-specific)"; \
cat "$$f" || exit $$?; \
fi; \
f="${srcdir}/libipt_$$ext.man"; \
if [ -f "$$f" ]; then \
- echo -e "\t+ $$f" >&2; \
+ printf "\t+ $$f\n" >&2; \
echo ".SS $$ext (IPv4-specific)"; \
cat "$$f" || exit $$?; \
fi; \
done >$@;
-matches.man: .initext.dd .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
+matches.man: ${initext_depfiles} $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_matches,${pfx_build_mod} ${pfb_build_mod} ${pfa_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
-targets.man: .initext.dd .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
+targets.man: ${initext_depfiles} $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_targets,${pfx_build_mod} ${pfb_build_mod} ${pfa_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
+
+dist_initext_src = $(addprefix $(srcdir)/,${initext_sources})
+dist_sources = $(filter-out ${dist_initext_src},$(wildcard $(srcdir)/*.[ch]))
+
+distdir:
+ mkdir -p $(distdir)
+ cp -p ${dist_sources} $(distdir)/
+ cp -p $(wildcard ${srcdir}/lib*.man) $(distdir)/
+ cp -p $(wildcard ${srcdir}/*.t ${srcdir}/*.txlate) $(distdir)/
+
+dvi:
+check: all
+installcheck:
diff --git a/extensions/dscp_helper.c b/extensions/dscp_helper.c
index 75b1fece..1f20b2a5 100644
--- a/extensions/dscp_helper.c
+++ b/extensions/dscp_helper.c
@@ -58,7 +58,7 @@ class_to_dscp(const char *name)
}
xtables_error(PARAMETER_PROBLEM,
- "Invalid DSCP value `%s'\n", name);
+ "Invalid DSCP value `%s'", name);
}
@@ -73,7 +73,7 @@ dscp_to_name(unsigned int dscp)
return ds_classes[i].name;
xtables_error(PARAMETER_PROBLEM,
- "Invalid DSCP value `%d'\n", dscp);
+ "Invalid DSCP value `%d'", dscp);
}
#endif
diff --git a/extensions/generic.txlate b/extensions/generic.txlate
index 0e256c37..9ad1266d 100644
--- a/extensions/generic.txlate
+++ b/extensions/generic.txlate
@@ -1,36 +1,126 @@
+arptables-translate -A OUTPUT --proto-type ipv4 -s 1.2.3.4 -j ACCEPT
+nft 'add rule arp filter OUTPUT arp htype 1 arp hlen 6 arp plen 4 arp ptype 0x800 arp saddr ip 1.2.3.4 counter accept'
+
+arptables-translate -I OUTPUT -o oifname
+nft 'insert rule arp filter OUTPUT oifname "oifname" arp htype 1 arp hlen 6 arp plen 4 counter'
+
iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT
-nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept
+nft 'insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept'
iptables-translate -F -t nat
nft flush table ip nat
iptables-translate -I INPUT -i iifname -s 10.0.0.0/8
-nft insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter
+nft 'insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter'
iptables-translate -A INPUT -i iif+ ! -d 10.0.0.0/8
-nft add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter
+nft 'add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter'
+
+iptables-translate -I INPUT -s 10.11.12.13/255.255.0.0
+nft 'insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter'
+
+iptables-translate -I INPUT -s 10.11.12.13/255.0.255.0
+nft 'insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter'
+
+iptables-translate -I INPUT -s 10.11.12.13/0.255.0.255
+nft 'insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter'
+
+iptables-translate -I INPUT ! -s 10.11.12.13/0.255.0.255
+nft 'insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter'
+
+iptables-translate -I INPUT -s 0.0.0.0/16
+nft 'insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter'
+
+iptables-translate -I INPUT -s 0.0.0.0/0
+nft 'insert rule ip filter INPUT counter'
+
+iptables-translate -I INPUT ! -s 0.0.0.0/0
+nft 'insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter'
+
+ip6tables-translate -I INPUT -i iifname -s feed::/16
+nft 'insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter'
+
+ip6tables-translate -A INPUT -i iif+ ! -d feed::/16
+nft 'add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter'
+
+ip6tables-translate -I INPUT -s feed:babe::1/ffff:ff00::
+nft 'insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter'
+
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/ffff:0:ffff:0:ffff:0:ffff:0
+nft 'insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter'
+
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
+nft 'insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter'
+
+ip6tables-translate -I INPUT ! -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
+nft 'insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter'
+
+ip6tables-translate -I INPUT -s ::/16
+nft 'insert rule ip6 filter INPUT ip6 saddr ::/16 counter'
+
+ip6tables-translate -I INPUT -s ::/0
+nft 'insert rule ip6 filter INPUT counter'
+
+ip6tables-translate -I INPUT ! -s ::/0
+nft 'insert rule ip6 filter INPUT ip6 saddr != ::/0 counter'
+
+iptables-translate -A FORWARD -p 132
+nft 'add rule ip filter FORWARD ip protocol sctp counter'
+
+ip6tables-translate -A FORWARD -p 132
+nft 'add rule ip6 filter FORWARD meta l4proto sctp counter'
+
+iptables-translate -A FORWARD ! -p 132
+nft 'add rule ip filter FORWARD ip protocol != sctp counter'
+
+ip6tables-translate -A FORWARD ! -p 132
+nft 'add rule ip6 filter FORWARD meta l4proto != sctp counter'
+
+iptables-translate -A FORWARD -p 141
+nft 'add rule ip filter FORWARD ip protocol 141 counter'
+
+ip6tables-translate -A FORWARD -p 141
+nft 'add rule ip6 filter FORWARD meta l4proto 141 counter'
+
+iptables-translate -A FORWARD ! -p 141
+nft 'add rule ip filter FORWARD ip protocol != 141 counter'
+
+ip6tables-translate -A FORWARD ! -p 141
+nft 'add rule ip6 filter FORWARD meta l4proto != 141 counter'
+
+iptables-translate -A FORWARD -m tcp --dport 22 -p tcp
+nft 'add rule ip filter FORWARD tcp dport 22 counter'
+
+ip6tables-translate -A FORWARD -m tcp --dport 22 -p tcp
+nft 'add rule ip6 filter FORWARD tcp dport 22 counter'
ebtables-translate -I INPUT -i iname --logical-in ilogname -s 0:0:0:0:0:0
-nft insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter
+nft 'insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter'
ebtables-translate -A FORWARD ! -i iname --logical-in ilogname -o out+ --logical-out lout+ -d 1:2:3:4:de:af
-nft add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oifname "out*" meta obrname "lout*" ether daddr 01:02:03:04:de:af counter
+nft 'add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oifname "out*" meta obrname "lout*" ether daddr 01:02:03:04:de:af counter'
ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00
-nft insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter
+nft 'insert rule bridge filter INPUT ether type 0x800 ether daddr and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter'
+
+ebtables-translate -I INPUT -p Length
+nft 'insert rule bridge filter INPUT ether type < 0x0600 counter'
+
+ebtables-translate -I INPUT -p ! Length
+nft 'insert rule bridge filter INPUT ether type >= 0x0600 counter'
# asterisk is not special in iptables and it is even a valid interface name
-iptables-translate -A FORWARD -i '*' -o 'eth*foo'
-nft add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter
+iptables-translate -A FORWARD -i * -o eth*foo
+nft 'add rule ip filter FORWARD iifname "\*" oifname "eth*foo" counter'
-# escape all asterisks but translate only the first plus character
-iptables-translate -A FORWARD -i 'eth*foo*+' -o 'eth++'
-nft add rule ip filter FORWARD iifname "eth\*foo\**" oifname "eth+*" counter
+# escape only suffix asterisk and translate only the last plus character
+iptables-translate -A FORWARD -i eth*foo*+ -o eth++
+nft 'add rule ip filter FORWARD iifname "eth*foo**" oifname "eth+*" counter'
# skip for always matching interface names
-iptables-translate -A FORWARD -i '+'
-nft add rule ip filter FORWARD counter
+iptables-translate -A FORWARD -i +
+nft 'add rule ip filter FORWARD counter'
# match against invalid interface name to simulate never matching rule
-iptables-translate -A FORWARD ! -i '+'
-nft add rule ip filter FORWARD iifname "INVAL/D" counter
+iptables-translate -A FORWARD ! -i +
+nft 'add rule ip filter FORWARD iifname "INVAL/D" counter'
diff --git a/extensions/libarpt_mangle.c b/extensions/libarpt_mangle.c
index 2fea6185..283bb132 100644
--- a/extensions/libarpt_mangle.c
+++ b/extensions/libarpt_mangle.c
@@ -13,7 +13,6 @@
#include <xtables.h>
#include <linux/netfilter_arp/arpt_mangle.h>
#include "iptables/nft.h"
-#include "iptables/nft-arp.h"
static void arpmangle_print_help(void)
{
@@ -26,19 +25,16 @@ static void arpmangle_print_help(void)
"--mangle-target target (DROP, CONTINUE or ACCEPT -- default is ACCEPT)\n");
}
-#define MANGLE_IPS '1'
-#define MANGLE_IPT '2'
-#define MANGLE_DEVS '3'
-#define MANGLE_DEVT '4'
-#define MANGLE_TARGET '5'
-
-static const struct option arpmangle_opts[] = {
- { .name = "mangle-ip-s", .has_arg = true, .val = MANGLE_IPS },
- { .name = "mangle-ip-d", .has_arg = true, .val = MANGLE_IPT },
- { .name = "mangle-mac-s", .has_arg = true, .val = MANGLE_DEVS },
- { .name = "mangle-mac-d", .has_arg = true, .val = MANGLE_DEVT },
- { .name = "mangle-target", .has_arg = true, .val = MANGLE_TARGET },
- XT_GETOPT_TABLEEND,
+/* internal use only, explicitly not covered by ARPT_MANGLE_MASK */
+#define ARPT_MANGLE_TARGET 0x10
+
+static const struct xt_option_entry arpmangle_opts[] = {
+{ .name = "mangle-ip-s", .id = ARPT_MANGLE_SIP, .type = XTTYPE_HOSTMASK },
+{ .name = "mangle-ip-d", .id = ARPT_MANGLE_TIP, .type = XTTYPE_HOSTMASK },
+{ .name = "mangle-mac-s", .id = ARPT_MANGLE_SDEV, .type = XTTYPE_ETHERMAC },
+{ .name = "mangle-mac-d", .id = ARPT_MANGLE_TDEV, .type = XTTYPE_ETHERMAC },
+{ .name = "mangle-target", .id = ARPT_MANGLE_TARGET, .type = XTTYPE_STRING },
+XTOPT_TABLEEND,
};
static void arpmangle_init(struct xt_entry_target *target)
@@ -48,95 +44,50 @@ static void arpmangle_init(struct xt_entry_target *target)
mangle->target = NF_ACCEPT;
}
-static int
-arpmangle_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
+static void assert_hopts(const struct arpt_entry *e, const char *optname)
+{
+ if (e->arp.arhln_mask == 0)
+ xtables_error(PARAMETER_PROBLEM, "no --h-length defined");
+ if (e->arp.invflags & IPT_INV_ARPHLN)
+ xtables_error(PARAMETER_PROBLEM,
+ "! hln not allowed for --%s", optname);
+ if (e->arp.arhln != 6)
+ xtables_error(PARAMETER_PROBLEM, "only --h-length 6 supported");
+}
+
+static void arpmangle_parse(struct xt_option_call *cb)
{
- struct arpt_mangle *mangle = (struct arpt_mangle *)(*target)->data;
- struct in_addr *ipaddr, mask;
- struct ether_addr *macaddr;
- const struct arpt_entry *e = (const struct arpt_entry *)entry;
- unsigned int nr;
- int ret = 1;
-
- memset(&mask, 0, sizeof(mask));
-
- switch (c) {
- case MANGLE_IPS:
- xtables_ipparse_any(optarg, &ipaddr, &mask, &nr);
- mangle->u_s.src_ip.s_addr = ipaddr->s_addr;
- free(ipaddr);
- mangle->flags |= ARPT_MANGLE_SIP;
+ const struct arpt_entry *e = cb->xt_entry;
+ struct arpt_mangle *mangle = cb->data;
+
+ xtables_option_parse(cb);
+ mangle->flags |= (cb->entry->id & ARPT_MANGLE_MASK);
+ switch (cb->entry->id) {
+ case ARPT_MANGLE_SIP:
+ mangle->u_s.src_ip = cb->val.haddr.in;
break;
- case MANGLE_IPT:
- xtables_ipparse_any(optarg, &ipaddr, &mask, &nr);
- mangle->u_t.tgt_ip.s_addr = ipaddr->s_addr;
- free(ipaddr);
- mangle->flags |= ARPT_MANGLE_TIP;
+ case ARPT_MANGLE_TIP:
+ mangle->u_t.tgt_ip = cb->val.haddr.in;
break;
- case MANGLE_DEVS:
- if (e->arp.arhln_mask == 0)
- xtables_error(PARAMETER_PROBLEM,
- "no --h-length defined");
- if (e->arp.invflags & ARPT_INV_ARPHLN)
- xtables_error(PARAMETER_PROBLEM,
- "! --h-length not allowed for "
- "--mangle-mac-s");
- if (e->arp.arhln != 6)
- xtables_error(PARAMETER_PROBLEM,
- "only --h-length 6 supported");
- macaddr = ether_aton(optarg);
- if (macaddr == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "invalid source MAC");
- memcpy(mangle->src_devaddr, macaddr, e->arp.arhln);
- mangle->flags |= ARPT_MANGLE_SDEV;
- break;
- case MANGLE_DEVT:
- if (e->arp.arhln_mask == 0)
- xtables_error(PARAMETER_PROBLEM,
- "no --h-length defined");
- if (e->arp.invflags & ARPT_INV_ARPHLN)
- xtables_error(PARAMETER_PROBLEM,
- "! hln not allowed for --mangle-mac-d");
- if (e->arp.arhln != 6)
- xtables_error(PARAMETER_PROBLEM,
- "only --h-length 6 supported");
- macaddr = ether_aton(optarg);
- if (macaddr == NULL)
- xtables_error(PARAMETER_PROBLEM, "invalid target MAC");
- memcpy(mangle->tgt_devaddr, macaddr, e->arp.arhln);
- mangle->flags |= ARPT_MANGLE_TDEV;
+ case ARPT_MANGLE_SDEV:
+ assert_hopts(e, cb->entry->name);
+ memcpy(mangle->src_devaddr, cb->val.ethermac, ETH_ALEN);
+ case ARPT_MANGLE_TDEV:
+ assert_hopts(e, cb->entry->name);
+ memcpy(mangle->tgt_devaddr, cb->val.ethermac, ETH_ALEN);
break;
- case MANGLE_TARGET:
- if (!strcmp(optarg, "DROP"))
+ case ARPT_MANGLE_TARGET:
+ if (!strcmp(cb->arg, "DROP"))
mangle->target = NF_DROP;
- else if (!strcmp(optarg, "ACCEPT"))
+ else if (!strcmp(cb->arg, "ACCEPT"))
mangle->target = NF_ACCEPT;
- else if (!strcmp(optarg, "CONTINUE"))
+ else if (!strcmp(cb->arg, "CONTINUE"))
mangle->target = XT_CONTINUE;
else
xtables_error(PARAMETER_PROBLEM,
"bad target for --mangle-target");
break;
- default:
- ret = 0;
}
-
- return ret;
-}
-
-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)
@@ -159,7 +110,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 +118,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",
@@ -180,6 +131,52 @@ static void arpmangle_save(const void *ip, const struct xt_entry_target *target)
arpmangle_print(ip, target, 0);
}
+static void print_devaddr_xlate(const char *macaddress, struct xt_xlate *xl)
+{
+ unsigned int i;
+
+ xt_xlate_add(xl, "%02x", macaddress[0]);
+ for (i = 1; i < ETH_ALEN; ++i)
+ xt_xlate_add(xl, ":%02x", macaddress[i]);
+}
+
+static int arpmangle_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct arpt_mangle *m = (const void *)params->target->data;
+
+ if (m->flags & ARPT_MANGLE_SIP)
+ xt_xlate_add(xl, "arp saddr ip set %s ",
+ xtables_ipaddr_to_numeric(&m->u_s.src_ip));
+
+ if (m->flags & ARPT_MANGLE_SDEV) {
+ xt_xlate_add(xl, "arp %caddr ether set ", 's');
+ print_devaddr_xlate(m->src_devaddr, xl);
+ }
+
+ if (m->flags & ARPT_MANGLE_TIP)
+ xt_xlate_add(xl, "arp daddr ip set %s ",
+ xtables_ipaddr_to_numeric(&m->u_t.tgt_ip));
+
+ if (m->flags & ARPT_MANGLE_TDEV) {
+ xt_xlate_add(xl, "arp %caddr ether set ", 'd');
+ print_devaddr_xlate(m->tgt_devaddr, xl);
+ }
+
+ switch (m->target) {
+ case NF_ACCEPT:
+ xt_xlate_add(xl, "accept");
+ break;
+ case NF_DROP:
+ xt_xlate_add(xl, "drop");
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
static struct xtables_target arpmangle_target = {
.name = "mangle",
.revision = 0,
@@ -189,11 +186,11 @@ static struct xtables_target arpmangle_target = {
.userspacesize = XT_ALIGN(sizeof(struct arpt_mangle)),
.help = arpmangle_print_help,
.init = arpmangle_init,
- .parse = arpmangle_parse,
- .final_check = arpmangle_final_check,
+ .x6_parse = arpmangle_parse,
.print = arpmangle_print,
.save = arpmangle_save,
- .extra_opts = arpmangle_opts,
+ .x6_options = arpmangle_opts,
+ .xlate = arpmangle_xlate,
};
void _init(void)
diff --git a/extensions/libarpt_mangle.t b/extensions/libarpt_mangle.t
index da966948..7a639ee1 100644
--- a/extensions/libarpt_mangle.t
+++ b/extensions/libarpt_mangle.t
@@ -3,3 +3,7 @@
-j mangle -d 1.2.3.4 --mangle-ip-d 1.2.3.5;=;OK
-j mangle -d 1.2.3.4 --mangle-mac-d 00:01:02:03:04:05;=;OK
-d 1.2.3.4 --h-length 5 -j mangle --mangle-mac-s 00:01:02:03:04:05;=;FAIL
+-j mangle --mangle-ip-s 1.2.3.4 --mangle-target DROP;=;OK
+-j mangle --mangle-ip-s 1.2.3.4 --mangle-target ACCEPT;-j mangle --mangle-ip-s 1.2.3.4;OK
+-j mangle --mangle-ip-s 1.2.3.4 --mangle-target CONTINUE;=;OK
+-j mangle --mangle-ip-s 1.2.3.4 --mangle-target FOO;=;FAIL
diff --git a/extensions/libarpt_mangle.txlate b/extensions/libarpt_mangle.txlate
new file mode 100644
index 00000000..e884d328
--- /dev/null
+++ b/extensions/libarpt_mangle.txlate
@@ -0,0 +1,6 @@
+arptables-translate -A OUTPUT -d 10.21.22.129 -j mangle --mangle-ip-s 10.21.22.161
+nft 'add rule arp filter OUTPUT arp htype 1 arp hlen 6 arp plen 4 arp daddr ip 10.21.22.129 counter arp saddr ip set 10.21.22.161 accept'
+arptables-translate -A OUTPUT -d 10.2.22.129/24 -j mangle --mangle-ip-d 10.2.22.1 --mangle-target CONTINUE
+nft 'add rule arp filter OUTPUT arp htype 1 arp hlen 6 arp plen 4 arp daddr ip 10.2.22.0/24 counter arp daddr ip set 10.2.22.1'
+arptables-translate -A OUTPUT -d 10.2.22.129/24 -j mangle --mangle-ip-d 10.2.22.1 --mangle-mac-d a:b:c:d:e:f
+nft 'add rule arp filter OUTPUT arp htype 1 arp hlen 6 arp plen 4 arp daddr ip 10.2.22.0/24 counter arp daddr ip set 10.2.22.1 arp daddr ether set 0a:0b:0c:0d:0e:0f accept'
diff --git a/extensions/libarpt_standard.t b/extensions/libarpt_standard.t
index e84a00b7..15354090 100644
--- a/extensions/libarpt_standard.t
+++ b/extensions/libarpt_standard.t
@@ -12,3 +12,12 @@
-i lo --destination-mac 11:22:33:44:55:66;-i lo --dst-mac 11:22:33:44:55:66;OK
--source-mac Unicast;--src-mac 00:00:00:00:00:00/01:00:00:00:00:00;OK
! --src-mac Multicast;! --src-mac 01:00:00:00:00:00/01:00:00:00:00:00;OK
+--src-mac=01:02:03:04:05:06 --dst-mac=07:08:09:0A:0B:0C --h-length=6 --opcode=Request --h-type=Ethernet --proto-type=ipv4;--src-mac 01:02:03:04:05:06 --dst-mac 07:08:09:0a:0b:0c --opcode 1 --proto-type 0x800;OK
+--src-mac ! 01:02:03:04:05:06 --dst-mac ! 07:08:09:0A:0B:0C --h-length ! 6 --opcode ! Request --h-type ! Ethernet --proto-type ! ipv4;! --src-mac 01:02:03:04:05:06 ! --dst-mac 07:08:09:0a:0b:0c ! --h-length 6 ! --opcode 1 ! --h-type 0x1 ! --proto-type 0x800;OK
+--h-type 10;--h-type 0x10;OK
+--h-type 0x10;=;OK
+--proto-type 10;--proto-type 0xa;OK
+--proto-type 10/10;--proto-type 0xa/0xa;OK
+--proto-type 0x10;=;OK
+--proto-type 0x10/0x10;=;OK
+--h-length 6/15 --opcode 1/235 --h-type 0x8/0xcf --proto-type 0x800/0xde00;=;OK
diff --git a/extensions/libebt_802_3.c b/extensions/libebt_802_3.c
index f05d02ea..489185e9 100644
--- a/extensions/libebt_802_3.c
+++ b/extensions/libebt_802_3.c
@@ -13,83 +13,40 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_802_3.h>
-#define _802_3_SAP '1'
-#define _802_3_TYPE '2'
-
-static const struct option br802_3_opts[] = {
- { .name = "802_3-sap", .has_arg = true, .val = _802_3_SAP },
- { .name = "802_3-type", .has_arg = true, .val = _802_3_TYPE },
- XT_GETOPT_TABLEEND,
+static const struct xt_option_entry br802_3_opts[] =
+{
+ { .name = "802_3-sap", .id = EBT_802_3_SAP,
+ .type = XTTYPE_UINT8, .base = 16,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_802_3_info, sap) },
+ { .name = "802_3-type", .id = EBT_802_3_TYPE,
+ .type = XTTYPE_UINT16, .base = 16,
+ .flags = XTOPT_INVERT | XTOPT_PUT | XTOPT_NBO,
+ XTOPT_POINTER(struct ebt_802_3_info, type) },
+ XTOPT_TABLEEND,
};
static void br802_3_print_help(void)
{
printf(
"802_3 options:\n"
-"--802_3-sap [!] protocol : 802.3 DSAP/SSAP- 1 byte value (hex)\n"
+"[!] --802_3-sap protocol : 802.3 DSAP/SSAP- 1 byte value (hex)\n"
" DSAP and SSAP are always the same. One SAP applies to both fields\n"
-"--802_3-type [!] protocol : 802.3 SNAP Type- 2 byte value (hex)\n"
+"[!] --802_3-type protocol : 802.3 SNAP Type- 2 byte value (hex)\n"
" Type implies SAP value 0xaa\n");
}
-static void br802_3_init(struct xt_entry_match *match)
-{
- struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data;
-
- info->invflags = 0;
- info->bitmask = 0;
-}
-
-static int
-br802_3_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
+static void br802_3_parse(struct xt_option_call *cb)
{
- struct ebt_802_3_info *info = (struct ebt_802_3_info *) (*match)->data;
- unsigned int i;
- char *end;
-
- switch (c) {
- case _802_3_SAP:
- if (invert)
- info->invflags |= EBT_802_3_SAP;
- i = strtoul(optarg, &end, 16);
- if (i > 255 || *end != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Problem with specified "
- "sap hex value, %x",i);
- info->sap = i; /* one byte, so no byte order worries */
- info->bitmask |= EBT_802_3_SAP;
- break;
- case _802_3_TYPE:
- if (invert)
- info->invflags |= EBT_802_3_TYPE;
- i = strtoul(optarg, &end, 16);
- if (i > 65535 || *end != '\0') {
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified "
- "type hex value, %x",i);
- }
- info->type = htons(i);
- info->bitmask |= EBT_802_3_TYPE;
- break;
- default:
- return 0;
- }
+ struct ebt_802_3_info *info = cb->data;
- *flags |= info->bitmask;
- return 1;
-}
-
-static void
-br802_3_final_check(unsigned int flags)
-{
- if (!flags)
- xtables_error(PARAMETER_PROBLEM,
- "You must specify proper arguments");
+ xtables_option_parse(cb);
+ info->bitmask |= cb->entry->id;
+ if (cb->invert)
+ info->invflags |= cb->entry->id;
}
static void br802_3_print(const void *ip, const struct xt_entry_match *match,
@@ -98,16 +55,14 @@ static void br802_3_print(const void *ip, const struct xt_entry_match *match,
struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data;
if (info->bitmask & EBT_802_3_SAP) {
- printf("--802_3-sap ");
if (info->invflags & EBT_802_3_SAP)
printf("! ");
- printf("0x%.2x ", info->sap);
+ printf("--802_3-sap 0x%.2x ", info->sap);
}
if (info->bitmask & EBT_802_3_TYPE) {
- printf("--802_3-type ");
if (info->invflags & EBT_802_3_TYPE)
printf("! ");
- printf("0x%.4x ", ntohs(info->type));
+ printf("--802_3-type 0x%.4x ", ntohs(info->type));
}
}
@@ -119,12 +74,10 @@ static struct xtables_match br802_3_match =
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_802_3_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_802_3_info)),
- .init = br802_3_init,
.help = br802_3_print_help,
- .parse = br802_3_parse,
- .final_check = br802_3_final_check,
+ .x6_parse = br802_3_parse,
.print = br802_3_print,
- .extra_opts = br802_3_opts,
+ .x6_options = br802_3_opts,
};
void _init(void)
diff --git a/extensions/libebt_802_3.t b/extensions/libebt_802_3.t
index ddfb2f0a..d1e19795 100644
--- a/extensions/libebt_802_3.t
+++ b/extensions/libebt_802_3.t
@@ -1,3 +1,7 @@
:INPUT,FORWARD,OUTPUT
---802_3-sap ! 0x0a -j CONTINUE;=;OK
---802_3-type 0x000a -j RETURN;=;OK
+! --802_3-sap 0x0a -j CONTINUE;=;FAIL
+--802_3-type 0x000a -j RETURN;=;FAIL
+-p Length --802_3-sap 0x0a -j CONTINUE;=;OK
+-p Length ! --802_3-sap 0x0a -j CONTINUE;=;OK
+-p Length --802_3-type 0x000a -j RETURN;=;OK
+-p Length ! --802_3-type 0x000a -j RETURN;=;OK
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
index 2b9a1b65..85f9bee4 100644
--- a/extensions/libebt_among.c
+++ b/extensions/libebt_among.c
@@ -43,10 +43,10 @@ static void bramong_print_help(void)
{
printf(
"`among' options:\n"
-"--among-dst [!] list : matches if ether dst is in list\n"
-"--among-src [!] list : matches if ether src is in list\n"
-"--among-dst-file [!] file : obtain dst list from file\n"
-"--among-src-file [!] file : obtain src list from file\n"
+"[!] --among-dst list : matches if ether dst is in list\n"
+"[!] --among-src list : matches if ether src is in list\n"
+"[!] --among-dst-file file : obtain dst list from file\n"
+"[!] --among-src-file file : obtain src list from file\n"
"list has form:\n"
" xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]"
",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
@@ -66,14 +66,14 @@ parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip)
if (sep) {
*sep = '\0';
- if (!inet_aton(sep + 1, &pair->in))
+ if (!inet_pton(AF_INET, sep + 1, &pair->in))
xtables_error(PARAMETER_PROBLEM,
- "Invalid IP address '%s'\n", sep + 1);
+ "Invalid IP address '%s'", sep + 1);
}
ether = ether_aton(buf);
if (!ether)
xtables_error(PARAMETER_PROBLEM,
- "Invalid MAC address '%s'\n", buf);
+ "Invalid MAC address '%s'", buf);
memcpy(&pair->ether, ether, sizeof(*ether));
}
@@ -119,7 +119,6 @@ static int bramong_parse(int c, char **argv, int invert,
struct xt_entry_match **match)
{
struct nft_among_data *data = (struct nft_among_data *)(*match)->data;
- struct xt_entry_match *new_match;
bool have_ip, dst = false;
size_t new_size, cnt;
struct stat stats;
@@ -152,10 +151,9 @@ static int bramong_parse(int c, char **argv, int invert,
xtables_error(PARAMETER_PROBLEM,
"File should only contain one line");
optarg[flen-1] = '\0';
- /* fall through */
+ break;
case AMONG_DST:
- if (c == AMONG_DST)
- dst = true;
+ dst = true;
/* fall through */
case AMONG_SRC:
break;
@@ -171,18 +169,17 @@ static int bramong_parse(int c, char **argv, int invert,
new_size *= sizeof(struct nft_among_pair);
new_size += XT_ALIGN(sizeof(struct xt_entry_match)) +
sizeof(struct nft_among_data);
- new_match = xtables_calloc(1, new_size);
- memcpy(new_match, *match, (*match)->u.match_size);
- new_match->u.match_size = new_size;
- data = (struct nft_among_data *)new_match->data;
+ if (new_size > (*match)->u.match_size) {
+ *match = xtables_realloc(*match, new_size);
+ (*match)->u.match_size = new_size;
+ data = (struct nft_among_data *)(*match)->data;
+ }
+
have_ip = nft_among_pairs_have_ip(optarg);
poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip);
parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip);
- free(*match);
- *match = new_match;
-
if (c == AMONG_DST_F || c == AMONG_SRC_F) {
munmap(argv, flen);
close(fd);
@@ -191,9 +188,10 @@ static int bramong_parse(int c, char **argv, int invert,
}
static void __bramong_print(struct nft_among_pair *pairs,
- int cnt, bool inv, bool have_ip)
+ int cnt, bool have_ip)
{
- const char *isep = inv ? "! " : "";
+ char abuf[INET_ADDRSTRLEN];
+ const char *isep = "";
int i;
for (i = 0; i < cnt; i++) {
@@ -202,7 +200,8 @@ static void __bramong_print(struct nft_among_pair *pairs,
printf("%s", ether_ntoa(&pairs[i].ether));
if (pairs[i].in.s_addr != INADDR_ANY)
- printf("=%s", inet_ntoa(pairs[i].in));
+ printf("=%s", inet_ntop(AF_INET, &pairs[i].in,
+ abuf, sizeof(abuf)));
}
printf(" ");
}
@@ -213,14 +212,13 @@ static void bramong_print(const void *ip, const struct xt_entry_match *match,
struct nft_among_data *data = (struct nft_among_data *)match->data;
if (data->src.cnt) {
- printf("--among-src ");
- __bramong_print(data->pairs,
- data->src.cnt, data->src.inv, data->src.ip);
+ printf("%s--among-src ", data->src.inv ? "! " : "");
+ __bramong_print(data->pairs, data->src.cnt, data->src.ip);
}
if (data->dst.cnt) {
- printf("--among-dst ");
+ printf("%s--among-dst ", data->dst.inv ? "! " : "");
__bramong_print(data->pairs + data->src.cnt,
- data->dst.cnt, data->dst.inv, data->dst.ip);
+ data->dst.cnt, data->dst.ip);
}
}
diff --git a/extensions/libebt_among.t b/extensions/libebt_among.t
index a02206f3..aef07acf 100644
--- a/extensions/libebt_among.t
+++ b/extensions/libebt_among.t
@@ -1,15 +1,15 @@
:INPUT,FORWARD,OUTPUT
--among-dst de:ad:0:be:ee:ff,c0:ff:ee:0:ba:be;--among-dst c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;OK
---among-dst ! c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;=;OK
+! --among-dst c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;=;OK
--among-src be:ef:0:c0:ff:ee,c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;=;OK
--among-src de:ad:0:be:ee:ff=10.0.0.1,c0:ff:ee:0:ba:be=192.168.1.1;--among-src c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff=10.0.0.1;OK
---among-src ! c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff=10.0.0.1;=;OK
+! --among-src c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff=10.0.0.1;=;OK
--among-src de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be;=;OK
--among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK
---among-src ! de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be;=;OK
---among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst ! c0:ff:ee:0:ba:be=192.168.1.1;=;OK
---among-src ! de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK
---among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst ! c0:ff:ee:0:ba:be=192.168.1.1;=;OK
+! --among-src de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be;=;OK
+--among-src de:ad:0:be:ee:ff=10.0.0.1 ! --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK
+! --among-src de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK
+--among-src de:ad:0:be:ee:ff=10.0.0.1 ! --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK
--among-src;=;FAIL
--among-src 00:11=10.0.0.1;=;FAIL
--among-src de:ad:0:be:ee:ff=10.256.0.1;=;FAIL
diff --git a/extensions/libebt_arp.c b/extensions/libebt_arp.c
index a062b7e7..50ce32be 100644
--- a/extensions/libebt_arp.c
+++ b/extensions/libebt_arp.c
@@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <getopt.h>
#include <xtables.h>
#include <netinet/ether.h>
@@ -20,26 +19,31 @@
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define ARP_OPCODE '1'
-#define ARP_HTYPE '2'
-#define ARP_PTYPE '3'
-#define ARP_IP_S '4'
-#define ARP_IP_D '5'
-#define ARP_MAC_S '6'
-#define ARP_MAC_D '7'
-#define ARP_GRAT '8'
+/* values must correspond with EBT_ARP_* bit positions */
+enum {
+ O_OPCODE = 0,
+ O_HTYPE,
+ O_PTYPE,
+ O_SRC_IP,
+ O_DST_IP,
+ O_SRC_MAC,
+ O_DST_MAC,
+ O_GRAT,
+};
-static const struct option brarp_opts[] = {
- { "arp-opcode" , required_argument, 0, ARP_OPCODE },
- { "arp-op" , required_argument, 0, ARP_OPCODE },
- { "arp-htype" , required_argument, 0, ARP_HTYPE },
- { "arp-ptype" , required_argument, 0, ARP_PTYPE },
- { "arp-ip-src" , required_argument, 0, ARP_IP_S },
- { "arp-ip-dst" , required_argument, 0, ARP_IP_D },
- { "arp-mac-src" , required_argument, 0, ARP_MAC_S },
- { "arp-mac-dst" , required_argument, 0, ARP_MAC_D },
- { "arp-gratuitous", no_argument, 0, ARP_GRAT },
- XT_GETOPT_TABLEEND,
+static const struct xt_option_entry brarp_opts[] = {
+#define ENTRY(n, i, t) { .name = n, .id = i, .type = t, .flags = XTOPT_INVERT }
+ ENTRY("arp-opcode", O_OPCODE, XTTYPE_STRING),
+ ENTRY("arp-op", O_OPCODE, XTTYPE_STRING),
+ ENTRY("arp-htype", O_HTYPE, XTTYPE_STRING),
+ ENTRY("arp-ptype", O_PTYPE, XTTYPE_STRING),
+ ENTRY("arp-ip-src", O_SRC_IP, XTTYPE_HOSTMASK),
+ ENTRY("arp-ip-dst", O_DST_IP, XTTYPE_HOSTMASK),
+ ENTRY("arp-mac-src", O_SRC_MAC, XTTYPE_ETHERMACMASK),
+ ENTRY("arp-mac-dst", O_DST_MAC, XTTYPE_ETHERMACMASK),
+ ENTRY("arp-gratuitous", O_GRAT, XTTYPE_NONE),
+#undef ENTRY
+ XTOPT_TABLEEND
};
/* a few names */
@@ -62,13 +66,13 @@ static void brarp_print_help(void)
printf(
"arp options:\n"
-"--arp-opcode [!] opcode : ARP opcode (integer or string)\n"
-"--arp-htype [!] type : ARP hardware type (integer or string)\n"
-"--arp-ptype [!] type : ARP protocol type (hexadecimal or string)\n"
-"--arp-ip-src [!] address[/mask]: ARP IP source specification\n"
-"--arp-ip-dst [!] address[/mask]: ARP IP target specification\n"
-"--arp-mac-src [!] address[/mask]: ARP MAC source specification\n"
-"--arp-mac-dst [!] address[/mask]: ARP MAC target specification\n"
+"[!] --arp-opcode opcode : ARP opcode (integer or string)\n"
+"[!] --arp-htype type : ARP hardware type (integer or string)\n"
+"[!] --arp-ptype type : ARP protocol type (hexadecimal or string)\n"
+"[!] --arp-ip-src address[/mask]: ARP IP source specification\n"
+"[!] --arp-ip-dst address[/mask]: ARP IP target specification\n"
+"[!] --arp-mac-src address[/mask]: ARP MAC source specification\n"
+"[!] --arp-mac-dst address[/mask]: ARP MAC target specification\n"
"[!] --arp-gratuitous : ARP gratuitous packet\n"
" opcode strings: \n");
for (i = 0; i < ARRAY_SIZE(opcodes); i++)
@@ -78,258 +82,74 @@ static void brarp_print_help(void)
" protocol type string: see "XT_PATH_ETHERTYPES"\n");
}
-#define OPT_OPCODE 0x01
-#define OPT_HTYPE 0x02
-#define OPT_PTYPE 0x04
-#define OPT_IP_S 0x08
-#define OPT_IP_D 0x10
-#define OPT_MAC_S 0x20
-#define OPT_MAC_D 0x40
-#define OPT_GRAT 0x80
-
-static int undot_ip(char *ip, unsigned char *ip2)
-{
- char *p, *q, *end;
- long int onebyte;
- int i;
- char buf[20];
-
- strncpy(buf, ip, sizeof(buf) - 1);
-
- p = buf;
- for (i = 0; i < 3; i++) {
- if ((q = strchr(p, '.')) == NULL)
- return -1;
- *q = '\0';
- onebyte = strtol(p, &end, 10);
- if (*end != '\0' || onebyte > 255 || onebyte < 0)
- return -1;
- ip2[i] = (unsigned char)onebyte;
- p = q + 1;
- }
-
- onebyte = strtol(p, &end, 10);
- if (*end != '\0' || onebyte > 255 || onebyte < 0)
- return -1;
- ip2[3] = (unsigned char)onebyte;
-
- return 0;
-}
-
-static int ip_mask(char *mask, unsigned char *mask2)
+static void brarp_parse(struct xt_option_call *cb)
{
+ struct ebt_arp_info *arpinfo = cb->data;
+ struct xt_ethertypeent *ent;
+ long int i;
char *end;
- long int bits;
- uint32_t mask22;
-
- if (undot_ip(mask, mask2)) {
- /* not the /a.b.c.e format, maybe the /x format */
- bits = strtol(mask, &end, 10);
- if (*end != '\0' || bits > 32 || bits < 0)
- return -1;
- if (bits != 0) {
- mask22 = htonl(0xFFFFFFFF << (32 - bits));
- memcpy(mask2, &mask22, 4);
- } else {
- mask22 = 0xFFFFFFFF;
- memcpy(mask2, &mask22, 4);
- }
- }
- return 0;
-}
-static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
-{
- char *p;
- /* first the mask */
- if ((p = strrchr(address, '/')) != NULL) {
- *p = '\0';
- if (ip_mask(p + 1, (unsigned char *)msk)) {
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the IP mask '%s'", p + 1);
- return;
- }
- } else
- *msk = 0xFFFFFFFF;
+ xtables_option_parse(cb);
- if (undot_ip(address, (unsigned char *)addr)) {
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the IP address '%s'", address);
- return;
- }
- *addr = *addr & *msk;
-}
+ arpinfo->bitmask |= 1 << cb->entry->id;
+ if (cb->invert)
+ arpinfo->invflags |= 1 << cb->entry->id;
-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)
-{
- struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data;
- long int i;
- char *end;
- uint32_t *addr;
- uint32_t *mask;
- unsigned char *maddr;
- unsigned char *mmask;
-
- switch (c) {
- case ARP_OPCODE:
- EBT_CHECK_OPTION(flags, OPT_OPCODE);
- if (invert)
- arpinfo->invflags |= EBT_ARP_OPCODE;
- i = strtol(optarg, &end, 10);
+ switch (cb->entry->id) {
+ case O_OPCODE:
+ i = strtol(cb->arg, &end, 10);
if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
for (i = 0; i < ARRAY_SIZE(opcodes); i++)
- if (!strcasecmp(opcodes[i], optarg))
+ if (!strcasecmp(opcodes[i], cb->arg))
break;
if (i == ARRAY_SIZE(opcodes))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP opcode");
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified ARP opcode");
i++;
}
arpinfo->opcode = htons(i);
- arpinfo->bitmask |= EBT_ARP_OPCODE;
break;
-
- case ARP_HTYPE:
- EBT_CHECK_OPTION(flags, OPT_HTYPE);
- if (invert)
- arpinfo->invflags |= EBT_ARP_HTYPE;
- i = strtol(optarg, &end, 10);
+ case O_HTYPE:
+ i = strtol(cb->arg, &end, 10);
if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
- if (!strcasecmp("Ethernet", argv[optind - 1]))
+ if (!strcasecmp("Ethernet", cb->arg))
i = 1;
else
- xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP hardware type");
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified ARP hardware type");
}
arpinfo->htype = htons(i);
- arpinfo->bitmask |= EBT_ARP_HTYPE;
break;
- case ARP_PTYPE: {
- uint16_t proto;
-
- EBT_CHECK_OPTION(flags, OPT_PTYPE);
- if (invert)
- arpinfo->invflags |= EBT_ARP_PTYPE;
-
- i = strtol(optarg, &end, 16);
- if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
- struct xt_ethertypeent *ent;
-
- ent = xtables_getethertypebyname(argv[optind - 1]);
- if (!ent)
- xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP "
- "protocol type");
- proto = ent->e_ethertype;
-
- } else
- proto = i;
- arpinfo->ptype = htons(proto);
- arpinfo->bitmask |= EBT_ARP_PTYPE;
- break;
- }
-
- case ARP_IP_S:
- case ARP_IP_D:
- if (c == ARP_IP_S) {
- EBT_CHECK_OPTION(flags, OPT_IP_S);
- addr = &arpinfo->saddr;
- mask = &arpinfo->smsk;
- arpinfo->bitmask |= EBT_ARP_SRC_IP;
- } else {
- EBT_CHECK_OPTION(flags, OPT_IP_D);
- addr = &arpinfo->daddr;
- mask = &arpinfo->dmsk;
- arpinfo->bitmask |= EBT_ARP_DST_IP;
+ case O_PTYPE:
+ i = strtol(cb->arg, &end, 16);
+ if (i >= 0 && i < (0x1 << 16) && *end == '\0') {
+ arpinfo->ptype = htons(i);
+ break;
}
- if (invert) {
- if (c == ARP_IP_S)
- arpinfo->invflags |= EBT_ARP_SRC_IP;
- else
- arpinfo->invflags |= EBT_ARP_DST_IP;
- }
- ebt_parse_ip_address(optarg, addr, mask);
+ ent = xtables_getethertypebyname(cb->arg);
+ if (!ent)
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified ARP protocol type");
+ arpinfo->ptype = htons(ent->e_ethertype);
break;
- case ARP_MAC_S:
- case ARP_MAC_D:
- if (c == ARP_MAC_S) {
- EBT_CHECK_OPTION(flags, OPT_MAC_S);
- maddr = arpinfo->smaddr;
- mmask = arpinfo->smmsk;
- arpinfo->bitmask |= EBT_ARP_SRC_MAC;
- } else {
- EBT_CHECK_OPTION(flags, OPT_MAC_D);
- maddr = arpinfo->dmaddr;
- mmask = arpinfo->dmmsk;
- arpinfo->bitmask |= EBT_ARP_DST_MAC;
- }
- if (invert) {
- if (c == ARP_MAC_S)
- arpinfo->invflags |= EBT_ARP_SRC_MAC;
- else
- arpinfo->invflags |= EBT_ARP_DST_MAC;
- }
- if (brarp_get_mac_and_mask(optarg, maddr, mmask))
- xtables_error(PARAMETER_PROBLEM, "Problem with ARP MAC address argument");
+ case O_SRC_IP:
+ arpinfo->saddr = cb->val.haddr.ip & cb->val.hmask.ip;
+ arpinfo->smsk = cb->val.hmask.ip;
+ break;
+ case O_DST_IP:
+ arpinfo->daddr = cb->val.haddr.ip & cb->val.hmask.ip;
+ arpinfo->dmsk = cb->val.hmask.ip;
+ break;
+ case O_SRC_MAC:
+ memcpy(arpinfo->smaddr, cb->val.ethermac, ETH_ALEN);
+ memcpy(arpinfo->smmsk, cb->val.ethermacmask, ETH_ALEN);
break;
- case ARP_GRAT:
- EBT_CHECK_OPTION(flags, OPT_GRAT);
- arpinfo->bitmask |= EBT_ARP_GRAT;
- if (invert)
- arpinfo->invflags |= EBT_ARP_GRAT;
+ case O_DST_MAC:
+ memcpy(arpinfo->dmaddr, cb->val.ethermac, ETH_ALEN);
+ memcpy(arpinfo->dmmsk, cb->val.ethermacmask, ETH_ALEN);
break;
- default:
- return 0;
}
- return 1;
}
static void brarp_print(const void *ip, const struct xt_entry_match *match, int numeric)
@@ -338,51 +158,50 @@ static void brarp_print(const void *ip, const struct xt_entry_match *match, int
if (arpinfo->bitmask & EBT_ARP_OPCODE) {
int opcode = ntohs(arpinfo->opcode);
- printf("--arp-op ");
+
if (arpinfo->invflags & EBT_ARP_OPCODE)
printf("! ");
+ printf("--arp-op ");
if (opcode > 0 && opcode <= ARRAY_SIZE(opcodes))
printf("%s ", opcodes[opcode - 1]);
else
printf("%d ", opcode);
}
if (arpinfo->bitmask & EBT_ARP_HTYPE) {
- printf("--arp-htype ");
if (arpinfo->invflags & EBT_ARP_HTYPE)
printf("! ");
- printf("%d ", ntohs(arpinfo->htype));
+ printf("--arp-htype %d ", ntohs(arpinfo->htype));
}
if (arpinfo->bitmask & EBT_ARP_PTYPE) {
- printf("--arp-ptype ");
if (arpinfo->invflags & EBT_ARP_PTYPE)
printf("! ");
- printf("0x%x ", ntohs(arpinfo->ptype));
+ printf("--arp-ptype 0x%x ", ntohs(arpinfo->ptype));
}
if (arpinfo->bitmask & EBT_ARP_SRC_IP) {
- printf("--arp-ip-src ");
if (arpinfo->invflags & EBT_ARP_SRC_IP)
printf("! ");
- printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->saddr),
- xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->smsk));
+ printf("--arp-ip-src %s%s ",
+ xtables_ipaddr_to_numeric((void *)&arpinfo->saddr),
+ xtables_ipmask_to_numeric((void *)&arpinfo->smsk));
}
if (arpinfo->bitmask & EBT_ARP_DST_IP) {
- printf("--arp-ip-dst ");
if (arpinfo->invflags & EBT_ARP_DST_IP)
printf("! ");
- printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->daddr),
- xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->dmsk));
+ printf("--arp-ip-dst %s%s ",
+ xtables_ipaddr_to_numeric((void *)&arpinfo->daddr),
+ xtables_ipmask_to_numeric((void *)&arpinfo->dmsk));
}
if (arpinfo->bitmask & EBT_ARP_SRC_MAC) {
- printf("--arp-mac-src ");
if (arpinfo->invflags & EBT_ARP_SRC_MAC)
printf("! ");
+ printf("--arp-mac-src ");
xtables_print_mac_and_mask(arpinfo->smaddr, arpinfo->smmsk);
printf(" ");
}
if (arpinfo->bitmask & EBT_ARP_DST_MAC) {
- printf("--arp-mac-dst ");
if (arpinfo->invflags & EBT_ARP_DST_MAC)
printf("! ");
+ printf("--arp-mac-dst ");
xtables_print_mac_and_mask(arpinfo->dmaddr, arpinfo->dmmsk);
printf(" ");
}
@@ -400,9 +219,9 @@ static struct xtables_match brarp_match = {
.size = XT_ALIGN(sizeof(struct ebt_arp_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_arp_info)),
.help = brarp_print_help,
- .parse = brarp_parse,
+ .x6_parse = brarp_parse,
.print = brarp_print,
- .extra_opts = brarp_opts,
+ .x6_options = brarp_opts,
};
void _init(void)
diff --git a/extensions/libebt_arp.t b/extensions/libebt_arp.t
index 14ff0f09..ea006f25 100644
--- a/extensions/libebt_arp.t
+++ b/extensions/libebt_arp.t
@@ -1,12 +1,22 @@
:INPUT,FORWARD,OUTPUT
-p ARP --arp-op Request;=;OK
--p ARP --arp-htype ! 1;=;OK
+-p ARP ! --arp-op Request;=;OK
+-p ARP --arp-htype Ethernet;-p ARP --arp-htype 1;OK
+-p ARP --arp-htype 1;=;OK
+-p ARP ! --arp-htype 1;=;OK
-p ARP --arp-ptype 0x2;=;OK
+-p ARP ! --arp-ptype 0x2;=;OK
-p ARP --arp-ip-src 1.2.3.4;=;OK
--p ARP ! --arp-ip-dst 1.2.3.4;-p ARP --arp-ip-dst ! 1.2.3.4 -j CONTINUE;OK
--p ARP --arp-ip-src ! 0.0.0.0;=;OK
--p ARP --arp-ip-dst ! 0.0.0.0/8;=;OK
+-p ARP --arp-ip-dst ! 1.2.3.4;-p ARP ! --arp-ip-dst 1.2.3.4 -j CONTINUE;OK
+-p ARP ! --arp-ip-src 0.0.0.0;=;OK
+-p ARP ! --arp-ip-dst 0.0.0.0/8;=;OK
+-p ARP ! --arp-ip-src 1.2.3.4/32;-p ARP ! --arp-ip-src 1.2.3.4;OK
+-p ARP ! --arp-ip-src 1.2.3.4/255.255.255.0;-p ARP ! --arp-ip-src 1.2.3.0/24;OK
+-p ARP ! --arp-ip-src 1.2.3.4/255.0.255.255;-p ARP ! --arp-ip-src 1.0.3.4/255.0.255.255;OK
-p ARP --arp-mac-src 00:de:ad:be:ef:00;=;OK
+-p ARP ! --arp-mac-src 00:de:ad:be:ef:00;=;OK
-p ARP --arp-mac-dst de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK
+-p ARP ! --arp-mac-dst de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK
-p ARP --arp-gratuitous;=;OK
+-p ARP ! --arp-gratuitous;=;OK
--arp-htype 1;=;FAIL
diff --git a/extensions/libebt_arpreply.c b/extensions/libebt_arpreply.c
index 80ba2159..1d6ba36a 100644
--- a/extensions/libebt_arpreply.c
+++ b/extensions/libebt_arpreply.c
@@ -10,22 +10,22 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <getopt.h>
#include <xtables.h>
#include <netinet/ether.h>
#include <linux/netfilter_bridge/ebt_arpreply.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define OPT_REPLY_MAC 0x01
-#define OPT_REPLY_TARGET 0x02
+enum {
+ O_MAC,
+ O_TARGET,
+};
-#define REPLY_MAC '1'
-#define REPLY_TARGET '2'
-static const struct option brarpreply_opts[] = {
- { "arpreply-mac" , required_argument, 0, REPLY_MAC },
- { "arpreply-target" , required_argument, 0, REPLY_TARGET },
- XT_GETOPT_TABLEEND,
+static const struct xt_option_entry brarpreply_opts[] = {
+ { .name = "arpreply-mac" , .id = O_MAC, .type = XTTYPE_ETHERMAC,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_arpreply_info, mac) },
+ { .name = "arpreply-target" , .id = O_TARGET, .type = XTTYPE_STRING },
+ XTOPT_TABLEEND,
};
static void brarpreply_print_help(void)
@@ -44,31 +44,15 @@ static void brarpreply_init(struct xt_entry_target *target)
replyinfo->target = EBT_DROP;
}
-static int
-brarpreply_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **tg)
-
+static void brarpreply_parse(struct xt_option_call *cb)
{
- struct ebt_arpreply_info *replyinfo = (void *)(*tg)->data;
- struct ether_addr *addr;
-
- switch (c) {
- case REPLY_MAC:
- EBT_CHECK_OPTION(flags, OPT_REPLY_MAC);
- if (!(addr = ether_aton(optarg)))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified --arpreply-mac mac");
- memcpy(replyinfo->mac, addr, ETH_ALEN);
- break;
- case REPLY_TARGET:
- EBT_CHECK_OPTION(flags, OPT_REPLY_TARGET);
- if (ebt_fill_target(optarg, (unsigned int *)&replyinfo->target))
- xtables_error(PARAMETER_PROBLEM, "Illegal --arpreply-target target");
- break;
+ struct ebt_arpreply_info *replyinfo = cb->data;
- default:
- return 0;
- }
- return 1;
+ xtables_option_parse(cb);
+ if (cb->entry->id == O_TARGET &&
+ ebt_fill_target(cb->arg, (unsigned int *)&replyinfo->target))
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal --arpreply-target target");
}
static void brarpreply_print(const void *ip, const struct xt_entry_target *t, int numeric)
@@ -90,9 +74,9 @@ static struct xtables_target arpreply_target = {
.size = XT_ALIGN(sizeof(struct ebt_arpreply_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_arpreply_info)),
.help = brarpreply_print_help,
- .parse = brarpreply_parse,
+ .x6_parse = brarpreply_parse,
.print = brarpreply_print,
- .extra_opts = brarpreply_opts,
+ .x6_options = brarpreply_opts,
};
void _init(void)
diff --git a/extensions/libebt_arpreply.t b/extensions/libebt_arpreply.t
index 6734501a..66103e16 100644
--- a/extensions/libebt_arpreply.t
+++ b/extensions/libebt_arpreply.t
@@ -1,4 +1,8 @@
:PREROUTING
*nat
+-j arpreply;=;FAIL
+-p ARP -i foo -j arpreply;-p ARP -i foo -j arpreply --arpreply-mac 00:00:00:00:00:00;OK
-p ARP -i foo -j arpreply --arpreply-mac de:ad:00:be:ee:ff --arpreply-target ACCEPT;=;OK
-p ARP -i foo -j arpreply --arpreply-mac de:ad:00:be:ee:ff;=;OK
+-p ARP -j arpreply ! --arpreply-mac de:ad:00:be:ee:ff;;FAIL
+-p ARP -j arpreply --arpreply-mac de:ad:00:be:ee:ff ! --arpreply-target ACCEPT;;FAIL
diff --git a/extensions/libebt_dnat.c b/extensions/libebt_dnat.c
index 9f5f721e..447ff105 100644
--- a/extensions/libebt_dnat.c
+++ b/extensions/libebt_dnat.c
@@ -9,21 +9,25 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <netinet/ether.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define NAT_D '1'
-#define NAT_D_TARGET '2'
-static const struct option brdnat_opts[] =
+enum {
+ O_DST,
+ O_TARGET,
+};
+
+static const struct xt_option_entry brdnat_opts[] =
{
- { "to-destination", required_argument, 0, NAT_D },
- { "to-dst" , required_argument, 0, NAT_D },
- { "dnat-target" , required_argument, 0, NAT_D_TARGET },
- { 0 }
+ { .name = "to-destination", .id = O_DST, .type = XTTYPE_ETHERMAC,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nat_info, mac) },
+ { .name = "to-dst" , .id = O_DST, .type = XTTYPE_ETHERMAC,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nat_info, mac) },
+ { .name = "dnat-target" , .id = O_TARGET, .type = XTTYPE_STRING },
+ XTOPT_TABLEEND,
};
static void brdnat_print_help(void)
@@ -31,7 +35,8 @@ static void brdnat_print_help(void)
printf(
"dnat options:\n"
" --to-dst address : MAC address to map destination to\n"
- " --dnat-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
+ " --dnat-target target : ACCEPT, DROP, RETURN or CONTINUE\n"
+ " (standard target is ACCEPT)\n");
}
static void brdnat_init(struct xt_entry_target *target)
@@ -41,35 +46,20 @@ static void brdnat_init(struct xt_entry_target *target)
natinfo->target = EBT_ACCEPT;
}
-#define OPT_DNAT 0x01
-#define OPT_DNAT_TARGET 0x02
-static int brdnat_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
+static void brdnat_parse(struct xt_option_call *cb)
{
- struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
- struct ether_addr *addr;
-
- switch (c) {
- case NAT_D:
- EBT_CHECK_OPTION(flags, OPT_DNAT);
- if (!(addr = ether_aton(optarg)))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified --to-destination mac");
- memcpy(natinfo->mac, addr, ETH_ALEN);
- break;
- case NAT_D_TARGET:
- EBT_CHECK_OPTION(flags, OPT_DNAT_TARGET);
- if (ebt_fill_target(optarg, (unsigned int *)&natinfo->target))
- xtables_error(PARAMETER_PROBLEM, "Illegal --dnat-target target");
- break;
- default:
- return 0;
- }
- return 1;
+ struct ebt_nat_info *natinfo = cb->data;
+
+ xtables_option_parse(cb);
+ if (cb->entry->id == O_TARGET &&
+ ebt_fill_target(cb->arg, (unsigned int *)&natinfo->target))
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal --dnat-target target");
}
-static void brdnat_final_check(unsigned int flags)
+static void brdnat_final_check(struct xt_fcheck_call *fc)
{
- if (!flags)
+ if (!fc->xflags)
xtables_error(PARAMETER_PROBLEM,
"You must specify proper arguments");
}
@@ -116,11 +106,11 @@ static struct xtables_target brdnat_target =
.userspacesize = XT_ALIGN(sizeof(struct ebt_nat_info)),
.help = brdnat_print_help,
.init = brdnat_init,
- .parse = brdnat_parse,
- .final_check = brdnat_final_check,
+ .x6_parse = brdnat_parse,
+ .x6_fcheck = brdnat_final_check,
.print = brdnat_print,
.xlate = brdnat_xlate,
- .extra_opts = brdnat_opts,
+ .x6_options = brdnat_opts,
};
void _init(void)
diff --git a/extensions/libebt_dnat.txlate b/extensions/libebt_dnat.txlate
index 2652dd55..531a22aa 100644
--- a/extensions/libebt_dnat.txlate
+++ b/extensions/libebt_dnat.txlate
@@ -1,8 +1,8 @@
-ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff
-nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter
+ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff
+nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff accept'
-ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT
-nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff accept counter
+ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff --dnat-target ACCEPT
+nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff accept'
-ebtables-translate -t nat -A PREROUTING -i someport --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE
-nft add rule bridge nat PREROUTING iifname "someport" ether daddr set de:ad:0:be:ee:ff continue counter
+ebtables-translate -t nat -A PREROUTING -i someport -j dnat --to-dst de:ad:00:be:ee:ff --dnat-target CONTINUE
+nft 'add rule bridge nat PREROUTING iifname "someport" counter ether daddr set de:ad:0:be:ee:ff continue'
diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c
index acb9bfcd..3ed852ad 100644
--- a/extensions/libebt_ip.c
+++ b/extensions/libebt_ip.c
@@ -16,144 +16,77 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <netdb.h>
#include <inttypes.h>
#include <xtables.h>
+#include <linux/netfilter_bridge/ebt_ip.h>
#include "libxt_icmp.h"
-#define EBT_IP_SOURCE 0x01
-#define EBT_IP_DEST 0x02
-#define EBT_IP_TOS 0x04
-#define EBT_IP_PROTO 0x08
-#define EBT_IP_SPORT 0x10
-#define EBT_IP_DPORT 0x20
-#define EBT_IP_ICMP 0x40
-#define EBT_IP_IGMP 0x80
-#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
- EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
-
-struct ebt_ip_info {
- __be32 saddr;
- __be32 daddr;
- __be32 smsk;
- __be32 dmsk;
- __u8 tos;
- __u8 protocol;
- __u8 bitmask;
- __u8 invflags;
- union {
- __u16 sport[2];
- __u8 icmp_type[2];
- __u8 igmp_type[2];
- };
- union {
- __u16 dport[2];
- __u8 icmp_code[2];
- };
+/* must correspond to the bit position in EBT_IP6_* defines */
+enum {
+ O_SOURCE = 0,
+ O_DEST,
+ O_TOS,
+ O_PROTO,
+ O_SPORT,
+ O_DPORT,
+ O_ICMP,
+ O_IGMP,
+ F_PORT = 1 << O_ICMP | 1 << O_IGMP,
+ F_ICMP = 1 << O_SPORT | 1 << O_DPORT | 1 << O_IGMP,
+ F_IGMP = 1 << O_SPORT | 1 << O_DPORT | 1 << O_ICMP,
};
-#define IP_SOURCE '1'
-#define IP_DEST '2'
-#define IP_EBT_TOS '3' /* include/bits/in.h seems to already define IP_TOS */
-#define IP_PROTO '4'
-#define IP_SPORT '5'
-#define IP_DPORT '6'
-#define IP_EBT_ICMP '7'
-#define IP_EBT_IGMP '8'
-
-static const struct option brip_opts[] = {
- { .name = "ip-source", .has_arg = true, .val = IP_SOURCE },
- { .name = "ip-src", .has_arg = true, .val = IP_SOURCE },
- { .name = "ip-destination", .has_arg = true, .val = IP_DEST },
- { .name = "ip-dst", .has_arg = true, .val = IP_DEST },
- { .name = "ip-tos", .has_arg = true, .val = IP_EBT_TOS },
- { .name = "ip-protocol", .has_arg = true, .val = IP_PROTO },
- { .name = "ip-proto", .has_arg = true, .val = IP_PROTO },
- { .name = "ip-source-port", .has_arg = true, .val = IP_SPORT },
- { .name = "ip-sport", .has_arg = true, .val = IP_SPORT },
- { .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT },
- { .name = "ip-dport", .has_arg = true, .val = IP_DPORT },
- { .name = "ip-icmp-type", .has_arg = true, .val = IP_EBT_ICMP },
- { .name = "ip-igmp-type", .has_arg = true, .val = IP_EBT_IGMP },
- XT_GETOPT_TABLEEND,
-};
-
-static const struct xt_icmp_names icmp_codes[] = {
- { "echo-reply", 0, 0, 0xFF },
- /* Alias */ { "pong", 0, 0, 0xFF },
-
- { "destination-unreachable", 3, 0, 0xFF },
- { "network-unreachable", 3, 0, 0 },
- { "host-unreachable", 3, 1, 1 },
- { "protocol-unreachable", 3, 2, 2 },
- { "port-unreachable", 3, 3, 3 },
- { "fragmentation-needed", 3, 4, 4 },
- { "source-route-failed", 3, 5, 5 },
- { "network-unknown", 3, 6, 6 },
- { "host-unknown", 3, 7, 7 },
- { "network-prohibited", 3, 9, 9 },
- { "host-prohibited", 3, 10, 10 },
- { "TOS-network-unreachable", 3, 11, 11 },
- { "TOS-host-unreachable", 3, 12, 12 },
- { "communication-prohibited", 3, 13, 13 },
- { "host-precedence-violation", 3, 14, 14 },
- { "precedence-cutoff", 3, 15, 15 },
-
- { "source-quench", 4, 0, 0xFF },
-
- { "redirect", 5, 0, 0xFF },
- { "network-redirect", 5, 0, 0 },
- { "host-redirect", 5, 1, 1 },
- { "TOS-network-redirect", 5, 2, 2 },
- { "TOS-host-redirect", 5, 3, 3 },
-
- { "echo-request", 8, 0, 0xFF },
- /* Alias */ { "ping", 8, 0, 0xFF },
-
- { "router-advertisement", 9, 0, 0xFF },
-
- { "router-solicitation", 10, 0, 0xFF },
-
- { "time-exceeded", 11, 0, 0xFF },
- /* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
- { "ttl-zero-during-transit", 11, 0, 0 },
- { "ttl-zero-during-reassembly", 11, 1, 1 },
-
- { "parameter-problem", 12, 0, 0xFF },
- { "ip-header-bad", 12, 0, 0 },
- { "required-option-missing", 12, 1, 1 },
-
- { "timestamp-request", 13, 0, 0xFF },
-
- { "timestamp-reply", 14, 0, 0xFF },
-
- { "address-mask-request", 17, 0, 0xFF },
-
- { "address-mask-reply", 18, 0, 0xFF }
-};
-
-static const struct xt_icmp_names igmp_types[] = {
- { "membership-query", 0x11 },
- { "membership-report-v1", 0x12 },
- { "membership-report-v2", 0x16 },
- { "leave-group", 0x17 },
- { "membership-report-v3", 0x22 },
+static const struct xt_option_entry brip_opts[] = {
+ { .name = "ip-source", .id = O_SOURCE, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip-src", .id = O_SOURCE, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip-destination", .id = O_DEST, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip-dst", .id = O_DEST, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip-tos", .id = O_TOS, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip_info, tos) },
+ { .name = "ip-protocol", .id = O_PROTO, .type = XTTYPE_PROTOCOL,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip_info, protocol) },
+ { .name = "ip-proto", .id = O_PROTO, .type = XTTYPE_PROTOCOL,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip_info, protocol) },
+ { .name = "ip-source-port", .id = O_SPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip_info, sport) },
+ { .name = "ip-sport", .id = O_SPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip_info, sport) },
+ { .name = "ip-destination-port",.id = O_DPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip_info, dport) },
+ { .name = "ip-dport", .id = O_DPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip_info, dport) },
+ { .name = "ip-icmp-type", .id = O_ICMP, .type = XTTYPE_STRING,
+ .excl = F_ICMP, .flags = XTOPT_INVERT },
+ { .name = "ip-igmp-type", .id = O_IGMP, .type = XTTYPE_STRING,
+ .excl = F_IGMP, .flags = XTOPT_INVERT },
+ XTOPT_TABLEEND,
};
static void brip_print_help(void)
{
printf(
"ip options:\n"
-"--ip-src [!] address[/mask]: ip source specification\n"
-"--ip-dst [!] address[/mask]: ip destination specification\n"
-"--ip-tos [!] tos : ip tos specification\n"
-"--ip-proto [!] protocol : ip protocol specification\n"
-"--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
-"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n"
-"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n"
-"--ip-igmp-type [!] type[:type] : igmp type or type range\n");
+"[!] --ip-src address[/mask]: ip source specification\n"
+"[!] --ip-dst address[/mask]: ip destination specification\n"
+"[!] --ip-tos tos : ip tos specification\n"
+"[!] --ip-proto protocol : ip protocol specification\n"
+"[!] --ip-sport port[:port] : tcp/udp source port or port range\n"
+"[!] --ip-dport port[:port] : tcp/udp destination port or port range\n"
+"[!] --ip-icmp-type type[[:type]/code[:code]] : icmp type/code or type/code range\n"
+"[!] --ip-igmp-type type[:type] : igmp type or type range\n");
printf("\nValid ICMP Types:\n");
xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
@@ -161,188 +94,7 @@ static void brip_print_help(void)
xt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
}
-static void brip_init(struct xt_entry_match *match)
-{
- struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
-
- info->invflags = 0;
- info->bitmask = 0;
-}
-
-static void
-parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
-{
- char *buffer;
- char *cp;
-
- buffer = strdup(portstring);
- if ((cp = strchr(buffer, ':')) == NULL)
- ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
- else {
- *cp = '\0';
- cp++;
-
- ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0;
- ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF;
-
- if (ports[0] > ports[1])
- xtables_error(PARAMETER_PROBLEM,
- "invalid portrange (min > max)");
- }
- free(buffer);
-}
-
/* original code from ebtables: useful_functions.c */
-static int undot_ip(char *ip, unsigned char *ip2)
-{
- char *p, *q, *end;
- long int onebyte;
- int i;
- char buf[20];
-
- strncpy(buf, ip, sizeof(buf) - 1);
-
- p = buf;
- for (i = 0; i < 3; i++) {
- if ((q = strchr(p, '.')) == NULL)
- return -1;
- *q = '\0';
- onebyte = strtol(p, &end, 10);
- if (*end != '\0' || onebyte > 255 || onebyte < 0)
- return -1;
- ip2[i] = (unsigned char)onebyte;
- p = q + 1;
- }
-
- onebyte = strtol(p, &end, 10);
- if (*end != '\0' || onebyte > 255 || onebyte < 0)
- return -1;
- ip2[3] = (unsigned char)onebyte;
-
- return 0;
-}
-
-static int ip_mask(char *mask, unsigned char *mask2)
-{
- char *end;
- long int bits;
- uint32_t mask22;
-
- if (undot_ip(mask, mask2)) {
- /* not the /a.b.c.e format, maybe the /x format */
- bits = strtol(mask, &end, 10);
- if (*end != '\0' || bits > 32 || bits < 0)
- return -1;
- if (bits != 0) {
- mask22 = htonl(0xFFFFFFFF << (32 - bits));
- memcpy(mask2, &mask22, 4);
- } else {
- mask22 = 0xFFFFFFFF;
- memcpy(mask2, &mask22, 4);
- }
- }
- return 0;
-}
-
-static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
-{
- char *p;
-
- /* first the mask */
- if ((p = strrchr(address, '/')) != NULL) {
- *p = '\0';
- if (ip_mask(p + 1, (unsigned char *)msk)) {
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the IP mask '%s'", p + 1);
- return;
- }
- } else
- *msk = 0xFFFFFFFF;
-
- if (undot_ip(address, (unsigned char *)addr)) {
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the IP address '%s'", address);
- return;
- }
- *addr = *addr & *msk;
-}
-
-static char *parse_range(const char *str, unsigned int res[])
-{
- char *next;
-
- if (!xtables_strtoui(str, &next, &res[0], 0, 255))
- return NULL;
-
- res[1] = res[0];
- if (*next == ':') {
- str = next + 1;
- if (!xtables_strtoui(str, &next, &res[1], 0, 255))
- return NULL;
- }
-
- return next;
-}
-
-static int ebt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes,
- const char *icmptype, uint8_t type[], uint8_t code[])
-{
- unsigned int match = n_codes;
- unsigned int i, number[2];
-
- for (i = 0; i < n_codes; i++) {
- if (strncasecmp(codes[i].name, icmptype, strlen(icmptype)))
- continue;
- if (match != n_codes)
- xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMP type `%s':"
- " `%s' or `%s'?",
- icmptype, codes[match].name,
- codes[i].name);
- match = i;
- }
-
- if (match < n_codes) {
- type[0] = type[1] = codes[match].type;
- if (code) {
- code[0] = codes[match].code_min;
- code[1] = codes[match].code_max;
- }
- } else {
- char *next = parse_range(icmptype, number);
- if (!next) {
- xtables_error(PARAMETER_PROBLEM, "Unknown ICMP type `%s'",
- icmptype);
- return -1;
- }
-
- type[0] = (uint8_t) number[0];
- type[1] = (uint8_t) number[1];
- switch (*next) {
- case 0:
- if (code) {
- code[0] = 0;
- code[1] = 255;
- }
- return 0;
- case '/':
- if (code) {
- next = parse_range(next+1, number);
- code[0] = (uint8_t) number[0];
- code[1] = (uint8_t) number[1];
- if (next == NULL)
- return -1;
- if (next && *next == 0)
- return 0;
- }
- /* fallthrough */
- default:
- xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next);
- return -1;
- }
- }
- return 0;
-}
-
static void print_icmp_code(uint8_t *code)
{
if (!code)
@@ -379,80 +131,38 @@ static void ebt_print_icmp_type(const struct xt_icmp_names *codes,
print_icmp_code(code);
}
-static int
-brip_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
+static void brip_parse(struct xt_option_call *cb)
{
- struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data;
-
- switch (c) {
- case IP_SOURCE:
- if (invert)
- info->invflags |= EBT_IP_SOURCE;
- ebt_parse_ip_address(optarg, &info->saddr, &info->smsk);
- info->bitmask |= EBT_IP_SOURCE;
- break;
- case IP_DEST:
- if (invert)
- info->invflags |= EBT_IP_DEST;
- ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk);
- info->bitmask |= EBT_IP_DEST;
- break;
- case IP_SPORT:
- if (invert)
- info->invflags |= EBT_IP_SPORT;
- parse_port_range(NULL, optarg, info->sport);
- info->bitmask |= EBT_IP_SPORT;
- break;
- case IP_DPORT:
- if (invert)
- info->invflags |= EBT_IP_DPORT;
- parse_port_range(NULL, optarg, info->dport);
- info->bitmask |= EBT_IP_DPORT;
- break;
- case IP_EBT_ICMP:
- if (invert)
- info->invflags |= EBT_IP_ICMP;
- ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg,
- info->icmp_type, info->icmp_code);
- info->bitmask |= EBT_IP_ICMP;
+ struct ebt_ip_info *info = cb->data;
+
+ xtables_option_parse(cb);
+
+ info->bitmask |= 1 << cb->entry->id;
+ info->invflags |= cb->invert ? 1 << cb->entry->id : 0;
+
+ switch (cb->entry->id) {
+ case O_SOURCE:
+ cb->val.haddr.all[0] &= cb->val.hmask.all[0];
+ info->saddr = cb->val.haddr.ip;
+ info->smsk = cb->val.hmask.ip;
break;
- case IP_EBT_IGMP:
- if (invert)
- info->invflags |= EBT_IP_IGMP;
- ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg,
- info->igmp_type, NULL);
- info->bitmask |= EBT_IP_IGMP;
+ case O_DEST:
+ cb->val.haddr.all[0] &= cb->val.hmask.all[0];
+ info->daddr = cb->val.haddr.ip;
+ info->dmsk = cb->val.hmask.ip;
break;
- case IP_EBT_TOS: {
- uintmax_t tosvalue;
-
- if (invert)
- info->invflags |= EBT_IP_TOS;
- if (!xtables_strtoul(optarg, NULL, &tosvalue, 0, 255))
- xtables_error(PARAMETER_PROBLEM,
- "Problem with specified IP tos");
- info->tos = tosvalue;
- info->bitmask |= EBT_IP_TOS;
- }
+ case O_ICMP:
+ ebt_parse_icmp(cb->arg, info->icmp_type, info->icmp_code);
break;
- case IP_PROTO:
- if (invert)
- info->invflags |= EBT_IP_PROTO;
- info->protocol = xtables_parse_protocol(optarg);
- info->bitmask |= EBT_IP_PROTO;
+ case O_IGMP:
+ ebt_parse_igmp(cb->arg, info->igmp_type);
break;
- default:
- return 0;
}
-
- *flags |= info->bitmask;
- return 1;
}
-static void brip_final_check(unsigned int flags)
+static void brip_final_check(struct xt_fcheck_call *fc)
{
- if (!flags)
+ if (!fc->xflags)
xtables_error(PARAMETER_PROBLEM,
"You must specify proper arguments");
}
@@ -472,35 +182,34 @@ static void brip_print(const void *ip, const struct xt_entry_match *match,
struct in_addr *addrp, *maskp;
if (info->bitmask & EBT_IP_SOURCE) {
- printf("--ip-src ");
if (info->invflags & EBT_IP_SOURCE)
printf("! ");
addrp = (struct in_addr *)&info->saddr;
maskp = (struct in_addr *)&info->smsk;
- printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
+ printf("--ip-src %s%s ",
+ xtables_ipaddr_to_numeric(addrp),
xtables_ipmask_to_numeric(maskp));
}
if (info->bitmask & EBT_IP_DEST) {
- printf("--ip-dst ");
if (info->invflags & EBT_IP_DEST)
printf("! ");
addrp = (struct in_addr *)&info->daddr;
maskp = (struct in_addr *)&info->dmsk;
- printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
+ printf("--ip-dst %s%s ",
+ xtables_ipaddr_to_numeric(addrp),
xtables_ipmask_to_numeric(maskp));
}
if (info->bitmask & EBT_IP_TOS) {
- printf("--ip-tos ");
if (info->invflags & EBT_IP_TOS)
printf("! ");
- printf("0x%02X ", info->tos);
+ printf("--ip-tos 0x%02X ", info->tos);
}
if (info->bitmask & EBT_IP_PROTO) {
struct protoent *pe;
- printf("--ip-proto ");
if (info->invflags & EBT_IP_PROTO)
printf("! ");
+ printf("--ip-proto ");
pe = getprotobynumber(info->protocol);
if (pe == NULL) {
printf("%d ", info->protocol);
@@ -509,28 +218,28 @@ static void brip_print(const void *ip, const struct xt_entry_match *match,
}
}
if (info->bitmask & EBT_IP_SPORT) {
- printf("--ip-sport ");
if (info->invflags & EBT_IP_SPORT)
printf("! ");
+ printf("--ip-sport ");
print_port_range(info->sport);
}
if (info->bitmask & EBT_IP_DPORT) {
- printf("--ip-dport ");
if (info->invflags & EBT_IP_DPORT)
printf("! ");
+ printf("--ip-dport ");
print_port_range(info->dport);
}
if (info->bitmask & EBT_IP_ICMP) {
- printf("--ip-icmp-type ");
if (info->invflags & EBT_IP_ICMP)
printf("! ");
+ printf("--ip-icmp-type ");
ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
info->icmp_type, info->icmp_code);
}
if (info->bitmask & EBT_IP_IGMP) {
- printf("--ip-igmp-type ");
if (info->invflags & EBT_IP_IGMP)
printf("! ");
+ printf("--ip-igmp-type ");
ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
info->igmp_type, NULL);
}
@@ -667,6 +376,24 @@ static void brip_xlate_nh(struct xt_xlate *xl,
xtables_ipmask_to_numeric(maskp));
}
+static bool may_skip_ether_type_dep(uint8_t flags)
+{
+ /* these convert to "ip (s|d)addr" matches */
+ if (flags & (EBT_IP_SOURCE | EBT_IP_DEST))
+ return true;
+
+ /* icmp match triggers implicit ether type dependency in nft */
+ if (flags & EBT_IP_ICMP)
+ return true;
+
+ /* allow if "ip protocol" match is created by brip_xlate() */
+ if (flags & EBT_IP_PROTO &&
+ !(flags & (EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP)))
+ return true;
+
+ return false;
+}
+
static int brip_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
@@ -676,11 +403,14 @@ static int brip_xlate(struct xt_xlate *xl,
brip_xlate_nh(xl, info, EBT_IP_SOURCE);
brip_xlate_nh(xl, info, EBT_IP_DEST);
+ if (!may_skip_ether_type_dep(info->bitmask))
+ xt_xlate_add(xl, "ether type ip ");
+
if (info->bitmask & EBT_IP_TOS) {
- xt_xlate_add(xl, "ip dscp ");
+ xt_xlate_add(xl, "@nh,8,8 ");
if (info->invflags & EBT_IP_TOS)
xt_xlate_add(xl, "!= ");
- xt_xlate_add(xl, "0x%02x ", info->tos & 0x3f); /* remove ECN bits */
+ xt_xlate_add(xl, "0x%02x ", info->tos);
}
if (info->bitmask & EBT_IP_PROTO) {
struct protoent *pe;
@@ -717,13 +447,12 @@ static struct xtables_match brip_match = {
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_ip_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_ip_info)),
- .init = brip_init,
.help = brip_print_help,
- .parse = brip_parse,
- .final_check = brip_final_check,
+ .x6_parse = brip_parse,
+ .x6_fcheck = brip_final_check,
.print = brip_print,
.xlate = brip_xlate,
- .extra_opts = brip_opts,
+ .x6_options = brip_opts,
};
void _init(void)
diff --git a/extensions/libebt_ip.t b/extensions/libebt_ip.t
index 8be5dfbb..a9b5b8b5 100644
--- a/extensions/libebt_ip.t
+++ b/extensions/libebt_ip.t
@@ -1,13 +1,33 @@
:INPUT,FORWARD,OUTPUT
--p ip --ip-src ! 192.168.0.0/24 -j ACCEPT;-p IPv4 --ip-src ! 192.168.0.0/24 -j ACCEPT;OK
+-p ip ! --ip-src 192.168.0.0/24 -j ACCEPT;-p IPv4 ! --ip-src 192.168.0.0/24 -j ACCEPT;OK
-p IPv4 --ip-dst 10.0.0.1;=;OK
+-p IPv4 ! --ip-dst 10.0.0.1;=;OK
-p IPv4 --ip-tos 0xFF;=;OK
--p IPv4 --ip-tos ! 0xFF;=;OK
+-p IPv4 ! --ip-tos 0xFF;=;OK
-p IPv4 --ip-proto tcp --ip-dport 22;=;OK
-p IPv4 --ip-proto udp --ip-sport 1024:65535;=;OK
+-p IPv4 --ip-proto udp --ip-sport :;-p IPv4 --ip-proto udp --ip-sport 0:65535;OK
+-p IPv4 --ip-proto udp --ip-sport :4;-p IPv4 --ip-proto udp --ip-sport 0:4;OK
+-p IPv4 --ip-proto udp --ip-sport 4:;-p IPv4 --ip-proto udp --ip-sport 4:65535;OK
+-p IPv4 --ip-proto udp --ip-sport 3:4;=;OK
+-p IPv4 --ip-proto udp --ip-sport 4:4;-p IPv4 --ip-proto udp --ip-sport 4;OK
+-p IPv4 --ip-proto udp --ip-sport 4:3;;FAIL
+-p IPv4 --ip-proto udp --ip-dport :;-p IPv4 --ip-proto udp --ip-dport 0:65535;OK
+-p IPv4 --ip-proto udp --ip-dport :4;-p IPv4 --ip-proto udp --ip-dport 0:4;OK
+-p IPv4 --ip-proto udp --ip-dport 4:;-p IPv4 --ip-proto udp --ip-dport 4:65535;OK
+-p IPv4 --ip-proto udp --ip-dport 3:4;=;OK
+-p IPv4 --ip-proto udp --ip-dport 4:4;-p IPv4 --ip-proto udp --ip-dport 4;OK
+-p IPv4 --ip-proto udp --ip-dport 4:3;;FAIL
-p IPv4 --ip-proto 253;=;OK
+-p IPv4 ! --ip-proto 253;=;OK
-p IPv4 --ip-proto icmp --ip-icmp-type echo-request;=;OK
-p IPv4 --ip-proto icmp --ip-icmp-type 1/1;=;OK
--p ip --ip-protocol icmp --ip-icmp-type ! 1:10;-p IPv4 --ip-proto icmp --ip-icmp-type ! 1:10/0:255 -j CONTINUE;OK
+-p ip --ip-protocol icmp ! --ip-icmp-type 1:10;-p IPv4 --ip-proto icmp ! --ip-icmp-type 1:10/0:255 -j CONTINUE;OK
--ip-proto icmp --ip-icmp-type 1/1;=;FAIL
! -p ip --ip-proto icmp --ip-icmp-type 1/1;=;FAIL
+! -p ip --ip-proto tcp --ip-sport 22 --ip-icmp-type echo-reply;;FAIL
+! -p ip --ip-proto tcp --ip-sport 22 --ip-igmp-type membership-query;;FAIL
+! -p ip --ip-proto tcp --ip-dport 22 --ip-icmp-type echo-reply;;FAIL
+! -p ip --ip-proto tcp --ip-dport 22 --ip-igmp-type membership-query;;FAIL
+! -p ip --ip-proto icmp --ip-icmp-type echo-reply --ip-igmp-type membership-query;;FAIL
+-p IPv4 --ip-proto icmp ! --ip-icmp-type echo-reply;=;OK
diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate
index b5882c34..712ba3d1 100644
--- a/extensions/libebt_ip.txlate
+++ b/extensions/libebt_ip.txlate
@@ -1,26 +1,26 @@
-ebtables-translate -A FORWARD -p ip --ip-src ! 192.168.0.0/24 -j ACCEPT
-nft add rule bridge filter FORWARD ip saddr != 192.168.0.0/24 counter accept
+ebtables-translate -A FORWARD -p ip ! --ip-src 192.168.0.0/24 -j ACCEPT
+nft 'add rule bridge filter FORWARD ip saddr != 192.168.0.0/24 counter accept'
ebtables-translate -I FORWARD -p ip --ip-dst 10.0.0.1
-nft insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter
+nft 'insert rule bridge filter FORWARD ip daddr 10.0.0.1 counter'
-ebtables-translate -I OUTPUT 3 -p ip -o eth0 --ip-tos 0xff
-nft insert rule bridge filter OUTPUT oifname "eth0" ip dscp 0x3f counter
+ebtables-translate -I OUTPUT -p ip -o eth0 --ip-tos 0xff
+nft 'insert rule bridge filter OUTPUT oifname "eth0" ether type ip @nh,8,8 0xff counter'
ebtables-translate -A FORWARD -p ip --ip-proto tcp --ip-dport 22
-nft add rule bridge filter FORWARD tcp dport 22 counter
+nft 'add rule bridge filter FORWARD ether type ip tcp dport 22 counter'
ebtables-translate -A FORWARD -p ip --ip-proto udp --ip-sport 1024:65535
-nft add rule bridge filter FORWARD udp sport 1024-65535 counter
+nft 'add rule bridge filter FORWARD ether type ip udp sport 1024-65535 counter'
ebtables-translate -A FORWARD -p ip --ip-proto 253
-nft add rule bridge filter FORWARD ip protocol 253 counter
+nft 'add rule bridge filter FORWARD ip protocol 253 counter'
ebtables-translate -A FORWARD -p ip --ip-protocol icmp --ip-icmp-type "echo-request"
-nft add rule bridge filter FORWARD icmp type 8 counter
+nft 'add rule bridge filter FORWARD icmp type 8 counter'
ebtables-translate -A FORWARD -p ip --ip-proto icmp --ip-icmp-type 1/1
-nft add rule bridge filter FORWARD icmp type 1 icmp code 1 counter
+nft 'add rule bridge filter FORWARD icmp type 1 icmp code 1 counter'
-ebtables-translate -A FORWARD -p ip --ip-protocol icmp --ip-icmp-type ! 1:10
-nft add rule bridge filter FORWARD icmp type != 1-10 counter
+ebtables-translate -A FORWARD -p ip --ip-protocol icmp ! --ip-icmp-type 1:10
+nft 'add rule bridge filter FORWARD icmp type != 1-10 counter'
diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c
index b8a5a5d8..247a99eb 100644
--- a/extensions/libebt_ip6.c
+++ b/extensions/libebt_ip6.c
@@ -18,168 +18,60 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <netdb.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_ip6.h>
#include "libxt_icmp.h"
-#define IP_SOURCE '1'
-#define IP_DEST '2'
-#define IP_TCLASS '3'
-#define IP_PROTO '4'
-#define IP_SPORT '5'
-#define IP_DPORT '6'
-#define IP_ICMP6 '7'
-
-static const struct option brip6_opts[] = {
- { .name = "ip6-source", .has_arg = true, .val = IP_SOURCE },
- { .name = "ip6-src", .has_arg = true, .val = IP_SOURCE },
- { .name = "ip6-destination", .has_arg = true, .val = IP_DEST },
- { .name = "ip6-dst", .has_arg = true, .val = IP_DEST },
- { .name = "ip6-tclass", .has_arg = true, .val = IP_TCLASS },
- { .name = "ip6-protocol", .has_arg = true, .val = IP_PROTO },
- { .name = "ip6-proto", .has_arg = true, .val = IP_PROTO },
- { .name = "ip6-source-port", .has_arg = true, .val = IP_SPORT },
- { .name = "ip6-sport", .has_arg = true, .val = IP_SPORT },
- { .name = "ip6-destination-port",.has_arg = true,.val = IP_DPORT },
- { .name = "ip6-dport", .has_arg = true, .val = IP_DPORT },
- { .name = "ip6-icmp-type", .has_arg = true, .val = IP_ICMP6 },
- XT_GETOPT_TABLEEND,
+/* must correspond to the bit position in EBT_IP6_* defines */
+enum {
+ O_SOURCE = 0,
+ O_DEST,
+ O_TCLASS,
+ O_PROTO,
+ O_SPORT,
+ O_DPORT,
+ O_ICMP6,
+ F_PORT = 1 << O_ICMP6,
+ F_ICMP6 = 1 << O_SPORT | 1 << O_DPORT,
};
-static const struct xt_icmp_names icmpv6_codes[] = {
- { "destination-unreachable", 1, 0, 0xFF },
- { "no-route", 1, 0, 0 },
- { "communication-prohibited", 1, 1, 1 },
- { "address-unreachable", 1, 3, 3 },
- { "port-unreachable", 1, 4, 4 },
-
- { "packet-too-big", 2, 0, 0xFF },
-
- { "time-exceeded", 3, 0, 0xFF },
- /* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
- { "ttl-zero-during-transit", 3, 0, 0 },
- { "ttl-zero-during-reassembly", 3, 1, 1 },
-
- { "parameter-problem", 4, 0, 0xFF },
- { "bad-header", 4, 0, 0 },
- { "unknown-header-type", 4, 1, 1 },
- { "unknown-option", 4, 2, 2 },
-
- { "echo-request", 128, 0, 0xFF },
- /* Alias */ { "ping", 128, 0, 0xFF },
-
- { "echo-reply", 129, 0, 0xFF },
- /* Alias */ { "pong", 129, 0, 0xFF },
-
- { "router-solicitation", 133, 0, 0xFF },
-
- { "router-advertisement", 134, 0, 0xFF },
-
- { "neighbour-solicitation", 135, 0, 0xFF },
- /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
-
- { "neighbour-advertisement", 136, 0, 0xFF },
- /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
-
- { "redirect", 137, 0, 0xFF },
+static const struct xt_option_entry brip6_opts[] = {
+ { .name = "ip6-source", .id = O_SOURCE, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip6-src", .id = O_SOURCE, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip6-destination", .id = O_DEST, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip6-dst", .id = O_DEST, .type = XTTYPE_HOSTMASK,
+ .flags = XTOPT_INVERT },
+ { .name = "ip6-tclass", .id = O_TCLASS, .type = XTTYPE_UINT8,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip6_info, tclass) },
+ { .name = "ip6-protocol", .id = O_PROTO, .type = XTTYPE_PROTOCOL,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip6_info, protocol) },
+ { .name = "ip6-proto", .id = O_PROTO, .type = XTTYPE_PROTOCOL,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip6_info, protocol) },
+ { .name = "ip6-source-port", .id = O_SPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip6_info, sport) },
+ { .name = "ip6-sport", .id = O_SPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip6_info, sport) },
+ { .name = "ip6-destination-port",.id = O_DPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip6_info, dport) },
+ { .name = "ip6-dport", .id = O_DPORT, .type = XTTYPE_PORTRC,
+ .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_ip6_info, dport) },
+ { .name = "ip6-icmp-type", .id = O_ICMP6, .type = XTTYPE_STRING,
+ .excl = F_ICMP6, .flags = XTOPT_INVERT },
+ XTOPT_TABLEEND,
};
-static void
-parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
-{
- char *buffer;
- char *cp;
-
- buffer = strdup(portstring);
- if ((cp = strchr(buffer, ':')) == NULL)
- ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
- else {
- *cp = '\0';
- cp++;
-
- ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0;
- ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF;
-
- if (ports[0] > ports[1])
- xtables_error(PARAMETER_PROBLEM,
- "invalid portrange (min > max)");
- }
- free(buffer);
-}
-
-static char *parse_range(const char *str, unsigned int res[])
-{
- char *next;
-
- if (!xtables_strtoui(str, &next, &res[0], 0, 255))
- return NULL;
-
- res[1] = res[0];
- if (*next == ':') {
- str = next + 1;
- if (!xtables_strtoui(str, &next, &res[1], 0, 255))
- return NULL;
- }
-
- return next;
-}
-
-static int
-parse_icmpv6(const char *icmpv6type, uint8_t type[], uint8_t code[])
-{
- static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
- unsigned int match = limit;
- unsigned int i, number[2];
-
- for (i = 0; i < limit; i++) {
- if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)))
- continue;
- if (match != limit)
- xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMPv6 type `%s':"
- " `%s' or `%s'?",
- icmpv6type, icmpv6_codes[match].name,
- icmpv6_codes[i].name);
- match = i;
- }
-
- if (match < limit) {
- type[0] = type[1] = icmpv6_codes[match].type;
- code[0] = icmpv6_codes[match].code_min;
- code[1] = icmpv6_codes[match].code_max;
- } else {
- char *next = parse_range(icmpv6type, number);
- if (!next) {
- xtables_error(PARAMETER_PROBLEM, "Unknown ICMPv6 type `%s'",
- icmpv6type);
- return -1;
- }
- type[0] = (uint8_t) number[0];
- type[1] = (uint8_t) number[1];
- switch (*next) {
- case 0:
- code[0] = 0;
- code[1] = 255;
- return 0;
- case '/':
- next = parse_range(next+1, number);
- code[0] = (uint8_t) number[0];
- code[1] = (uint8_t) number[1];
- if (next == NULL)
- return -1;
- if (next && *next == 0)
- return 0;
- /* fallthrough */
- default:
- xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next);
- return -1;
- }
- }
- return 0;
-}
-
static void print_port_range(uint16_t *ports)
{
if (ports[0] == ports[1])
@@ -224,171 +116,53 @@ static void brip6_print_help(void)
{
printf(
"ip6 options:\n"
-"--ip6-src [!] address[/mask]: ipv6 source specification\n"
-"--ip6-dst [!] address[/mask]: ipv6 destination specification\n"
-"--ip6-tclass [!] tclass : ipv6 traffic class specification\n"
-"--ip6-proto [!] protocol : ipv6 protocol specification\n"
-"--ip6-sport [!] port[:port] : tcp/udp source port or port range\n"
-"--ip6-dport [!] port[:port] : tcp/udp destination port or port range\n"
-"--ip6-icmp-type [!] type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n");
+"[!] --ip6-src address[/mask]: ipv6 source specification\n"
+"[!] --ip6-dst address[/mask]: ipv6 destination specification\n"
+"[!] --ip6-tclass tclass : ipv6 traffic class specification\n"
+"[!] --ip6-proto protocol : ipv6 protocol specification\n"
+"[!] --ip6-sport port[:port] : tcp/udp source port or port range\n"
+"[!] --ip6-dport port[:port] : tcp/udp destination port or port range\n"
+"[!] --ip6-icmp-type type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n");
printf("Valid ICMPv6 Types:");
xt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes));
}
-static void brip6_init(struct xt_entry_match *match)
-{
- struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
-
- ipinfo->invflags = 0;
- ipinfo->bitmask = 0;
- memset(ipinfo->saddr.s6_addr, 0, sizeof(ipinfo->saddr.s6_addr));
- memset(ipinfo->smsk.s6_addr, 0, sizeof(ipinfo->smsk.s6_addr));
- memset(ipinfo->daddr.s6_addr, 0, sizeof(ipinfo->daddr.s6_addr));
- memset(ipinfo->dmsk.s6_addr, 0, sizeof(ipinfo->dmsk.s6_addr));
-}
-
-static struct in6_addr *numeric_to_addr(const char *num)
+static void brip6_parse(struct xt_option_call *cb)
{
- static struct in6_addr ap;
- int err;
-
- if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
- return &ap;
- return (struct in6_addr *)NULL;
-}
-
-static struct in6_addr *parse_ip6_mask(char *mask)
-{
- static struct in6_addr maskaddr;
- struct in6_addr *addrp;
- unsigned int bits;
-
- if (mask == NULL) {
- /* no mask at all defaults to 128 bits */
- memset(&maskaddr, 0xff, sizeof maskaddr);
- return &maskaddr;
- }
- if ((addrp = numeric_to_addr(mask)) != NULL)
- return addrp;
- if (!xtables_strtoui(mask, NULL, &bits, 0, 128))
- xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Mask '%s' specified", mask);
- if (bits != 0) {
- char *p = (char *)&maskaddr;
- memset(p, 0xff, bits / 8);
- memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
- p[bits / 8] = 0xff << (8 - (bits & 7));
- return &maskaddr;
- }
-
- memset(&maskaddr, 0, sizeof maskaddr);
- return &maskaddr;
-}
-
-/* Set the ipv6 mask and address. Callers should check ebt_errormsg[0].
- * The string pointed to by address can be altered. */
-static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct in6_addr *msk)
-{
- struct in6_addr *tmp_addr;
- char buf[256];
- char *p;
- int i;
- int err;
-
- strncpy(buf, address, sizeof(buf) - 1);
- /* first the mask */
- buf[sizeof(buf) - 1] = '\0';
- if ((p = strrchr(buf, '/')) != NULL) {
- *p = '\0';
- tmp_addr = parse_ip6_mask(p + 1);
- } else
- tmp_addr = parse_ip6_mask(NULL);
-
- *msk = *tmp_addr;
-
- /* if a null mask is given, the name is ignored, like in "any/0" */
- if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any)))
- strcpy(buf, "::");
-
- if ((err=inet_pton(AF_INET6, buf, addr)) < 1) {
- xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Address '%s' specified", buf);
- return;
- }
-
- for (i = 0; i < 4; i++)
- addr->s6_addr32[i] &= msk->s6_addr32[i];
-}
-
-#define OPT_SOURCE 0x01
-#define OPT_DEST 0x02
-#define OPT_TCLASS 0x04
-#define OPT_PROTO 0x08
-#define OPT_SPORT 0x10
-#define OPT_DPORT 0x20
-static int
-brip6_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
-{
- struct ebt_ip6_info *info = (struct ebt_ip6_info *)(*match)->data;
+ struct ebt_ip6_info *info = cb->data;
unsigned int i;
- char *end;
-
- switch (c) {
- case IP_SOURCE:
- if (invert)
- info->invflags |= EBT_IP6_SOURCE;
- ebt_parse_ip6_address(optarg, &info->saddr, &info->smsk);
- info->bitmask |= EBT_IP6_SOURCE;
- break;
- case IP_DEST:
- if (invert)
- info->invflags |= EBT_IP6_DEST;
- ebt_parse_ip6_address(optarg, &info->daddr, &info->dmsk);
- info->bitmask |= EBT_IP6_DEST;
- break;
- case IP_SPORT:
- if (invert)
- info->invflags |= EBT_IP6_SPORT;
- parse_port_range(NULL, optarg, info->sport);
- info->bitmask |= EBT_IP6_SPORT;
- break;
- case IP_DPORT:
- if (invert)
- info->invflags |= EBT_IP6_DPORT;
- parse_port_range(NULL, optarg, info->dport);
- info->bitmask |= EBT_IP6_DPORT;
- break;
- case IP_ICMP6:
- if (invert)
- info->invflags |= EBT_IP6_ICMP6;
- if (parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code))
- return 0;
- info->bitmask |= EBT_IP6_ICMP6;
+
+ /* XXX: overriding afinfo family is dangerous, but
+ * required for XTTYPE_HOSTMASK parsing */
+ xtables_set_nfproto(NFPROTO_IPV6);
+ xtables_option_parse(cb);
+ xtables_set_nfproto(NFPROTO_BRIDGE);
+
+ info->bitmask |= 1 << cb->entry->id;
+ info->invflags |= cb->invert ? 1 << cb->entry->id : 0;
+
+ switch (cb->entry->id) {
+ case O_SOURCE:
+ for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++)
+ cb->val.haddr.all[i] &= cb->val.hmask.all[i];
+ info->saddr = cb->val.haddr.in6;
+ info->smsk = cb->val.hmask.in6;
break;
- case IP_TCLASS:
- if (invert)
- info->invflags |= EBT_IP6_TCLASS;
- if (!xtables_strtoui(optarg, &end, &i, 0, 255))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified IPv6 traffic class '%s'", optarg);
- info->tclass = i;
- info->bitmask |= EBT_IP6_TCLASS;
+ case O_DEST:
+ for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++)
+ cb->val.haddr.all[i] &= cb->val.hmask.all[i];
+ info->daddr = cb->val.haddr.in6;
+ info->dmsk = cb->val.hmask.in6;
break;
- case IP_PROTO:
- if (invert)
- info->invflags |= EBT_IP6_PROTO;
- info->protocol = xtables_parse_protocol(optarg);
- info->bitmask |= EBT_IP6_PROTO;
+ case O_ICMP6:
+ ebt_parse_icmpv6(cb->arg, info->icmpv6_type, info->icmpv6_code);
break;
- default:
- return 0;
}
-
- *flags |= info->bitmask;
- return 1;
}
-static void brip6_final_check(unsigned int flags)
+static void brip6_final_check(struct xt_fcheck_call *fc)
{
- if (!flags)
+ if (!fc->xflags)
xtables_error(PARAMETER_PROBLEM,
"You must specify proper arguments");
}
@@ -399,31 +173,30 @@ static void brip6_print(const void *ip, const struct xt_entry_match *match,
struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
if (ipinfo->bitmask & EBT_IP6_SOURCE) {
- printf("--ip6-src ");
if (ipinfo->invflags & EBT_IP6_SOURCE)
printf("! ");
+ printf("--ip6-src ");
printf("%s", xtables_ip6addr_to_numeric(&ipinfo->saddr));
printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->smsk));
}
if (ipinfo->bitmask & EBT_IP6_DEST) {
- printf("--ip6-dst ");
if (ipinfo->invflags & EBT_IP6_DEST)
printf("! ");
+ printf("--ip6-dst ");
printf("%s", xtables_ip6addr_to_numeric(&ipinfo->daddr));
printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->dmsk));
}
if (ipinfo->bitmask & EBT_IP6_TCLASS) {
- printf("--ip6-tclass ");
if (ipinfo->invflags & EBT_IP6_TCLASS)
printf("! ");
- printf("0x%02X ", ipinfo->tclass);
+ printf("--ip6-tclass 0x%02X ", ipinfo->tclass);
}
if (ipinfo->bitmask & EBT_IP6_PROTO) {
struct protoent *pe;
- printf("--ip6-proto ");
if (ipinfo->invflags & EBT_IP6_PROTO)
printf("! ");
+ printf("--ip6-proto ");
pe = getprotobynumber(ipinfo->protocol);
if (pe == NULL) {
printf("%d ", ipinfo->protocol);
@@ -432,21 +205,21 @@ static void brip6_print(const void *ip, const struct xt_entry_match *match,
}
}
if (ipinfo->bitmask & EBT_IP6_SPORT) {
- printf("--ip6-sport ");
if (ipinfo->invflags & EBT_IP6_SPORT)
printf("! ");
+ printf("--ip6-sport ");
print_port_range(ipinfo->sport);
}
if (ipinfo->bitmask & EBT_IP6_DPORT) {
- printf("--ip6-dport ");
if (ipinfo->invflags & EBT_IP6_DPORT)
printf("! ");
+ printf("--ip6-dport ");
print_port_range(ipinfo->dport);
}
if (ipinfo->bitmask & EBT_IP6_ICMP6) {
- printf("--ip6-icmp-type ");
if (ipinfo->invflags & EBT_IP6_ICMP6)
printf("! ");
+ printf("--ip6-icmp-type ");
print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
}
}
@@ -617,13 +390,12 @@ static struct xtables_match brip6_match = {
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_ip6_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_ip6_info)),
- .init = brip6_init,
.help = brip6_print_help,
- .parse = brip6_parse,
- .final_check = brip6_final_check,
+ .x6_parse = brip6_parse,
+ .x6_fcheck = brip6_final_check,
.print = brip6_print,
.xlate = brip6_xlate,
- .extra_opts = brip6_opts,
+ .x6_options = brip6_opts,
};
void _init(void)
diff --git a/extensions/libebt_ip6.t b/extensions/libebt_ip6.t
index fa1038af..cb1be9e3 100644
--- a/extensions/libebt_ip6.t
+++ b/extensions/libebt_ip6.t
@@ -1,15 +1,35 @@
:INPUT,FORWARD,OUTPUT
--p ip6 --ip6-src ! dead::beef/64 -j ACCEPT;-p IPv6 --ip6-src ! dead::/64 -j ACCEPT;OK
+-p ip6 ! --ip6-src dead::beef/64 -j ACCEPT;-p IPv6 ! --ip6-src dead::/64 -j ACCEPT;OK
-p IPv6 --ip6-dst dead:beef::/64 -j ACCEPT;=;OK
-p IPv6 --ip6-dst f00:ba::;=;OK
+-p IPv6 ! --ip6-dst f00:ba::;=;OK
+-p IPv6 --ip6-src 10.0.0.1;;FAIL
-p IPv6 --ip6-tclass 0xFF;=;OK
+-p IPv6 ! --ip6-tclass 0xFF;=;OK
-p IPv6 --ip6-proto tcp --ip6-dport 22;=;OK
--p IPv6 --ip6-proto tcp --ip6-dport ! 22;=;OK
+-p IPv6 --ip6-proto tcp ! --ip6-dport 22;=;OK
+-p IPv6 --ip6-proto tcp ! --ip6-sport 22 --ip6-dport 22;=;OK
-p IPv6 --ip6-proto udp --ip6-sport 1024:65535;=;OK
+-p IPv6 --ip6-proto udp --ip6-sport :;-p IPv6 --ip6-proto udp --ip6-sport 0:65535;OK
+-p IPv6 --ip6-proto udp --ip6-sport :4;-p IPv6 --ip6-proto udp --ip6-sport 0:4;OK
+-p IPv6 --ip6-proto udp --ip6-sport 4:;-p IPv6 --ip6-proto udp --ip6-sport 4:65535;OK
+-p IPv6 --ip6-proto udp --ip6-sport 3:4;=;OK
+-p IPv6 --ip6-proto udp --ip6-sport 4:4;-p IPv6 --ip6-proto udp --ip6-sport 4;OK
+-p IPv6 --ip6-proto udp --ip6-sport 4:3;;FAIL
+-p IPv6 --ip6-proto udp --ip6-dport :;-p IPv6 --ip6-proto udp --ip6-dport 0:65535;OK
+-p IPv6 --ip6-proto udp --ip6-dport :4;-p IPv6 --ip6-proto udp --ip6-dport 0:4;OK
+-p IPv6 --ip6-proto udp --ip6-dport 4:;-p IPv6 --ip6-proto udp --ip6-dport 4:65535;OK
+-p IPv6 --ip6-proto udp --ip6-dport 3:4;=;OK
+-p IPv6 --ip6-proto udp --ip6-dport 4:4;-p IPv6 --ip6-proto udp --ip6-dport 4;OK
+-p IPv6 --ip6-proto udp --ip6-dport 4:3;;FAIL
-p IPv6 --ip6-proto 253;=;OK
+-p IPv6 ! --ip6-proto 253;=;OK
-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type echo-request -j CONTINUE;=;OK
-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type echo-request;=;OK
+-p IPv6 --ip6-proto ipv6-icmp ! --ip6-icmp-type echo-request;=;OK
-p ip6 --ip6-protocol icmpv6 --ip6-icmp-type 1/1;-p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type communication-prohibited -j CONTINUE;OK
--p IPv6 --ip6-proto ipv6-icmp --ip6-icmp-type ! 1:10/0:255;=;OK
+-p IPv6 --ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;OK
--ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;FAIL
! -p IPv6 --ip6-proto ipv6-icmp ! --ip6-icmp-type 1:10/0:255;=;FAIL
+-p IPv6 --ip6-proto tcp --ip6-sport 22 --ip6-icmp-type echo-request;;FAIL
+-p IPv6 --ip6-proto tcp --ip6-dport 22 --ip6-icmp-type echo-request;;FAIL
diff --git a/extensions/libebt_ip6.txlate b/extensions/libebt_ip6.txlate
index 0271734c..13d57e3a 100644
--- a/extensions/libebt_ip6.txlate
+++ b/extensions/libebt_ip6.txlate
@@ -1,29 +1,29 @@
ebtables-translate -A FORWARD -p ip6 --ip6-src ! dead::beef/64 -j ACCEPT
-nft add rule bridge filter FORWARD ip6 saddr != dead::/64 counter accept
+nft 'add rule bridge filter FORWARD ip6 saddr != dead::/64 counter accept'
ebtables-translate -A FORWARD -p ip6 ! --ip6-dst dead:beef::/64 -j ACCEPT
-nft add rule bridge filter FORWARD ip6 daddr != dead:beef::/64 counter accept
+nft 'add rule bridge filter FORWARD ip6 daddr != dead:beef::/64 counter accept'
ebtables-translate -I FORWARD -p ip6 --ip6-dst f00:ba::
-nft insert rule bridge filter FORWARD ip6 daddr f00:ba:: counter
+nft 'insert rule bridge filter FORWARD ip6 daddr f00:ba:: counter'
ebtables-translate -I OUTPUT -o eth0 -p ip6 --ip6-tclass 0xff
-nft insert rule bridge filter OUTPUT oifname "eth0" ip6 dscp 0x3f counter
+nft 'insert rule bridge filter OUTPUT oifname "eth0" ip6 dscp 0x3f counter'
ebtables-translate -A FORWARD -p ip6 --ip6-proto tcp --ip6-dport 22
-nft add rule bridge filter FORWARD ether type ip6 tcp dport 22 counter
+nft 'add rule bridge filter FORWARD ether type ip6 tcp dport 22 counter'
ebtables-translate -A FORWARD -p ip6 --ip6-proto udp --ip6-sport 1024:65535
-nft add rule bridge filter FORWARD ether type ip6 udp sport 1024-65535 counter
+nft 'add rule bridge filter FORWARD ether type ip6 udp sport 1024-65535 counter'
ebtables-translate -A FORWARD -p ip6 --ip6-proto 253
-nft add rule bridge filter FORWARD ether type ip6 meta l4proto 253 counter
+nft 'add rule bridge filter FORWARD ether type ip6 meta l4proto 253 counter'
ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type "echo-request"
-nft add rule bridge filter FORWARD icmpv6 type 128 counter
+nft 'add rule bridge filter FORWARD icmpv6 type 128 counter'
ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type 1/1
-nft add rule bridge filter FORWARD icmpv6 type 1 icmpv6 code 1 counter
+nft 'add rule bridge filter FORWARD icmpv6 type 1 icmpv6 code 1 counter'
-ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 --ip6-icmp-type ! 1:10
-nft add rule bridge filter FORWARD icmpv6 type != 1-10 counter
+ebtables-translate -A FORWARD -p ip6 --ip6-protocol icmpv6 ! --ip6-icmp-type 1:10
+nft 'add rule bridge filter FORWARD icmpv6 type != 1-10 counter'
diff --git a/extensions/libebt_limit.txlate b/extensions/libebt_limit.txlate
index b6af15d5..adcce3ed 100644
--- a/extensions/libebt_limit.txlate
+++ b/extensions/libebt_limit.txlate
@@ -1,8 +1,8 @@
ebtables-translate -A INPUT --limit 3/m --limit-burst 3
-nft add rule bridge filter INPUT limit rate 3/minute burst 3 packets counter
+nft 'add rule bridge filter INPUT limit rate 3/minute burst 3 packets counter'
ebtables-translate -A INPUT --limit 10/s --limit-burst 5
-nft add rule bridge filter INPUT limit rate 10/second burst 5 packets counter
+nft 'add rule bridge filter INPUT limit rate 10/second burst 5 packets counter'
ebtables-translate -A INPUT --limit 10/s --limit-burst 0
-nft add rule bridge filter INPUT limit rate 10/second counter
+nft 'add rule bridge filter INPUT limit rate 10/second counter'
diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c
index 8858cf0e..dc2357c0 100644
--- a/extensions/libebt_log.c
+++ b/extensions/libebt_log.c
@@ -14,19 +14,11 @@
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
-#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_log.h>
#define LOG_DEFAULT_LEVEL LOG_INFO
-#define LOG_PREFIX '1'
-#define LOG_LEVEL '2'
-#define LOG_ARP '3'
-#define LOG_IP '4'
-#define LOG_LOG '5'
-#define LOG_IP6 '6'
-
struct code {
char *c_name;
int c_val;
@@ -43,26 +35,26 @@ static struct code eight_priority[] = {
{ "debug", LOG_DEBUG }
};
-static int name_to_loglevel(const char *arg)
-{
- int i;
-
- for (i = 0; i < 8; i++)
- if (!strcmp(arg, eight_priority[i].c_name))
- return eight_priority[i].c_val;
-
- /* return bad loglevel */
- return 9;
-}
+enum {
+ /* first three must correspond with bit pos in respective EBT_LOG_* */
+ O_LOG_IP = 0,
+ O_LOG_ARP = 1,
+ O_LOG_IP6 = 3,
+ O_LOG_PREFIX,
+ O_LOG_LEVEL,
+ O_LOG_LOG,
+};
-static const struct option brlog_opts[] = {
- { .name = "log-prefix", .has_arg = true, .val = LOG_PREFIX },
- { .name = "log-level", .has_arg = true, .val = LOG_LEVEL },
- { .name = "log-arp", .has_arg = false, .val = LOG_ARP },
- { .name = "log-ip", .has_arg = false, .val = LOG_IP },
- { .name = "log", .has_arg = false, .val = LOG_LOG },
- { .name = "log-ip6", .has_arg = false, .val = LOG_IP6 },
- XT_GETOPT_TABLEEND,
+static const struct xt_option_entry brlog_opts[] = {
+ { .name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_log_info, prefix) },
+ { .name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_log_info, loglevel) },
+ { .name = "log-arp", .id = O_LOG_ARP, .type = XTTYPE_NONE },
+ { .name = "log-ip", .id = O_LOG_IP, .type = XTTYPE_NONE },
+ { .name = "log", .id = O_LOG_LOG, .type = XTTYPE_NONE },
+ { .name = "log-ip6", .id = O_LOG_IP6, .type = XTTYPE_NONE },
+ XTOPT_TABLEEND,
};
static void brlog_help(void)
@@ -87,73 +79,21 @@ static void brlog_init(struct xt_entry_target *t)
{
struct ebt_log_info *loginfo = (struct ebt_log_info *)t->data;
- loginfo->bitmask = 0;
- loginfo->prefix[0] = '\0';
loginfo->loglevel = LOG_NOTICE;
}
-static unsigned int log_chk_inv(int inv, unsigned int bit, const char *suffix)
-{
- if (inv)
- xtables_error(PARAMETER_PROBLEM,
- "Unexpected `!' after --log%s", suffix);
- return bit;
-}
-
-static int brlog_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
+static void brlog_parse(struct xt_option_call *cb)
{
- struct ebt_log_info *loginfo = (struct ebt_log_info *)(*target)->data;
- long int i;
- char *end;
-
- switch (c) {
- case LOG_PREFIX:
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "Unexpected `!` after --log-prefix");
- if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
- xtables_error(PARAMETER_PROBLEM,
- "Prefix too long");
- if (strchr(optarg, '\"'))
- xtables_error(PARAMETER_PROBLEM,
- "Use of \\\" is not allowed"
- " in the prefix");
- strcpy((char *)loginfo->prefix, (char *)optarg);
- break;
- case LOG_LEVEL:
- i = strtol(optarg, &end, 16);
- if (*end != '\0' || i < 0 || i > 7)
- loginfo->loglevel = name_to_loglevel(optarg);
- else
- loginfo->loglevel = i;
-
- if (loginfo->loglevel == 9)
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the log-level");
+ struct ebt_log_info *loginfo = cb->data;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_LOG_IP:
+ case O_LOG_ARP:
+ case O_LOG_IP6:
+ loginfo->bitmask |= 1 << cb->entry->id;
break;
- case LOG_IP:
- loginfo->bitmask |= log_chk_inv(invert, EBT_LOG_IP, "-ip");
- break;
- case LOG_ARP:
- loginfo->bitmask |= log_chk_inv(invert, EBT_LOG_ARP, "-arp");
- break;
- case LOG_LOG:
- loginfo->bitmask |= log_chk_inv(invert, 0, "");
- break;
- case LOG_IP6:
- loginfo->bitmask |= log_chk_inv(invert, EBT_LOG_IP6, "-ip6");
- break;
- default:
- return 0;
}
-
- *flags |= loginfo->bitmask;
- return 1;
-}
-
-static void brlog_final_check(unsigned int flags)
-{
}
static void brlog_print(const void *ip, const struct xt_entry_target *target,
@@ -161,9 +101,10 @@ static void brlog_print(const void *ip, const struct xt_entry_target *target,
{
struct ebt_log_info *loginfo = (struct ebt_log_info *)target->data;
- printf("--log-level %s --log-prefix \"%s\"",
- eight_priority[loginfo->loglevel].c_name,
- loginfo->prefix);
+ printf("--log-level %s", eight_priority[loginfo->loglevel].c_name);
+
+ if (loginfo->prefix[0])
+ printf(" --log-prefix \"%s\"", loginfo->prefix);
if (loginfo->bitmask & EBT_LOG_IP)
printf(" --log-ip");
@@ -180,16 +121,14 @@ static int brlog_xlate(struct xt_xlate *xl,
const struct ebt_log_info *loginfo = (const void *)params->target->data;
xt_xlate_add(xl, "log");
- if (loginfo->prefix[0]) {
- if (params->escape_quotes)
- xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix);
- else
- xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
- }
+ if (loginfo->prefix[0])
+ xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
if (loginfo->loglevel != LOG_DEFAULT_LEVEL)
xt_xlate_add(xl, " level %s", eight_priority[loginfo->loglevel].c_name);
+ /* ebt_log always decodes MAC header, nft_log always decodes upper header -
+ * so set flags ether and ignore EBT_LOG_IP, EBT_LOG_ARP and EBT_LOG_IP6 */
xt_xlate_add(xl, " flags ether ");
return 1;
@@ -198,17 +137,17 @@ static int brlog_xlate(struct xt_xlate *xl,
static struct xtables_target brlog_target = {
.name = "log",
.revision = 0,
+ .ext_flags = XTABLES_EXT_WATCHER,
.version = XTABLES_VERSION,
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_log_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_log_info)),
.init = brlog_init,
.help = brlog_help,
- .parse = brlog_parse,
- .final_check = brlog_final_check,
+ .x6_parse = brlog_parse,
.print = brlog_print,
.xlate = brlog_xlate,
- .extra_opts = brlog_opts,
+ .x6_options = brlog_opts,
};
void _init(void)
diff --git a/extensions/libebt_log.t b/extensions/libebt_log.t
index a0df6169..e6adbd3b 100644
--- a/extensions/libebt_log.t
+++ b/extensions/libebt_log.t
@@ -1,6 +1,6 @@
:INPUT,FORWARD,OUTPUT
---log;=;OK
+--log;--log-level notice;OK
--log-level crit;=;OK
---log-level 1;--log-level alert --log-prefix "";OK
---log-level emerg --log-ip --log-arp --log-ip6;--log-level emerg --log-prefix "" --log-ip --log-arp --log-ip6 -j CONTINUE;OK
+--log-level 1;--log-level alert;OK
+--log-level emerg --log-ip --log-arp --log-ip6;=;OK
--log-level crit --log-ip --log-arp --log-ip6 --log-prefix foo;--log-level crit --log-prefix "foo" --log-ip --log-arp --log-ip6 -j CONTINUE;OK
diff --git a/extensions/libebt_log.txlate b/extensions/libebt_log.txlate
index 7ef8d5e1..9847e4c1 100644
--- a/extensions/libebt_log.txlate
+++ b/extensions/libebt_log.txlate
@@ -1,15 +1,15 @@
ebtables-translate -A INPUT --log
-nft add rule bridge filter INPUT log level notice flags ether counter
+nft 'add rule bridge filter INPUT log level notice flags ether counter'
ebtables-translate -A INPUT --log-level 1
-nft add rule bridge filter INPUT log level alert flags ether counter
+nft 'add rule bridge filter INPUT log level alert flags ether counter'
ebtables-translate -A INPUT --log-level crit
-nft add rule bridge filter INPUT log level crit flags ether counter
+nft 'add rule bridge filter INPUT log level crit flags ether counter'
ebtables-translate -A INPUT --log-level emerg --log-ip --log-arp --log-ip6
-nft add rule bridge filter INPUT log level emerg flags ether counter
+nft 'add rule bridge filter INPUT log level emerg flags ether counter'
ebtables-translate -A INPUT --log-level crit --log-ip --log-arp --log-ip6 --log-prefix foo
-nft add rule bridge filter INPUT log prefix "foo" level crit flags ether counter
+nft 'add rule bridge filter INPUT log prefix "foo" level crit flags ether counter'
diff --git a/extensions/libebt_mark.c b/extensions/libebt_mark.c
index 423c5c91..0dc598fe 100644
--- a/extensions/libebt_mark.c
+++ b/extensions/libebt_mark.c
@@ -12,27 +12,39 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_mark_t.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define MARK_TARGET '1'
-#define MARK_SETMARK '2'
-#define MARK_ORMARK '3'
-#define MARK_ANDMARK '4'
-#define MARK_XORMARK '5'
-static const struct option brmark_opts[] = {
- { .name = "mark-target",.has_arg = true, .val = MARK_TARGET },
+enum {
+ O_SET_MARK = 0,
+ O_AND_MARK,
+ O_OR_MARK,
+ O_XOR_MARK,
+ O_MARK_TARGET,
+ F_SET_MARK = 1 << O_SET_MARK,
+ F_AND_MARK = 1 << O_AND_MARK,
+ F_OR_MARK = 1 << O_OR_MARK,
+ F_XOR_MARK = 1 << O_XOR_MARK,
+ F_ANY = F_SET_MARK | F_AND_MARK | F_OR_MARK | F_XOR_MARK,
+};
+
+static const struct xt_option_entry brmark_opts[] = {
+ { .name = "mark-target",.id = O_MARK_TARGET, .type = XTTYPE_STRING },
/* an oldtime messup, we should have always used the scheme
* <extension-name>-<option> */
- { .name = "set-mark", .has_arg = true, .val = MARK_SETMARK },
- { .name = "mark-set", .has_arg = true, .val = MARK_SETMARK },
- { .name = "mark-or", .has_arg = true, .val = MARK_ORMARK },
- { .name = "mark-and", .has_arg = true, .val = MARK_ANDMARK },
- { .name = "mark-xor", .has_arg = true, .val = MARK_XORMARK },
- XT_GETOPT_TABLEEND,
+ { .name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_UINT32,
+ .excl = F_ANY },
+ { .name = "mark-set", .id = O_SET_MARK, .type = XTTYPE_UINT32,
+ .excl = F_ANY },
+ { .name = "mark-or", .id = O_OR_MARK, .type = XTTYPE_UINT32,
+ .excl = F_ANY },
+ { .name = "mark-and", .id = O_AND_MARK, .type = XTTYPE_UINT32,
+ .excl = F_ANY },
+ { .name = "mark-xor", .id = O_XOR_MARK, .type = XTTYPE_UINT32,
+ .excl = F_ANY },
+ XTOPT_TABLEEND,
};
static void brmark_print_help(void)
@@ -54,83 +66,39 @@ static void brmark_init(struct xt_entry_target *target)
info->mark = 0;
}
-#define OPT_MARK_TARGET 0x01
-#define OPT_MARK_SETMARK 0x02
-#define OPT_MARK_ORMARK 0x04
-#define OPT_MARK_ANDMARK 0x08
-#define OPT_MARK_XORMARK 0x10
-
-static int
-brmark_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
+static void brmark_parse(struct xt_option_call *cb)
{
- struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)
- (*target)->data;
- char *end;
- uint32_t mask;
-
- switch (c) {
- case MARK_TARGET:
- { unsigned int tmp;
- EBT_CHECK_OPTION(flags, OPT_MARK_TARGET);
- if (ebt_fill_target(optarg, &tmp))
+ static const unsigned long target_orval[] = {
+ [O_SET_MARK] = MARK_SET_VALUE,
+ [O_AND_MARK] = MARK_AND_VALUE,
+ [O_OR_MARK] = MARK_OR_VALUE,
+ [O_XOR_MARK] = MARK_XOR_VALUE,
+ };
+ struct ebt_mark_t_info *info = cb->data;
+ unsigned int tmp;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_MARK_TARGET:
+ if (ebt_fill_target(cb->arg, &tmp))
xtables_error(PARAMETER_PROBLEM,
"Illegal --mark-target target");
/* the 4 lsb are left to designate the target */
info->target = (info->target & ~EBT_VERDICT_BITS) |
(tmp & EBT_VERDICT_BITS);
- }
- return 1;
- case MARK_SETMARK:
- EBT_CHECK_OPTION(flags, OPT_MARK_SETMARK);
- mask = (OPT_MARK_ORMARK|OPT_MARK_ANDMARK|OPT_MARK_XORMARK);
- if (*flags & mask)
- xtables_error(PARAMETER_PROBLEM,
- "--mark-set cannot be used together with"
- " specific --mark option");
- info->target = (info->target & EBT_VERDICT_BITS) |
- MARK_SET_VALUE;
- break;
- case MARK_ORMARK:
- EBT_CHECK_OPTION(flags, OPT_MARK_ORMARK);
- mask = (OPT_MARK_SETMARK|OPT_MARK_ANDMARK|OPT_MARK_XORMARK);
- if (*flags & mask)
- xtables_error(PARAMETER_PROBLEM,
- "--mark-or cannot be used together with"
- " specific --mark option");
- info->target = (info->target & EBT_VERDICT_BITS) |
- MARK_OR_VALUE;
- break;
- case MARK_ANDMARK:
- EBT_CHECK_OPTION(flags, OPT_MARK_ANDMARK);
- mask = (OPT_MARK_SETMARK|OPT_MARK_ORMARK|OPT_MARK_XORMARK);
- if (*flags & mask)
- xtables_error(PARAMETER_PROBLEM,
- "--mark-and cannot be used together with"
- " specific --mark option");
- info->target = (info->target & EBT_VERDICT_BITS) |
- MARK_AND_VALUE;
- break;
- case MARK_XORMARK:
- EBT_CHECK_OPTION(flags, OPT_MARK_XORMARK);
- mask = (OPT_MARK_SETMARK|OPT_MARK_ANDMARK|OPT_MARK_ORMARK);
- if (*flags & mask)
- xtables_error(PARAMETER_PROBLEM,
- "--mark-xor cannot be used together with"
- " specific --mark option");
- info->target = (info->target & EBT_VERDICT_BITS) |
- MARK_XOR_VALUE;
+ return;
+ case O_SET_MARK:
+ case O_OR_MARK:
+ case O_AND_MARK:
+ case O_XOR_MARK:
break;
default:
- return 0;
+ return;
}
/* mutual code */
- info->mark = strtoul(optarg, &end, 0);
- if (*end != '\0' || end == optarg)
- xtables_error(PARAMETER_PROBLEM, "Bad MARK value '%s'",
- optarg);
-
- return 1;
+ info->mark = cb->val.u32;
+ info->target = (info->target & EBT_VERDICT_BITS) |
+ target_orval[cb->entry->id];
}
static void brmark_print(const void *ip, const struct xt_entry_target *target,
@@ -156,9 +124,9 @@ static void brmark_print(const void *ip, const struct xt_entry_target *target,
printf(" --mark-target %s", ebt_target_name(tmp));
}
-static void brmark_final_check(unsigned int flags)
+static void brmark_final_check(struct xt_fcheck_call *fc)
{
- if (!flags)
+ if (!fc->xflags)
xtables_error(PARAMETER_PROBLEM,
"You must specify some option");
}
@@ -201,7 +169,7 @@ static int brmark_xlate(struct xt_xlate *xl,
return 0;
}
- tmp = info->target & EBT_VERDICT_BITS;
+ tmp = info->target | ~EBT_VERDICT_BITS;
xt_xlate_add(xl, "0x%lx %s ", info->mark, brmark_verdict(tmp));
return 1;
}
@@ -215,11 +183,11 @@ static struct xtables_target brmark_target = {
.userspacesize = XT_ALIGN(sizeof(struct ebt_mark_t_info)),
.help = brmark_print_help,
.init = brmark_init,
- .parse = brmark_parse,
- .final_check = brmark_final_check,
+ .x6_parse = brmark_parse,
+ .x6_fcheck = brmark_final_check,
.print = brmark_print,
.xlate = brmark_xlate,
- .extra_opts = brmark_opts,
+ .x6_options = brmark_opts,
};
void _init(void)
diff --git a/extensions/libebt_mark.txlate b/extensions/libebt_mark.txlate
new file mode 100644
index 00000000..4ace1a1f
--- /dev/null
+++ b/extensions/libebt_mark.txlate
@@ -0,0 +1,11 @@
+ebtables-translate -A INPUT -j mark --mark-set 42
+nft 'add rule bridge filter INPUT counter meta mark set 0x2a accept'
+
+ebtables-translate -A INPUT -j mark --mark-or 42 --mark-target RETURN
+nft 'add rule bridge filter INPUT counter meta mark set meta mark or 0x2a return'
+
+ebtables-translate -A INPUT -j mark --mark-and 42 --mark-target ACCEPT
+nft 'add rule bridge filter INPUT counter meta mark set meta mark and 0x2a accept'
+
+ebtables-translate -A INPUT -j mark --mark-xor 42 --mark-target DROP
+nft 'add rule bridge filter INPUT counter meta mark set meta mark xor 0x2a drop'
diff --git a/extensions/libebt_mark.xlate b/extensions/libebt_mark.xlate
deleted file mode 100644
index e0982a1e..00000000
--- a/extensions/libebt_mark.xlate
+++ /dev/null
@@ -1,11 +0,0 @@
-ebtables-translate -A INPUT --mark-set 42
-nft add rule bridge filter INPUT mark set 0x2a counter
-
-ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN
-nft add rule bridge filter INPUT mark set mark or 0x2a counter return
-
-ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT
-nft add rule bridge filter INPUT mark set mark and 0x2a counter accept
-
-ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP
-nft add rule bridge filter INPUT mark set mark xor 0x2a counter drop
diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c
index 2462d0af..8ee17207 100644
--- a/extensions/libebt_mark_m.c
+++ b/extensions/libebt_mark_m.c
@@ -12,73 +12,50 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_mark_m.h>
-#define MARK '1'
+enum {
+ O_MARK = 0,
+};
-static const struct option brmark_m_opts[] = {
- { .name = "mark", .has_arg = true, .val = MARK },
- XT_GETOPT_TABLEEND,
+static const struct xt_option_entry brmark_m_opts[] = {
+ { .name = "mark", .id = O_MARK, .type = XTTYPE_STRING,
+ .flags = XTOPT_INVERT | XTOPT_MAND },
+ XTOPT_TABLEEND,
};
static void brmark_m_print_help(void)
{
printf(
"mark option:\n"
-"--mark [!] [value][/mask]: Match nfmask value (see man page)\n");
+"[!] --mark [value][/mask]: Match nfmask value (see man page)\n");
}
-static void brmark_m_init(struct xt_entry_match *match)
+static void brmark_m_parse(struct xt_option_call *cb)
{
- struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data;
-
- info->mark = 0;
- info->mask = 0;
- info->invert = 0;
- info->bitmask = 0;
-}
-
-#define OPT_MARK 0x01
-static int
-brmark_m_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
-{
- struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)
- (*match)->data;
+ struct ebt_mark_m_info *info = cb->data;
char *end;
- switch (c) {
- case MARK:
- if (invert)
- info->invert = 1;
- info->mark = strtoul(optarg, &end, 0);
+ xtables_option_parse(cb);
+
+ switch (cb->entry->id) {
+ case O_MARK:
+ info->invert = cb->invert;
+ info->mark = strtoul(cb->arg, &end, 0);
info->bitmask = EBT_MARK_AND;
if (*end == '/') {
- if (end == optarg)
+ if (end == cb->arg)
info->bitmask = EBT_MARK_OR;
info->mask = strtoul(end+1, &end, 0);
} else {
- info->mask = 0xffffffff;
+ info->mask = UINT32_MAX;
}
- if (*end != '\0' || end == optarg)
+ if (*end != '\0' || end == cb->arg)
xtables_error(PARAMETER_PROBLEM, "Bad mark value '%s'",
- optarg);
+ cb->arg);
break;
- default:
- return 0;
}
-
- *flags |= info->bitmask;
- return 1;
-}
-
-static void brmark_m_final_check(unsigned int flags)
-{
- if (!flags)
- xtables_error(PARAMETER_PROBLEM,
- "You must specify proper arguments");
}
static void brmark_m_print(const void *ip, const struct xt_entry_match *match,
@@ -86,9 +63,9 @@ static void brmark_m_print(const void *ip, const struct xt_entry_match *match,
{
struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data;
- printf("--mark ");
if (info->invert)
printf("! ");
+ printf("--mark ");
if (info->bitmask == EBT_MARK_OR)
printf("/0x%lx ", info->mask);
else if (info->mask != 0xffffffff)
@@ -111,7 +88,7 @@ static int brmark_m_xlate(struct xt_xlate *xl,
if (info->bitmask == EBT_MARK_OR) {
xt_xlate_add(xl, "and 0x%x %s0 ", (uint32_t)info->mask,
info->invert ? "" : "!= ");
- } else if (info->mask != 0xffffffffU) {
+ } else if (info->mask != UINT32_MAX) {
xt_xlate_add(xl, "and 0x%x %s0x%x ", (uint32_t)info->mask,
op == XT_OP_EQ ? "" : "!= ", (uint32_t)info->mark);
} else {
@@ -128,13 +105,11 @@ static struct xtables_match brmark_m_match = {
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_mark_m_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_mark_m_info)),
- .init = brmark_m_init,
.help = brmark_m_print_help,
- .parse = brmark_m_parse,
- .final_check = brmark_m_final_check,
+ .x6_parse = brmark_m_parse,
.print = brmark_m_print,
.xlate = brmark_m_xlate,
- .extra_opts = brmark_m_opts,
+ .x6_options = brmark_m_opts,
};
void _init(void)
diff --git a/extensions/libebt_mark_m.t b/extensions/libebt_mark_m.t
index 00035427..4de72bde 100644
--- a/extensions/libebt_mark_m.t
+++ b/extensions/libebt_mark_m.t
@@ -1,6 +1,6 @@
:INPUT,FORWARD,OUTPUT
--mark 42;--mark 0x2a;OK
---mark ! 42;--mark ! 0x2a;OK
+! --mark 42;! --mark 0x2a;OK
--mark 42/0xff;--mark 0x2a/0xff;OK
---mark ! 0x1/0xff;=;OK
+! --mark 0x1/0xff;=;OK
--mark /0x2;=;OK
diff --git a/extensions/libebt_mark_m.txlate b/extensions/libebt_mark_m.txlate
index 7b44425b..9061adbf 100644
--- a/extensions/libebt_mark_m.txlate
+++ b/extensions/libebt_mark_m.txlate
@@ -1,14 +1,14 @@
ebtables-translate -A INPUT --mark 42
-nft add rule bridge filter INPUT meta mark 0x2a counter
+nft 'add rule bridge filter INPUT meta mark 0x2a counter'
ebtables-translate -A INPUT ! --mark 42
-nft add rule bridge filter INPUT meta mark != 0x2a counter
+nft 'add rule bridge filter INPUT meta mark != 0x2a counter'
ebtables-translate -A INPUT --mark ! 42
-nft add rule bridge filter INPUT meta mark != 0x2a counter
+nft 'add rule bridge filter INPUT meta mark != 0x2a counter'
-ebtables-translate -A INPUT --mark ! 0x1/0xff
-nft add rule bridge filter INPUT meta mark and 0xff != 0x1 counter
+ebtables-translate -A INPUT ! --mark 0x1/0xff
+nft 'add rule bridge filter INPUT meta mark and 0xff != 0x1 counter'
ebtables-translate -A INPUT --mark /0x02
-nft add rule bridge filter INPUT meta mark and 0x2 != 0 counter
+nft 'add rule bridge filter INPUT meta mark and 0x2 != 0 counter'
diff --git a/extensions/libebt_nflog.c b/extensions/libebt_nflog.c
index 9801f358..48cd5321 100644
--- a/extensions/libebt_nflog.c
+++ b/extensions/libebt_nflog.c
@@ -16,27 +16,30 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <xtables.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
#include <linux/netfilter_bridge/ebt_nflog.h>
enum {
- NFLOG_GROUP = 0x1,
- NFLOG_PREFIX = 0x2,
- NFLOG_RANGE = 0x4,
- NFLOG_THRESHOLD = 0x8,
- NFLOG_NFLOG = 0x16,
+ O_GROUP = 0,
+ O_PREFIX,
+ O_RANGE,
+ O_THRESHOLD,
+ O_NFLOG,
};
-static const struct option brnflog_opts[] = {
- { .name = "nflog-group", .has_arg = true, .val = NFLOG_GROUP},
- { .name = "nflog-prefix", .has_arg = true, .val = NFLOG_PREFIX},
- { .name = "nflog-range", .has_arg = true, .val = NFLOG_RANGE},
- { .name = "nflog-threshold", .has_arg = true, .val = NFLOG_THRESHOLD},
- { .name = "nflog", .has_arg = false, .val = NFLOG_NFLOG},
- XT_GETOPT_TABLEEND,
+static const struct xt_option_entry brnflog_opts[] = {
+ { .name = "nflog-group", .id = O_GROUP, .type = XTTYPE_UINT16,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nflog_info, group) },
+ { .name = "nflog-prefix", .id = O_PREFIX, .type = XTTYPE_STRING,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nflog_info, prefix) },
+ { .name = "nflog-range", .id = O_RANGE, .type = XTTYPE_UINT32,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nflog_info, len) },
+ { .name = "nflog-threshold", .id = O_THRESHOLD, .type = XTTYPE_UINT16,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nflog_info, threshold) },
+ { .name = "nflog", .id = O_NFLOG, .type = XTTYPE_NONE },
+ XTOPT_TABLEEND,
};
static void brnflog_help(void)
@@ -59,55 +62,6 @@ static void brnflog_init(struct xt_entry_target *t)
info->threshold = EBT_NFLOG_DEFAULT_THRESHOLD;
}
-static int brnflog_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
-{
- struct ebt_nflog_info *info = (struct ebt_nflog_info *)(*target)->data;
- unsigned int i;
-
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "The use of '!' makes no sense for the"
- " nflog watcher");
-
- switch (c) {
- case NFLOG_PREFIX:
- EBT_CHECK_OPTION(flags, NFLOG_PREFIX);
- if (strlen(optarg) > EBT_NFLOG_PREFIX_SIZE - 1)
- xtables_error(PARAMETER_PROBLEM,
- "Prefix too long for nflog-prefix");
- strncpy(info->prefix, optarg, EBT_NFLOG_PREFIX_SIZE);
- break;
- case NFLOG_GROUP:
- EBT_CHECK_OPTION(flags, NFLOG_GROUP);
- if (!xtables_strtoui(optarg, NULL, &i, 1, UINT32_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "--nflog-group must be a number!");
- info->group = i;
- break;
- case NFLOG_RANGE:
- EBT_CHECK_OPTION(flags, NFLOG_RANGE);
- if (!xtables_strtoui(optarg, NULL, &i, 1, UINT32_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "--nflog-range must be a number!");
- info->len = i;
- break;
- case NFLOG_THRESHOLD:
- EBT_CHECK_OPTION(flags, NFLOG_THRESHOLD);
- if (!xtables_strtoui(optarg, NULL, &i, 1, UINT32_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "--nflog-threshold must be a number!");
- info->threshold = i;
- break;
- case NFLOG_NFLOG:
- EBT_CHECK_OPTION(flags, NFLOG_NFLOG);
- break;
- default:
- return 0;
- }
- return 1;
-}
-
static void
brnflog_print(const void *ip, const struct xt_entry_target *target,
int numeric)
@@ -130,12 +84,8 @@ static int brnflog_xlate(struct xt_xlate *xl,
const struct ebt_nflog_info *info = (void *)params->target->data;
xt_xlate_add(xl, "log ");
- if (info->prefix[0] != '\0') {
- if (params->escape_quotes)
- xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix);
- else
- xt_xlate_add(xl, "prefix \"%s\" ", info->prefix);
- }
+ if (info->prefix[0] != '\0')
+ xt_xlate_add(xl, "prefix \"%s\" ", info->prefix);
xt_xlate_add(xl, "group %u ", info->group);
@@ -150,16 +100,17 @@ static int brnflog_xlate(struct xt_xlate *xl,
static struct xtables_target brnflog_watcher = {
.name = "nflog",
.revision = 0,
+ .ext_flags = XTABLES_EXT_WATCHER,
.version = XTABLES_VERSION,
.family = NFPROTO_BRIDGE,
.size = XT_ALIGN(sizeof(struct ebt_nflog_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_nflog_info)),
.init = brnflog_init,
.help = brnflog_help,
- .parse = brnflog_parse,
+ .x6_parse = xtables_option_parse,
.print = brnflog_print,
.xlate = brnflog_xlate,
- .extra_opts = brnflog_opts,
+ .x6_options = brnflog_opts,
};
void _init(void)
diff --git a/extensions/libebt_nflog.t b/extensions/libebt_nflog.t
index f867df30..e98d8f5f 100644
--- a/extensions/libebt_nflog.t
+++ b/extensions/libebt_nflog.t
@@ -1,5 +1,5 @@
:INPUT,FORWARD,OUTPUT
---nflog;=;OK
+--nflog;--nflog-group 1;OK
--nflog-group 42;=;OK
--nflog-range 42;--nflog-group 1 --nflog-range 42 -j CONTINUE;OK
--nflog-threshold 100 --nflog-prefix foo;--nflog-prefix "foo" --nflog-group 1 --nflog-threshold 100 -j CONTINUE;OK
diff --git a/extensions/libebt_nflog.txlate b/extensions/libebt_nflog.txlate
index bc3f5364..6f292fd2 100644
--- a/extensions/libebt_nflog.txlate
+++ b/extensions/libebt_nflog.txlate
@@ -1,11 +1,11 @@
ebtables-translate -A INPUT --nflog
-nft add rule bridge filter INPUT log group 1 counter
+nft 'add rule bridge filter INPUT log group 1 counter'
ebtables-translate -A INPUT --nflog-group 42
-nft add rule bridge filter INPUT log group 42 counter
+nft 'add rule bridge filter INPUT log group 42 counter'
ebtables-translate -A INPUT --nflog-range 42
-nft add rule bridge filter INPUT log group 1 snaplen 42 counter
+nft 'add rule bridge filter INPUT log group 1 snaplen 42 counter'
ebtables-translate -A INPUT --nflog-threshold 100 --nflog-prefix foo
-nft add rule bridge filter INPUT log prefix "foo" group 1 queue-threshold 100 counter
+nft 'add rule bridge filter INPUT log prefix "foo" group 1 queue-threshold 100 counter'
diff --git a/extensions/libebt_pkttype.c b/extensions/libebt_pkttype.c
index 4e2d19de..579e8fdb 100644
--- a/extensions/libebt_pkttype.c
+++ b/extensions/libebt_pkttype.c
@@ -9,7 +9,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <netdb.h>
#include <xtables.h>
#include <linux/if_packet.h>
@@ -25,57 +24,59 @@ static const char *classes[] = {
"fastroute",
};
-static const struct option brpkttype_opts[] =
-{
- { "pkttype-type" , required_argument, 0, '1' },
- { 0 }
+enum {
+ O_TYPE,
+};
+
+static const struct xt_option_entry brpkttype_opts[] = {
+ { .name = "pkttype-type", .id = O_TYPE, .type = XTTYPE_STRING,
+ .flags = XTOPT_INVERT },
+ XTOPT_TABLEEND,
};
static void brpkttype_print_help(void)
{
printf(
"pkttype options:\n"
-"--pkttype-type [!] type: class the packet belongs to\n"
+"[!] --pkttype-type type: class the packet belongs to\n"
"Possible values: broadcast, multicast, host, otherhost, or any other byte value (which would be pretty useless).\n");
}
-static int brpkttype_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
+static void brpkttype_parse(struct xt_option_call *cb)
{
- struct ebt_pkttype_info *ptinfo = (struct ebt_pkttype_info *)(*match)->data;
- char *end;
+ struct ebt_pkttype_info *ptinfo = cb->data;
long int i;
+ char *end;
+
+ xtables_option_parse(cb);
- switch (c) {
- case '1':
- if (invert)
- ptinfo->invert = 1;
- i = strtol(optarg, &end, 16);
+ switch (cb->entry->id) {
+ case O_TYPE:
+ ptinfo->invert = cb->invert;
+ i = strtol(cb->arg, &end, 16);
if (*end != '\0') {
for (i = 0; i < ARRAY_SIZE(classes); i++) {
- if (!strcasecmp(optarg, classes[i]))
+ if (!strcasecmp(cb->arg, classes[i]))
break;
}
if (i >= ARRAY_SIZE(classes))
- xtables_error(PARAMETER_PROBLEM, "Could not parse class '%s'", optarg);
+ xtables_error(PARAMETER_PROBLEM,
+ "Could not parse class '%s'",
+ cb->arg);
}
if (i < 0 || i > 255)
xtables_error(PARAMETER_PROBLEM, "Problem with specified pkttype class");
ptinfo->pkt_type = (uint8_t)i;
break;
- default:
- return 0;
}
- return 1;
}
-
static void brpkttype_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
struct ebt_pkttype_info *pt = (struct ebt_pkttype_info *)match->data;
- printf("--pkttype-type %s", pt->invert ? "! " : "");
+ printf("%s--pkttype-type ", pt->invert ? "! " : "");
if (pt->pkt_type < ARRAY_SIZE(classes))
printf("%s ", classes[pt->pkt_type]);
@@ -107,10 +108,10 @@ static struct xtables_match brpkttype_match = {
.size = XT_ALIGN(sizeof(struct ebt_pkttype_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_pkttype_info)),
.help = brpkttype_print_help,
- .parse = brpkttype_parse,
+ .x6_parse = brpkttype_parse,
.print = brpkttype_print,
.xlate = brpkttype_xlate,
- .extra_opts = brpkttype_opts,
+ .x6_options = brpkttype_opts,
};
void _init(void)
diff --git a/extensions/libebt_pkttype.t b/extensions/libebt_pkttype.t
index e3b95ded..f3cdc19d 100644
--- a/extensions/libebt_pkttype.t
+++ b/extensions/libebt_pkttype.t
@@ -1,14 +1,14 @@
:INPUT,FORWARD,OUTPUT
-! --pkttype-type host;--pkttype-type ! host -j CONTINUE;OK
+--pkttype-type ! host;! --pkttype-type host -j CONTINUE;OK
--pkttype-type host;=;OK
---pkttype-type ! host;=;OK
+! --pkttype-type host;=;OK
--pkttype-type broadcast;=;OK
---pkttype-type ! broadcast;=;OK
+! --pkttype-type broadcast;=;OK
--pkttype-type multicast;=;OK
---pkttype-type ! multicast;=;OK
+! --pkttype-type multicast;=;OK
--pkttype-type otherhost;=;OK
---pkttype-type ! otherhost;=;OK
+! --pkttype-type otherhost;=;OK
--pkttype-type outgoing;=;OK
---pkttype-type ! outgoing;=;OK
+! --pkttype-type outgoing;=;OK
--pkttype-type loopback;=;OK
---pkttype-type ! loopback;=;OK
+! --pkttype-type loopback;=;OK
diff --git a/extensions/libebt_pkttype.txlate b/extensions/libebt_pkttype.txlate
index 94d016d9..6a828a98 100644
--- a/extensions/libebt_pkttype.txlate
+++ b/extensions/libebt_pkttype.txlate
@@ -1,20 +1,20 @@
ebtables-translate -A INPUT --pkttype-type host
-nft add rule bridge filter INPUT meta pkttype host counter
+nft 'add rule bridge filter INPUT meta pkttype host counter'
ebtables-translate -A INPUT ! --pkttype-type broadcast
-nft add rule bridge filter INPUT meta pkttype != broadcast counter
+nft 'add rule bridge filter INPUT meta pkttype != broadcast counter'
ebtables-translate -A INPUT --pkttype-type ! multicast
-nft add rule bridge filter INPUT meta pkttype != multicast counter
+nft 'add rule bridge filter INPUT meta pkttype != multicast counter'
ebtables-translate -A INPUT --pkttype-type otherhost
-nft add rule bridge filter INPUT meta pkttype other counter
+nft 'add rule bridge filter INPUT meta pkttype other counter'
ebtables-translate -A INPUT --pkttype-type outgoing
-nft add rule bridge filter INPUT meta pkttype 4 counter
+nft 'add rule bridge filter INPUT meta pkttype 4 counter'
ebtables-translate -A INPUT --pkttype-type loopback
-nft add rule bridge filter INPUT meta pkttype 5 counter
+nft 'add rule bridge filter INPUT meta pkttype 5 counter'
ebtables-translate -A INPUT --pkttype-type fastroute
-nft add rule bridge filter INPUT meta pkttype 6 counter
+nft 'add rule bridge filter INPUT meta pkttype 6 counter'
diff --git a/extensions/libebt_redirect.c b/extensions/libebt_redirect.c
index 6e653997..a44dbaec 100644
--- a/extensions/libebt_redirect.c
+++ b/extensions/libebt_redirect.c
@@ -9,17 +9,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_redirect.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define REDIRECT_TARGET '1'
-static const struct option brredir_opts[] =
+enum {
+ O_TARGET,
+};
+
+static const struct xt_option_entry brredir_opts[] =
{
- { "redirect-target", required_argument, 0, REDIRECT_TARGET },
- { 0 }
+ { .name = "redirect-target", .id = O_TARGET, .type = XTTYPE_STRING },
+ XTOPT_TABLEEND,
};
static void brredir_print_help(void)
@@ -37,23 +39,15 @@ static void brredir_init(struct xt_entry_target *target)
redirectinfo->target = EBT_ACCEPT;
}
-#define OPT_REDIRECT_TARGET 0x01
-static int brredir_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
+static void brredir_parse(struct xt_option_call *cb)
{
- struct ebt_redirect_info *redirectinfo =
- (struct ebt_redirect_info *)(*target)->data;
-
- switch (c) {
- case REDIRECT_TARGET:
- EBT_CHECK_OPTION(flags, OPT_REDIRECT_TARGET);
- if (ebt_fill_target(optarg, (unsigned int *)&redirectinfo->target))
- xtables_error(PARAMETER_PROBLEM, "Illegal --redirect-target target");
- break;
- default:
- return 0;
- }
- return 1;
+ struct ebt_redirect_info *redirectinfo = cb->data;
+
+ xtables_option_parse(cb);
+ if (cb->entry->id == O_TARGET &&
+ ebt_fill_target(cb->arg, (unsigned int *)&redirectinfo->target))
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal --redirect-target target");
}
static void brredir_print(const void *ip, const struct xt_entry_target *target, int numeric)
@@ -83,10 +77,10 @@ static int brredir_xlate(struct xt_xlate *xl,
{
const struct ebt_redirect_info *red = (const void*)params->target->data;
- xt_xlate_add(xl, "meta set pkttype host");
- if (red->target != EBT_ACCEPT)
+ xt_xlate_add(xl, "meta pkttype set host");
+ if (red->target != EBT_CONTINUE)
xt_xlate_add(xl, " %s ", brredir_verdict(red->target));
- return 0;
+ return 1;
}
static struct xtables_target brredirect_target = {
@@ -97,10 +91,10 @@ static struct xtables_target brredirect_target = {
.userspacesize = XT_ALIGN(sizeof(struct ebt_redirect_info)),
.help = brredir_print_help,
.init = brredir_init,
- .parse = brredir_parse,
+ .x6_parse = brredir_parse,
.print = brredir_print,
.xlate = brredir_xlate,
- .extra_opts = brredir_opts,
+ .x6_options = brredir_opts,
};
void _init(void)
diff --git a/extensions/libebt_redirect.t b/extensions/libebt_redirect.t
index 23858afa..58492b79 100644
--- a/extensions/libebt_redirect.t
+++ b/extensions/libebt_redirect.t
@@ -1,4 +1,4 @@
:PREROUTING
*nat
--j redirect;=;OK
+-j redirect ;=;OK
-j redirect --redirect-target RETURN;=;OK
diff --git a/extensions/libebt_redirect.txlate b/extensions/libebt_redirect.txlate
new file mode 100644
index 00000000..d073ec77
--- /dev/null
+++ b/extensions/libebt_redirect.txlate
@@ -0,0 +1,8 @@
+ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect
+nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host accept'
+
+ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target RETURN
+nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host return'
+
+ebtables-translate -t nat -A PREROUTING -d de:ad:00:00:be:ef -j redirect --redirect-target CONTINUE
+nft 'add rule bridge nat PREROUTING ether daddr de:ad:00:00:be:ef counter meta pkttype set host'
diff --git a/extensions/libebt_snat.c b/extensions/libebt_snat.c
index c1124bf3..1dc738fa 100644
--- a/extensions/libebt_snat.c
+++ b/extensions/libebt_snat.c
@@ -9,23 +9,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <netinet/ether.h>
#include <xtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define NAT_S '1'
-#define NAT_S_TARGET '2'
-#define NAT_S_ARP '3'
-static const struct option brsnat_opts[] =
+enum {
+ O_SRC,
+ O_TARGET,
+ O_ARP,
+};
+
+static const struct xt_option_entry brsnat_opts[] =
{
- { "to-source" , required_argument, 0, NAT_S },
- { "to-src" , required_argument, 0, NAT_S },
- { "snat-target" , required_argument, 0, NAT_S_TARGET },
- { "snat-arp" , no_argument, 0, NAT_S_ARP },
- { 0 }
+ { .name = "to-source", .id = O_SRC, .type = XTTYPE_ETHERMAC,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nat_info, mac) },
+ { .name = "to-src", .id = O_SRC, .type = XTTYPE_ETHERMAC,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct ebt_nat_info, mac) },
+ { .name = "snat-target", .id = O_TARGET, .type = XTTYPE_STRING },
+ { .name = "snat-arp", .id = O_ARP, .type = XTTYPE_NONE },
+ XTOPT_TABLEEND,
};
static void brsnat_print_help(void)
@@ -44,43 +48,29 @@ static void brsnat_init(struct xt_entry_target *target)
natinfo->target = EBT_ACCEPT;
}
-#define OPT_SNAT 0x01
-#define OPT_SNAT_TARGET 0x02
-#define OPT_SNAT_ARP 0x04
-static int brsnat_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
+static void brsnat_parse(struct xt_option_call *cb)
{
- struct ebt_nat_info *natinfo = (struct ebt_nat_info *)(*target)->data;
- struct ether_addr *addr;
-
- switch (c) {
- case NAT_S:
- EBT_CHECK_OPTION(flags, OPT_SNAT);
- if (!(addr = ether_aton(optarg)))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified --to-source mac");
- memcpy(natinfo->mac, addr, ETH_ALEN);
- break;
- case NAT_S_TARGET:
- { unsigned int tmp;
- EBT_CHECK_OPTION(flags, OPT_SNAT_TARGET);
- if (ebt_fill_target(optarg, &tmp))
- xtables_error(PARAMETER_PROBLEM, "Illegal --snat-target target");
- natinfo->target = (natinfo->target & ~EBT_VERDICT_BITS) | (tmp & EBT_VERDICT_BITS);
- }
+ struct ebt_nat_info *natinfo = cb->data;
+ unsigned int tmp;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_TARGET:
+ if (ebt_fill_target(cb->arg, &tmp))
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal --snat-target target");
+ natinfo->target &= ~EBT_VERDICT_BITS;
+ natinfo->target |= tmp & EBT_VERDICT_BITS;
break;
- case NAT_S_ARP:
- EBT_CHECK_OPTION(flags, OPT_SNAT_ARP);
+ case O_ARP:
natinfo->target ^= NAT_ARP_BIT;
break;
- default:
- return 0;
}
- return 1;
}
-static void brsnat_final_check(unsigned int flags)
+static void brsnat_final_check(struct xt_fcheck_call *fc)
{
- if (!flags)
+ if (!fc->xflags)
xtables_error(PARAMETER_PROBLEM,
"You must specify proper arguments");
}
@@ -133,11 +123,11 @@ static struct xtables_target brsnat_target =
.userspacesize = XT_ALIGN(sizeof(struct ebt_nat_info)),
.help = brsnat_print_help,
.init = brsnat_init,
- .parse = brsnat_parse,
- .final_check = brsnat_final_check,
+ .x6_parse = brsnat_parse,
+ .x6_fcheck = brsnat_final_check,
.print = brsnat_print,
.xlate = brsnat_xlate,
- .extra_opts = brsnat_opts,
+ .x6_options = brsnat_opts,
};
void _init(void)
diff --git a/extensions/libebt_snat.t b/extensions/libebt_snat.t
index 639b13f3..f5d02340 100644
--- a/extensions/libebt_snat.t
+++ b/extensions/libebt_snat.t
@@ -2,3 +2,5 @@
*nat
-o someport -j snat --to-source a:b:c:d:e:f;-o someport -j snat --to-src 0a:0b:0c:0d:0e:0f --snat-target ACCEPT;OK
-o someport+ -j snat --to-src de:ad:00:be:ee:ff --snat-target CONTINUE;=;OK
+-j snat;;FAIL
+-j snat --to-src de:ad:00:be:ee:ff;-j snat --to-src de:ad:00:be:ee:ff --snat-target ACCEPT;OK
diff --git a/extensions/libebt_snat.txlate b/extensions/libebt_snat.txlate
index 0d846024..37343d3a 100644
--- a/extensions/libebt_snat.txlate
+++ b/extensions/libebt_snat.txlate
@@ -1,5 +1,5 @@
-ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ --to-source de:ad:00:be:ee:ff
-nft add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 ether saddr set de:ad:0:be:ee:ff accept counter
+ebtables-translate -t nat -A POSTROUTING -s 0:0:0:0:0:0 -o someport+ -j snat --to-source de:ad:00:be:ee:ff
+nft 'add rule bridge nat POSTROUTING oifname "someport*" ether saddr 00:00:00:00:00:00 counter ether saddr set de:ad:0:be:ee:ff accept'
-ebtables-translate -t nat -A POSTROUTING -o someport --to-src de:ad:00:be:ee:ff --snat-target CONTINUE
-nft add rule bridge nat POSTROUTING oifname "someport" ether saddr set de:ad:0:be:ee:ff continue counter
+ebtables-translate -t nat -A POSTROUTING -o someport -j snat --to-src de:ad:00:be:ee:ff --snat-target CONTINUE
+nft 'add rule bridge nat POSTROUTING oifname "someport" counter ether saddr set de:ad:0:be:ee:ff continue'
diff --git a/extensions/libebt_standard.t b/extensions/libebt_standard.t
index c6c31727..3f1a459c 100644
--- a/extensions/libebt_standard.t
+++ b/extensions/libebt_standard.t
@@ -6,18 +6,28 @@
-d de:ad:be:ef:00:00 -j CONTINUE;=;OK
-d de:ad:be:ef:0:00/ff:ff:ff:ff:0:0 -j DROP;-d de:ad:be:ef:00:00/ff:ff:ff:ff:00:00 -j DROP;OK
-p ARP -j ACCEPT;=;OK
--p ! ARP -j ACCEPT;=;OK
+! -p ARP -j ACCEPT;=;OK
+-p ! ARP -j ACCEPT;! -p ARP -j ACCEPT;OK
-p 0 -j ACCEPT;=;FAIL
-p ! 0 -j ACCEPT;=;FAIL
:INPUT
-i foobar;=;OK
-o foobar;=;FAIL
+--logical-in br0;=;OK
+--logical-out br1;=;FAIL
+-i + -d 00:0f:ee:d0:ba:be;-d 00:0f:ee:d0:ba:be;OK
+-i + -p ip;-p IPv4;OK
+--logical-in + -d 00:0f:ee:d0:ba:be;-d 00:0f:ee:d0:ba:be;OK
+--logical-in + -p ip;-p IPv4;OK
:FORWARD
-i foobar;=;OK
-o foobar;=;OK
+--logical-in br0 --logical-out br1;=;OK
:OUTPUT
-i foobar;=;FAIL
-o foobar;=;OK
+--logical-in br0;=;FAIL
+--logical-out br1;=;OK
:PREROUTING
*nat
-i foobar;=;OK
diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c
index 06cf93b8..189e36a5 100644
--- a/extensions/libebt_stp.c
+++ b/extensions/libebt_stp.c
@@ -9,7 +9,6 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <getopt.h>
#include <netinet/ether.h>
#include <linux/netfilter_bridge/ebt_stp.h>
#include <xtables.h>
@@ -17,35 +16,37 @@
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define STP_TYPE 'a'
-#define STP_FLAGS 'b'
-#define STP_ROOTPRIO 'c'
-#define STP_ROOTADDR 'd'
-#define STP_ROOTCOST 'e'
-#define STP_SENDERPRIO 'f'
-#define STP_SENDERADDR 'g'
-#define STP_PORT 'h'
-#define STP_MSGAGE 'i'
-#define STP_MAXAGE 'j'
-#define STP_HELLOTIME 'k'
-#define STP_FWDD 'l'
-#define STP_NUMOPS 12
+/* These must correspond to the bit position in EBT_STP_* defines */
+enum {
+ O_TYPE = 0,
+ O_FLAGS,
+ O_RPRIO,
+ O_RADDR,
+ O_RCOST,
+ O_SPRIO,
+ O_SADDR,
+ O_PORT,
+ O_MSGAGE,
+ O_MAXAGE,
+ O_HTIME,
+ O_FWDD,
+};
-static const struct option brstp_opts[] =
-{
- { "stp-type" , required_argument, 0, STP_TYPE},
- { "stp-flags" , required_argument, 0, STP_FLAGS},
- { "stp-root-prio" , required_argument, 0, STP_ROOTPRIO},
- { "stp-root-addr" , required_argument, 0, STP_ROOTADDR},
- { "stp-root-cost" , required_argument, 0, STP_ROOTCOST},
- { "stp-sender-prio" , required_argument, 0, STP_SENDERPRIO},
- { "stp-sender-addr" , required_argument, 0, STP_SENDERADDR},
- { "stp-port" , required_argument, 0, STP_PORT},
- { "stp-msg-age" , required_argument, 0, STP_MSGAGE},
- { "stp-max-age" , required_argument, 0, STP_MAXAGE},
- { "stp-hello-time" , required_argument, 0, STP_HELLOTIME},
- { "stp-forward-delay", required_argument, 0, STP_FWDD},
- { 0 }
+static const struct xt_option_entry brstp_opts[] = {
+#define ENTRY(n, i, t) { .name = n, .id = i, .type = t, .flags = XTOPT_INVERT }
+ ENTRY("stp-type", O_TYPE, XTTYPE_STRING),
+ ENTRY("stp-flags", O_FLAGS, XTTYPE_STRING),
+ ENTRY("stp-root-prio", O_RPRIO, XTTYPE_UINT16RC),
+ ENTRY("stp-root-addr", O_RADDR, XTTYPE_ETHERMACMASK),
+ ENTRY("stp-root-cost", O_RCOST, XTTYPE_UINT32RC),
+ ENTRY("stp-sender-prio", O_SPRIO, XTTYPE_UINT16RC),
+ ENTRY("stp-sender-addr", O_SADDR, XTTYPE_ETHERMACMASK),
+ ENTRY("stp-port", O_PORT, XTTYPE_UINT16RC),
+ ENTRY("stp-msg-age", O_MSGAGE, XTTYPE_UINT16RC),
+ ENTRY("stp-max-age", O_MAXAGE, XTTYPE_UINT16RC),
+ ENTRY("stp-hello-time", O_HTIME, XTTYPE_UINT16RC),
+ ENTRY("stp-forward-delay", O_FWDD, XTTYPE_UINT16RC),
+ XTOPT_TABLEEND,
};
#define BPDU_TYPE_CONFIG 0
@@ -62,18 +63,18 @@ static void brstp_print_help(void)
{
printf(
"stp options:\n"
-"--stp-type type : BPDU type\n"
-"--stp-flags flag : control flag\n"
-"--stp-root-prio prio[:prio] : root priority (16-bit) range\n"
-"--stp-root-addr address[/mask] : MAC address of root\n"
-"--stp-root-cost cost[:cost] : root cost (32-bit) range\n"
-"--stp-sender-prio prio[:prio] : sender priority (16-bit) range\n"
-"--stp-sender-addr address[/mask] : MAC address of sender\n"
-"--stp-port port[:port] : port id (16-bit) range\n"
-"--stp-msg-age age[:age] : message age timer (16-bit) range\n"
-"--stp-max-age age[:age] : maximum age timer (16-bit) range\n"
-"--stp-hello-time time[:time] : hello time timer (16-bit) range\n"
-"--stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n"
+"[!] --stp-type type : BPDU type\n"
+"[!] --stp-flags flag : control flag\n"
+"[!] --stp-root-prio prio[:prio] : root priority (16-bit) range\n"
+"[!] --stp-root-addr address[/mask] : MAC address of root\n"
+"[!] --stp-root-cost cost[:cost] : root cost (32-bit) range\n"
+"[!] --stp-sender-prio prio[:prio] : sender priority (16-bit) range\n"
+"[!] --stp-sender-addr address[/mask] : MAC address of sender\n"
+"[!] --stp-port port[:port] : port id (16-bit) range\n"
+"[!] --stp-msg-age age[:age] : message age timer (16-bit) range\n"
+"[!] --stp-max-age age[:age] : maximum age timer (16-bit) range\n"
+"[!] --stp-hello-time time[:time] : hello time timer (16-bit) range\n"
+"[!] --stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n"
" Recognized BPDU type strings:\n"
" \"config\": configuration BPDU (=0)\n"
" \"tcn\" : topology change notification BPDU (=0x80)\n"
@@ -82,219 +83,92 @@ static void brstp_print_help(void)
" \"topology-change-ack\": topology change acknowledgement flag (0x80)");
}
-static int parse_range(const char *portstring, void *lower, void *upper,
- int bits, uint32_t min, uint32_t max)
-{
- char *buffer;
- char *cp, *end;
- uint32_t low_nr, upp_nr;
- int ret = 0;
-
- buffer = strdup(portstring);
- if ((cp = strchr(buffer, ':')) == NULL) {
- low_nr = strtoul(buffer, &end, 10);
- if (*end || low_nr < min || low_nr > max) {
- ret = -1;
- goto out;
- }
- if (bits == 2) {
- *(uint16_t *)lower = low_nr;
- *(uint16_t *)upper = low_nr;
- } else {
- *(uint32_t *)lower = low_nr;
- *(uint32_t *)upper = low_nr;
- }
- } else {
- *cp = '\0';
- cp++;
- if (!*buffer)
- low_nr = min;
- else {
- low_nr = strtoul(buffer, &end, 10);
- if (*end || low_nr < min) {
- ret = -1;
- goto out;
- }
- }
- if (!*cp)
- upp_nr = max;
- else {
- upp_nr = strtoul(cp, &end, 10);
- if (*end || upp_nr > max) {
- ret = -1;
- goto out;
- }
- }
- if (upp_nr < low_nr) {
- ret = -1;
- goto out;
- }
- if (bits == 2) {
- *(uint16_t *)lower = low_nr;
- *(uint16_t *)upper = upp_nr;
- } else {
- *(uint32_t *)lower = low_nr;
- *(uint32_t *)upper = upp_nr;
- }
- }
-out:
- free(buffer);
- return ret;
-}
-
static void print_range(unsigned int l, unsigned int u)
{
if (l == u)
- printf("%u ", l);
+ printf("%u", l);
else
- printf("%u:%u ", l, u);
+ printf("%u:%u", l, u);
}
-static int brstp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
+static void brstp_parse(struct xt_option_call *cb)
{
- char *p;
- int i;
- struct ether_addr *addr = NULL;
+ struct ebt_stp_info *stpinfo = cb->data;
+ char *end = NULL;
+ long int i;
- 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};
+ xtables_option_parse(cb);
- 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)
-{
- struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
- unsigned int flag;
- long int i;
- char *end = NULL;
+ stpinfo->bitmask |= 1 << cb->entry->id;
+ if (cb->invert)
+ stpinfo->invflags |= 1 << cb->entry->id;
- if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
- return 0;
- flag = 1 << (c - 'a');
- EBT_CHECK_OPTION(flags, flag);
- if (invert)
- stpinfo->invflags |= flag;
- stpinfo->bitmask |= flag;
- switch (flag) {
- case EBT_STP_TYPE:
- i = strtol(optarg, &end, 0);
+ switch (cb->entry->id) {
+ case O_TYPE:
+ i = strtol(cb->arg, &end, 0);
if (i < 0 || i > 255 || *end != '\0') {
- if (!strcasecmp(optarg, BPDU_TYPE_CONFIG_STRING))
+ if (!strcasecmp(cb->arg, BPDU_TYPE_CONFIG_STRING))
stpinfo->type = BPDU_TYPE_CONFIG;
- else if (!strcasecmp(optarg, BPDU_TYPE_TCN_STRING))
+ else if (!strcasecmp(cb->arg, BPDU_TYPE_TCN_STRING))
stpinfo->type = BPDU_TYPE_TCN;
else
xtables_error(PARAMETER_PROBLEM, "Bad --stp-type argument");
} else
stpinfo->type = i;
break;
- case EBT_STP_FLAGS:
- i = strtol(optarg, &end, 0);
+ case O_FLAGS:
+ i = strtol(cb->arg, &end, 0);
if (i < 0 || i > 255 || *end != '\0') {
- if (!strcasecmp(optarg, FLAG_TC_STRING))
+ if (!strcasecmp(cb->arg, FLAG_TC_STRING))
stpinfo->config.flags = FLAG_TC;
- else if (!strcasecmp(optarg, FLAG_TC_ACK_STRING))
+ else if (!strcasecmp(cb->arg, FLAG_TC_ACK_STRING))
stpinfo->config.flags = FLAG_TC_ACK;
else
xtables_error(PARAMETER_PROBLEM, "Bad --stp-flags argument");
} else
stpinfo->config.flags = i;
break;
- case EBT_STP_ROOTPRIO:
- if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
- &(stpinfo->config.root_priou), 2, 0, 0xffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-prio range");
+ case O_RADDR:
+ memcpy(stpinfo->config.root_addr, cb->val.ethermac, ETH_ALEN);
+ memcpy(stpinfo->config.root_addrmsk,
+ cb->val.ethermacmask, ETH_ALEN);
break;
- case EBT_STP_ROOTCOST:
- if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
- &(stpinfo->config.root_costu), 4, 0, 0xffffffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-cost range");
+ case O_SADDR:
+ memcpy(stpinfo->config.sender_addr, cb->val.ethermac, ETH_ALEN);
+ memcpy(stpinfo->config.sender_addrmsk,
+ cb->val.ethermacmask, ETH_ALEN);
break;
- case EBT_STP_SENDERPRIO:
- if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
- &(stpinfo->config.sender_priou), 2, 0, 0xffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-prio range");
+
+#define RANGE_ASSIGN(fname, val) { \
+ stpinfo->config.fname##l = val[0]; \
+ stpinfo->config.fname##u = cb->nvals > 1 ? val[1] : val[0]; \
+}
+ case O_RPRIO:
+ RANGE_ASSIGN(root_prio, cb->val.u16_range);
break;
- case EBT_STP_PORT:
- if (parse_range(argv[optind-1], &(stpinfo->config.portl),
- &(stpinfo->config.portu), 2, 0, 0xffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-port-range");
+ case O_RCOST:
+ RANGE_ASSIGN(root_cost, cb->val.u32_range);
break;
- case EBT_STP_MSGAGE:
- if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
- &(stpinfo->config.msg_ageu), 2, 0, 0xffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-msg-age range");
+ case O_SPRIO:
+ RANGE_ASSIGN(sender_prio, cb->val.u16_range);
break;
- case EBT_STP_MAXAGE:
- if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
- &(stpinfo->config.max_ageu), 2, 0, 0xffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-max-age range");
+ case O_PORT:
+ RANGE_ASSIGN(port, cb->val.u16_range);
break;
- case EBT_STP_HELLOTIME:
- if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
- &(stpinfo->config.hello_timeu), 2, 0, 0xffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-hello-time range");
+ case O_MSGAGE:
+ RANGE_ASSIGN(msg_age, cb->val.u16_range);
break;
- case EBT_STP_FWDD:
- if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
- &(stpinfo->config.forward_delayu), 2, 0, 0xffff))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-forward-delay range");
+ case O_MAXAGE:
+ RANGE_ASSIGN(max_age, cb->val.u16_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))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-addr address");
+ case O_HTIME:
+ RANGE_ASSIGN(hello_time, cb->val.u16_range);
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))
- xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-addr address");
+ case O_FWDD:
+ RANGE_ASSIGN(forward_delay, cb->val.u16_range);
break;
- default:
- xtables_error(PARAMETER_PROBLEM, "Unknown stp option");
+#undef RANGE_ASSIGN
}
- return 1;
}
static void brstp_print(const void *ip, const struct xt_entry_match *match,
@@ -304,11 +178,12 @@ static void brstp_print(const void *ip, const struct xt_entry_match *match,
const struct ebt_stp_config_info *c = &(stpinfo->config);
int i;
- for (i = 0; i < STP_NUMOPS; i++) {
+ for (i = 0; (1 << i) < EBT_STP_MASK; i++) {
if (!(stpinfo->bitmask & (1 << i)))
continue;
- printf("--%s %s", brstp_opts[i].name,
- (stpinfo->invflags & (1 << i)) ? "! " : "");
+ printf("%s--%s ",
+ (stpinfo->invflags & (1 << i)) ? "! " : "",
+ brstp_opts[i].name);
if (EBT_STP_TYPE == (1 << i)) {
if (stpinfo->type == BPDU_TYPE_CONFIG)
printf("%s", BPDU_TYPE_CONFIG_STRING);
@@ -355,9 +230,9 @@ static struct xtables_match brstp_match = {
.family = NFPROTO_BRIDGE,
.size = sizeof(struct ebt_stp_info),
.help = brstp_print_help,
- .parse = brstp_parse,
+ .x6_parse = brstp_parse,
.print = brstp_print,
- .extra_opts = brstp_opts,
+ .x6_options = brstp_opts
};
void _init(void)
diff --git a/extensions/libebt_stp.t b/extensions/libebt_stp.t
index 0c6b77b9..f72051ac 100644
--- a/extensions/libebt_stp.t
+++ b/extensions/libebt_stp.t
@@ -1,13 +1,74 @@
:INPUT,FORWARD,OUTPUT
--stp-type 1;=;OK
+! --stp-type 1;=;OK
--stp-flags 0x1;--stp-flags topology-change -j CONTINUE;OK
---stp-root-prio 1 -j ACCEPT;=;OK
+! --stp-flags topology-change;=;OK
+--stp-root-prio 1 -j ACCEPT;=;OK
+! --stp-root-prio 1 -j ACCEPT;=;OK
--stp-root-addr 0d:ea:d0:0b:ee:f0;=;OK
+! --stp-root-addr 0d:ea:d0:0b:ee:f0;=;OK
+--stp-root-addr 0d:ea:d0:00:00:00/ff:ff:ff:00:00:00;=;OK
+! --stp-root-addr 0d:ea:d0:00:00:00/ff:ff:ff:00:00:00;=;OK
--stp-root-cost 1;=;OK
+! --stp-root-cost 1;=;OK
--stp-sender-prio 1;=;OK
+! --stp-sender-prio 1;=;OK
--stp-sender-addr de:ad:be:ef:00:00;=;OK
+! --stp-sender-addr de:ad:be:ef:00:00;=;OK
+--stp-sender-addr de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK
+! --stp-sender-addr de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK
--stp-port 1;=;OK
+! --stp-port 1;=;OK
--stp-msg-age 1;=;OK
+! --stp-msg-age 1;=;OK
--stp-max-age 1;=;OK
+! --stp-max-age 1;=;OK
--stp-hello-time 1;=;OK
+! --stp-hello-time 1;=;OK
--stp-forward-delay 1;=;OK
+! --stp-forward-delay 1;=;OK
+--stp-root-prio :2;--stp-root-prio 0:2;OK
+--stp-root-prio 2:;--stp-root-prio 2:65535;OK
+--stp-root-prio 1:2;=;OK
+--stp-root-prio 1:1;--stp-root-prio 1;OK
+--stp-root-prio 2:1;;FAIL
+--stp-root-cost :2;--stp-root-cost 0:2;OK
+--stp-root-cost 2:;--stp-root-cost 2:4294967295;OK
+--stp-root-cost 1:2;=;OK
+--stp-root-cost 1:1;--stp-root-cost 1;OK
+--stp-root-cost 2:1;;FAIL
+--stp-sender-prio :2;--stp-sender-prio 0:2;OK
+--stp-sender-prio 2:;--stp-sender-prio 2:65535;OK
+--stp-sender-prio 1:2;=;OK
+--stp-sender-prio 1:1;--stp-sender-prio 1;OK
+--stp-sender-prio 2:1;;FAIL
+--stp-port :;--stp-port 0:65535;OK
+--stp-port :2;--stp-port 0:2;OK
+--stp-port 2:;--stp-port 2:65535;OK
+--stp-port 1:2;=;OK
+--stp-port 1:1;--stp-port 1;OK
+--stp-port 2:1;;FAIL
+--stp-msg-age :;--stp-msg-age 0:65535;OK
+--stp-msg-age :2;--stp-msg-age 0:2;OK
+--stp-msg-age 2:;--stp-msg-age 2:65535;OK
+--stp-msg-age 1:2;=;OK
+--stp-msg-age 1:1;--stp-msg-age 1;OK
+--stp-msg-age 2:1;;FAIL
+--stp-max-age :;--stp-max-age 0:65535;OK
+--stp-max-age :2;--stp-max-age 0:2;OK
+--stp-max-age 2:;--stp-max-age 2:65535;OK
+--stp-max-age 1:2;=;OK
+--stp-max-age 1:1;--stp-max-age 1;OK
+--stp-max-age 2:1;;FAIL
+--stp-hello-time :;--stp-hello-time 0:65535;OK
+--stp-hello-time :2;--stp-hello-time 0:2;OK
+--stp-hello-time 2:;--stp-hello-time 2:65535;OK
+--stp-hello-time 1:2;=;OK
+--stp-hello-time 1:1;--stp-hello-time 1;OK
+--stp-hello-time 2:1;;FAIL
+--stp-forward-delay :;--stp-forward-delay 0:65535;OK
+--stp-forward-delay :2;--stp-forward-delay 0:2;OK
+--stp-forward-delay 2:;--stp-forward-delay 2:65535;OK
+--stp-forward-delay 1:2;=;OK
+--stp-forward-delay 1:1;--stp-forward-delay 1;OK
+--stp-forward-delay 2:1;;FAIL
diff --git a/extensions/libebt_vlan.c b/extensions/libebt_vlan.c
index fa697921..b9f6c519 100644
--- a/extensions/libebt_vlan.c
+++ b/extensions/libebt_vlan.c
@@ -9,7 +9,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
#include <ctype.h>
#include <xtables.h>
#include <netinet/if_ether.h>
@@ -18,89 +17,56 @@
#include "iptables/nft.h"
#include "iptables/nft-bridge.h"
-#define NAME_VLAN_ID "id"
-#define NAME_VLAN_PRIO "prio"
-#define NAME_VLAN_ENCAP "encap"
-
-#define VLAN_ID '1'
-#define VLAN_PRIO '2'
-#define VLAN_ENCAP '3'
-
-static const struct option brvlan_opts[] = {
- {"vlan-id" , required_argument, NULL, VLAN_ID},
- {"vlan-prio" , required_argument, NULL, VLAN_PRIO},
- {"vlan-encap", required_argument, NULL, VLAN_ENCAP},
- XT_GETOPT_TABLEEND,
+static const struct xt_option_entry brvlan_opts[] =
+{
+ { .name = "vlan-id", .id = EBT_VLAN_ID, .type = XTTYPE_UINT16,
+ .max = 4094, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_vlan_info, id) },
+ { .name = "vlan-prio", .id = EBT_VLAN_PRIO, .type = XTTYPE_UINT8,
+ .max = 7, .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct ebt_vlan_info, prio) },
+ { .name = "vlan-encap", .id = EBT_VLAN_ENCAP, .type = XTTYPE_STRING,
+ .flags = XTOPT_INVERT },
+ XTOPT_TABLEEND,
};
-/*
- * option inverse flags definition
- */
-#define OPT_VLAN_ID 0x01
-#define OPT_VLAN_PRIO 0x02
-#define OPT_VLAN_ENCAP 0x04
-#define OPT_VLAN_FLAGS (OPT_VLAN_ID | OPT_VLAN_PRIO | OPT_VLAN_ENCAP)
-
static void brvlan_print_help(void)
{
printf(
"vlan options:\n"
-"--vlan-id [!] id : vlan-tagged frame identifier, 0,1-4096 (integer)\n"
-"--vlan-prio [!] prio : Priority-tagged frame's user priority, 0-7 (integer)\n"
-"--vlan-encap [!] encap : Encapsulated frame protocol (hexadecimal or name)\n");
+"[!] --vlan-id id : vlan-tagged frame identifier, 0,1-4096 (integer)\n"
+"[!] --vlan-prio prio : Priority-tagged frame's user priority, 0-7 (integer)\n"
+"[!] --vlan-encap encap : Encapsulated frame protocol (hexadecimal or name)\n");
}
-static int
-brvlan_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
+static void brvlan_parse(struct xt_option_call *cb)
{
- struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) (*match)->data;
+ struct ebt_vlan_info *vlaninfo = cb->data;
struct xt_ethertypeent *ethent;
char *end;
- struct ebt_vlan_info local;
-
- switch (c) {
- case VLAN_ID:
- EBT_CHECK_OPTION(flags, OPT_VLAN_ID);
- if (invert)
- vlaninfo->invflags |= EBT_VLAN_ID;
- local.id = strtoul(optarg, &end, 10);
- if (local.id > 4094 || *end != '\0')
- xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-id range ('%s')", optarg);
- vlaninfo->id = local.id;
- vlaninfo->bitmask |= EBT_VLAN_ID;
- break;
- case VLAN_PRIO:
- EBT_CHECK_OPTION(flags, OPT_VLAN_PRIO);
- if (invert)
- vlaninfo->invflags |= EBT_VLAN_PRIO;
- local.prio = strtoul(optarg, &end, 10);
- if (local.prio >= 8 || *end != '\0')
- xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-prio range ('%s')", optarg);
- vlaninfo->prio = local.prio;
- vlaninfo->bitmask |= EBT_VLAN_PRIO;
- break;
- case VLAN_ENCAP:
- EBT_CHECK_OPTION(flags, OPT_VLAN_ENCAP);
- if (invert)
- vlaninfo->invflags |= EBT_VLAN_ENCAP;
- local.encap = strtoul(optarg, &end, 16);
+
+ xtables_option_parse(cb);
+
+ vlaninfo->bitmask |= cb->entry->id;
+ if (cb->invert)
+ vlaninfo->invflags |= cb->entry->id;
+
+ if (cb->entry->id == EBT_VLAN_ENCAP) {
+ vlaninfo->encap = strtoul(cb->arg, &end, 16);
if (*end != '\0') {
- ethent = xtables_getethertypebyname(optarg);
+ ethent = xtables_getethertypebyname(cb->arg);
if (ethent == NULL)
- xtables_error(PARAMETER_PROBLEM, "Unknown --vlan-encap value ('%s')", optarg);
- local.encap = ethent->e_ethertype;
+ xtables_error(PARAMETER_PROBLEM,
+ "Unknown --vlan-encap value ('%s')",
+ cb->arg);
+ vlaninfo->encap = ethent->e_ethertype;
}
- if (local.encap < ETH_ZLEN)
- xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-encap range ('%s')", optarg);
- vlaninfo->encap = htons(local.encap);
- vlaninfo->bitmask |= EBT_VLAN_ENCAP;
- break;
- default:
- return 0;
-
+ if (vlaninfo->encap < ETH_ZLEN)
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid --vlan-encap range ('%s')",
+ cb->arg);
+ vlaninfo->encap = htons(vlaninfo->encap);
}
- return 1;
}
static void brvlan_print(const void *ip, const struct xt_entry_match *match,
@@ -109,14 +75,19 @@ static void brvlan_print(const void *ip, const struct xt_entry_match *match,
struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data;
if (vlaninfo->bitmask & EBT_VLAN_ID) {
- printf("--vlan-id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "", vlaninfo->id);
+ printf("%s--vlan-id %d ",
+ (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "",
+ vlaninfo->id);
}
if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
- printf("--vlan-prio %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "", vlaninfo->prio);
+ printf("%s--vlan-prio %d ",
+ (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "",
+ vlaninfo->prio);
}
if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
- printf("--vlan-encap %s", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : "");
- printf("%4.4X ", ntohs(vlaninfo->encap));
+ printf("%s--vlan-encap %4.4X ",
+ (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : "",
+ ntohs(vlaninfo->encap));
}
}
@@ -144,10 +115,10 @@ static struct xtables_match brvlan_match = {
.size = XT_ALIGN(sizeof(struct ebt_vlan_info)),
.userspacesize = XT_ALIGN(sizeof(struct ebt_vlan_info)),
.help = brvlan_print_help,
- .parse = brvlan_parse,
+ .x6_parse = brvlan_parse,
.print = brvlan_print,
.xlate = brvlan_xlate,
- .extra_opts = brvlan_opts,
+ .x6_options = brvlan_opts,
};
void _init(void)
diff --git a/extensions/libebt_vlan.t b/extensions/libebt_vlan.t
index 81c79585..e009ad71 100644
--- a/extensions/libebt_vlan.t
+++ b/extensions/libebt_vlan.t
@@ -1,13 +1,13 @@
:INPUT,FORWARD,OUTPUT
-p 802_1Q --vlan-id 42;=;OK
--p 802_1Q --vlan-id ! 42;=;OK
+-p 802_1Q ! --vlan-id 42;=;OK
-p 802_1Q --vlan-prio 1;=;OK
--p 802_1Q --vlan-prio ! 1;=;OK
+-p 802_1Q ! --vlan-prio 1;=;OK
-p 802_1Q --vlan-encap ip;-p 802_1Q --vlan-encap 0800 -j CONTINUE;OK
--p 802_1Q --vlan-encap 0800 ;=;OK
--p 802_1Q --vlan-encap ! 0800 ;=;OK
--p 802_1Q --vlan-encap IPv6 ! --vlan-id 1;-p 802_1Q --vlan-id ! 1 --vlan-encap 86DD -j CONTINUE;OK
--p 802_1Q --vlan-id ! 1 --vlan-encap 86DD;=;OK
+-p 802_1Q --vlan-encap 0800;=;OK
+-p 802_1Q ! --vlan-encap 0800;=;OK
+-p 802_1Q --vlan-encap IPv6 --vlan-id ! 1;-p 802_1Q ! --vlan-id 1 --vlan-encap 86DD -j CONTINUE;OK
+-p 802_1Q ! --vlan-id 1 --vlan-encap 86DD;=;OK
--vlan-encap ip;=;FAIL
--vlan-id 2;=;FAIL
--vlan-prio 1;=;FAIL
diff --git a/extensions/libebt_vlan.txlate b/extensions/libebt_vlan.txlate
index 2ab62d53..6e12e2d0 100644
--- a/extensions/libebt_vlan.txlate
+++ b/extensions/libebt_vlan.txlate
@@ -1,11 +1,11 @@
ebtables-translate -A INPUT -p 802_1Q --vlan-id 42
-nft add rule bridge filter INPUT vlan id 42 counter
+nft 'add rule bridge filter INPUT vlan id 42 counter'
-ebtables-translate -A INPUT -p 802_1Q --vlan-prio ! 1
-nft add rule bridge filter INPUT vlan pcp != 1 counter
+ebtables-translate -A INPUT -p 802_1Q ! --vlan-prio 1
+nft 'add rule bridge filter INPUT vlan pcp != 1 counter'
ebtables-translate -A INPUT -p 802_1Q --vlan-encap ip
-nft add rule bridge filter INPUT vlan type 0x0800 counter
+nft 'add rule bridge filter INPUT vlan type 0x0800 counter'
ebtables-translate -A INPUT -p 802_1Q --vlan-encap ipv6 ! --vlan-id 1
-nft add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter
+nft 'add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter'
diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c
deleted file mode 100644
index 89c5ceb1..00000000
--- a/extensions/libip6t_DNAT.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
- *
- * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT
- * funded by Astaro.
- */
-
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <iptables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_DEST = 0,
- O_RANDOM,
- O_PERSISTENT,
- O_X_TO_DEST,
- F_TO_DEST = 1 << O_TO_DEST,
- F_RANDOM = 1 << O_RANDOM,
- F_X_TO_DEST = 1 << O_X_TO_DEST,
-};
-
-static void DNAT_help(void)
-{
- printf(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static void DNAT_help_v2(void)
-{
- printf(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static const struct xt_option_entry DNAT_opts[] = {
- {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-/* Ranges expected in network order. */
-static void
-parse_to(const char *orig_arg, int portok, struct nf_nat_range2 *range, int rev)
-{
- char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
- const struct in6_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
-
- start = strchr(arg, '[');
- if (start == NULL) {
- start = arg;
- /* Lets assume one colon is port information. Otherwise its an IPv6 address */
- colon = strchr(arg, ':');
- if (colon && strchr(colon+1, ':'))
- colon = NULL;
- }
- else {
- start++;
- end = strchr(start, ']');
- if (end == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid address format");
-
- *end = '\0';
- colon = strchr(end + 1, ':');
- }
-
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range->min_proto.tcp.port
- = range->max_proto.tcp.port
- = htons(port);
- } else {
- int maxport;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* People are stupid. */
- xtables_error(PARAMETER_PROBLEM,
- "Port range `%s' funky\n", colon+1);
- range->min_proto.tcp.port = htons(port);
- range->max_proto.tcp.port = htons(maxport);
-
- if (rev >= 2) {
- char *slash = strchr(dash, '/');
- if (slash) {
- int baseport;
-
- baseport = atoi(slash + 1);
- if (baseport <= 0 || baseport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", slash+1);
- range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
- range->base_proto.tcp.port = htons(baseport);
- }
- }
- }
- /* Starts with colon or [] colon? No IP info...*/
- if (colon == arg || colon == arg+2) {
- free(arg);
- return;
- }
- *colon = '\0';
- }
-
- range->flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(start, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ip6addr(start);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- start);
- range->min_addr.in6 = *ip;
- if (dash) {
- ip = xtables_numeric_to_ip6addr(dash + 1);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- dash+1);
- range->max_addr.in6 = *ip;
- } else
- range->max_addr = range->min_addr;
-
- free(arg);
- return;
-}
-
-static void _DNAT_parse(struct xt_option_call *cb,
- struct nf_nat_range2 *range, int rev)
-{
- const struct ip6t_entry *entry = cb->xt_entry;
- int portok;
-
- if (entry->ipv6.proto == IPPROTO_TCP ||
- entry->ipv6.proto == IPPROTO_UDP ||
- entry->ipv6.proto == IPPROTO_SCTP ||
- entry->ipv6.proto == IPPROTO_DCCP ||
- entry->ipv6.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_DEST:
- if (cb->xflags & F_X_TO_DEST) {
- xtables_error(PARAMETER_PROBLEM,
- "DNAT: Multiple --to-destination not supported");
- }
- parse_to(cb->arg, portok, range, rev);
- cb->xflags |= F_X_TO_DEST;
- break;
- case O_PERSISTENT:
- range->flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void DNAT_parse(struct xt_option_call *cb)
-{
- struct nf_nat_range *range_v1 = (void *)cb->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_parse(cb, &range, 1);
- memcpy(range_v1, &range, sizeof(*range_v1));
-}
-
-static void DNAT_parse_v2(struct xt_option_call *cb)
-{
- _DNAT_parse(cb, (struct nf_nat_range2 *)cb->data, 2);
-}
-
-static void _DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags)
-{
- static const unsigned int f = F_TO_DEST | F_RANDOM;
-
- if ((cb->xflags & f) == f)
- *flags |= NF_NAT_RANGE_PROTO_RANDOM;
-}
-
-static void DNAT_fcheck(struct xt_fcheck_call *cb)
-{
- _DNAT_fcheck(cb, &((struct nf_nat_range *)cb->data)->flags);
-}
-
-static void DNAT_fcheck_v2(struct xt_fcheck_call *cb)
-{
- _DNAT_fcheck(cb, &((struct nf_nat_range2 *)cb->data)->flags);
-}
-
-static void print_range(const struct nf_nat_range2 *range, int rev)
-{
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
- printf("[");
- printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6));
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr)))
- printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6));
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
- printf("]");
- }
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (rev >= 2 && (range->flags & NF_NAT_RANGE_PROTO_OFFSET))
- printf("/%hu", ntohs(range->base_proto.tcp.port));
- }
-}
-
-static void _DNAT_print(const struct nf_nat_range2 *range, int rev)
-{
- printf(" to:");
- print_range(range, rev);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
-}
-
-static void DNAT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range *range_v1 = (const void *)target->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_print(&range, 1);
-}
-
-static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- _DNAT_print((const struct nf_nat_range2 *)target->data, 2);
-}
-
-static void _DNAT_save(const struct nf_nat_range2 *range, int rev)
-{
- printf(" --to-destination ");
- print_range(range, rev);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
-}
-
-static void DNAT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range *range_v1 = (const void *)target->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_save(&range, 1);
-}
-
-static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target)
-{
- _DNAT_save((const struct nf_nat_range2 *)target->data, 2);
-}
-
-static void print_range_xlate(const struct nf_nat_range2 *range,
- struct xt_xlate *xl, int rev)
-{
- bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- xt_xlate_add(xl, "%s%s%s",
- proto_specified ? "[" : "",
- xtables_ip6addr_to_numeric(&range->min_addr.in6),
- proto_specified ? "]" : "");
-
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr))) {
- xt_xlate_add(xl, "-%s%s%s",
- proto_specified ? "[" : "",
- xtables_ip6addr_to_numeric(&range->max_addr.in6),
- proto_specified ? "]" : "");
- }
- }
- if (proto_specified) {
- xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
-
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu",
- ntohs(range->max_proto.tcp.port));
- }
-}
-
-static int _DNAT_xlate(struct xt_xlate *xl,
- const struct nf_nat_range2 *range, int rev)
-{
- bool sep_need = false;
- const char *sep = " ";
-
- xt_xlate_add(xl, "dnat to ");
- print_range_xlate(range, xl, rev);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (range->flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
-
- return 1;
-}
-
-static int DNAT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range *range_v1 = (const void *)params->target->data;
- struct nf_nat_range2 range = {};
-
- memcpy(&range, range_v1, sizeof(*range_v1));
- _DNAT_xlate(xl, &range, 1);
-
- return 1;
-}
-
-static int DNAT_xlate_v2(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- _DNAT_xlate(xl, (const struct nf_nat_range2 *)params->target->data, 2);
-
- return 1;
-}
-
-static struct xtables_target dnat_tg_reg[] = {
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .revision = 1,
- .size = XT_ALIGN(sizeof(struct nf_nat_range)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
- .help = DNAT_help,
- .print = DNAT_print,
- .save = DNAT_save,
- .x6_parse = DNAT_parse,
- .x6_fcheck = DNAT_fcheck,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate,
- },
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .revision = 2,
- .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .help = DNAT_help_v2,
- .print = DNAT_print_v2,
- .save = DNAT_save_v2,
- .x6_parse = DNAT_parse_v2,
- .x6_fcheck = DNAT_fcheck_v2,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate_v2,
- },
-};
-
-void _init(void)
-{
- xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg));
-}
diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t
index ec7d61f4..e53dfa16 100644
--- a/extensions/libip6t_DNAT.t
+++ b/extensions/libip6t_DNAT.t
@@ -13,4 +13,8 @@
-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65535;=;OK
-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/0;;FAIL
-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65536;;FAIL
+-p tcp -j DNAT --to-destination [dead::beef]:ssh;-p tcp -j DNAT --to-destination [dead::beef]:22;OK
+-p tcp -j DNAT --to-destination [dead::beef]:ftp-data;-p tcp -j DNAT --to-destination [dead::beef]:20;OK
+-p tcp -j DNAT --to-destination [dead::beef]:echo-ssh;;FAIL
+-p tcp -j DNAT --to-destination [dead::beef]:10-20/ftp;-p tcp -j DNAT --to-destination [dead::beef]:10-20/21;OK
-j DNAT;;FAIL
diff --git a/extensions/libip6t_DNAT.txlate b/extensions/libip6t_DNAT.txlate
deleted file mode 100644
index 03c4caf7..00000000
--- a/extensions/libip6t_DNAT.txlate
+++ /dev/null
@@ -1,11 +0,0 @@
-ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80
-nft add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80
-
-ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20
-nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20
-
-ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent
-nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent
-
-ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent
-nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent
diff --git a/extensions/libip6t_DNPT.man b/extensions/libip6t_DNPT.man
index 9b060f5b..2c4ae61b 100644
--- a/extensions/libip6t_DNPT.man
+++ b/extensions/libip6t_DNPT.man
@@ -15,11 +15,11 @@ Set destination prefix that you want to use in the translation and length
.PP
You have to use the SNPT target to undo the translation. Example:
.IP
-ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 \! \-o vboxnet0
+ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 ! \-o vboxnet0
\-j SNPT \-\-src-pfx fd00::/64 \-\-dst-pfx 2001:e20:2000:40f::/64
.IP
ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
-\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst-pfx fd00::/64
+\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst\-pfx fd00::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
diff --git a/extensions/libip6t_LOG.c b/extensions/libip6t_LOG.c
deleted file mode 100644
index 40adc69d..00000000
--- a/extensions/libip6t_LOG.c
+++ /dev/null
@@ -1,250 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <xtables.h>
-#include <linux/netfilter_ipv6/ip6t_LOG.h>
-
-#ifndef IP6T_LOG_UID /* Old kernel */
-#define IP6T_LOG_UID 0x08
-#undef IP6T_LOG_MASK
-#define IP6T_LOG_MASK 0x0f
-#endif
-
-#define LOG_DEFAULT_LEVEL LOG_WARNING
-
-enum {
- O_LOG_LEVEL = 0,
- O_LOG_PREFIX,
- O_LOG_TCPSEQ,
- O_LOG_TCPOPTS,
- O_LOG_IPOPTS,
- O_LOG_UID,
- O_LOG_MAC,
-};
-
-static void LOG_help(void)
-{
- printf(
-"LOG target options:\n"
-" --log-level level Level of logging (numeric or see syslog.conf)\n"
-" --log-prefix prefix Prefix log messages with this prefix.\n"
-" --log-tcp-sequence Log TCP sequence numbers.\n"
-" --log-tcp-options Log TCP options.\n"
-" --log-ip-options Log IP options.\n"
-" --log-uid Log UID owning the local socket.\n"
-" --log-macdecode Decode MAC addresses and protocol.\n");
-}
-
-#define s struct ip6t_log_info
-static const struct xt_option_entry LOG_opts[] = {
- {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, level)},
- {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1},
- {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE},
- {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE},
- {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE},
- {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE},
- {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-#undef s
-
-static void LOG_init(struct xt_entry_target *t)
-{
- struct ip6t_log_info *loginfo = (struct ip6t_log_info *)t->data;
-
- loginfo->level = LOG_DEFAULT_LEVEL;
-
-}
-
-struct ip6t_log_names {
- const char *name;
- unsigned int level;
-};
-
-struct ip6t_log_xlate {
- const char *name;
- unsigned int level;
-};
-
-static const struct ip6t_log_names ip6t_log_names[]
-= { { .name = "alert", .level = LOG_ALERT },
- { .name = "crit", .level = LOG_CRIT },
- { .name = "debug", .level = LOG_DEBUG },
- { .name = "emerg", .level = LOG_EMERG },
- { .name = "error", .level = LOG_ERR }, /* DEPRECATED */
- { .name = "info", .level = LOG_INFO },
- { .name = "notice", .level = LOG_NOTICE },
- { .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */
- { .name = "warning", .level = LOG_WARNING }
-};
-
-static void LOG_parse(struct xt_option_call *cb)
-{
- struct ip6t_log_info *info = cb->data;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_LOG_PREFIX:
- if (strchr(cb->arg, '\n') != NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Newlines not allowed in --log-prefix");
- break;
- case O_LOG_TCPSEQ:
- info->logflags |= IP6T_LOG_TCPSEQ;
- break;
- case O_LOG_TCPOPTS:
- info->logflags |= IP6T_LOG_TCPOPT;
- break;
- case O_LOG_IPOPTS:
- info->logflags |= IP6T_LOG_IPOPT;
- break;
- case O_LOG_UID:
- info->logflags |= IP6T_LOG_UID;
- break;
- case O_LOG_MAC:
- info->logflags |= IP6T_LOG_MACDECODE;
- break;
- }
-}
-
-static void LOG_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct ip6t_log_info *loginfo
- = (const struct ip6t_log_info *)target->data;
- unsigned int i = 0;
-
- printf(" LOG");
- if (numeric)
- printf(" flags %u level %u",
- loginfo->logflags, loginfo->level);
- else {
- for (i = 0; i < ARRAY_SIZE(ip6t_log_names); ++i)
- if (loginfo->level == ip6t_log_names[i].level) {
- printf(" level %s", ip6t_log_names[i].name);
- break;
- }
- if (i == ARRAY_SIZE(ip6t_log_names))
- printf(" UNKNOWN level %u", loginfo->level);
- if (loginfo->logflags & IP6T_LOG_TCPSEQ)
- printf(" tcp-sequence");
- if (loginfo->logflags & IP6T_LOG_TCPOPT)
- printf(" tcp-options");
- if (loginfo->logflags & IP6T_LOG_IPOPT)
- printf(" ip-options");
- if (loginfo->logflags & IP6T_LOG_UID)
- printf(" uid");
- if (loginfo->logflags & IP6T_LOG_MACDECODE)
- printf(" macdecode");
- if (loginfo->logflags & ~(IP6T_LOG_MASK))
- printf(" unknown-flags");
- }
-
- if (strcmp(loginfo->prefix, "") != 0)
- printf(" prefix \"%s\"", loginfo->prefix);
-}
-
-static void LOG_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct ip6t_log_info *loginfo
- = (const struct ip6t_log_info *)target->data;
-
- if (strcmp(loginfo->prefix, "") != 0) {
- printf(" --log-prefix");
- xtables_save_string(loginfo->prefix);
- }
-
- if (loginfo->level != LOG_DEFAULT_LEVEL)
- printf(" --log-level %d", loginfo->level);
-
- if (loginfo->logflags & IP6T_LOG_TCPSEQ)
- printf(" --log-tcp-sequence");
- if (loginfo->logflags & IP6T_LOG_TCPOPT)
- printf(" --log-tcp-options");
- if (loginfo->logflags & IP6T_LOG_IPOPT)
- printf(" --log-ip-options");
- if (loginfo->logflags & IP6T_LOG_UID)
- printf(" --log-uid");
- if (loginfo->logflags & IP6T_LOG_MACDECODE)
- printf(" --log-macdecode");
-}
-
-static const struct ip6t_log_xlate ip6t_log_xlate_names[] = {
- {"alert", LOG_ALERT },
- {"crit", LOG_CRIT },
- {"debug", LOG_DEBUG },
- {"emerg", LOG_EMERG },
- {"err", LOG_ERR },
- {"info", LOG_INFO },
- {"notice", LOG_NOTICE },
- {"warn", LOG_WARNING }
-};
-
-static int LOG_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct ip6t_log_info *loginfo =
- (const struct ip6t_log_info *)params->target->data;
- unsigned int i = 0;
-
- xt_xlate_add(xl, "log");
- if (strcmp(loginfo->prefix, "") != 0) {
- if (params->escape_quotes)
- xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix);
- else
- xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
- }
-
- for (i = 0; i < ARRAY_SIZE(ip6t_log_xlate_names); ++i)
- if (loginfo->level == ip6t_log_xlate_names[i].level &&
- loginfo->level != LOG_DEFAULT_LEVEL) {
- xt_xlate_add(xl, " level %s",
- ip6t_log_xlate_names[i].name);
- break;
- }
-
- if ((loginfo->logflags & IP6T_LOG_MASK) == IP6T_LOG_MASK) {
- xt_xlate_add(xl, " flags all");
- } else {
- if (loginfo->logflags & (IP6T_LOG_TCPSEQ | IP6T_LOG_TCPOPT)) {
- const char *delim = " ";
-
- xt_xlate_add(xl, " flags tcp");
- if (loginfo->logflags & IP6T_LOG_TCPSEQ) {
- xt_xlate_add(xl, " sequence");
- delim = ",";
- }
- if (loginfo->logflags & IP6T_LOG_TCPOPT)
- xt_xlate_add(xl, "%soptions", delim);
- }
- if (loginfo->logflags & IP6T_LOG_IPOPT)
- xt_xlate_add(xl, " flags ip options");
- if (loginfo->logflags & IP6T_LOG_UID)
- xt_xlate_add(xl, " flags skuid");
- if (loginfo->logflags & IP6T_LOG_MACDECODE)
- xt_xlate_add(xl, " flags ether");
- }
-
- return 1;
-}
-static struct xtables_target log_tg6_reg = {
- .name = "LOG",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct ip6t_log_info)),
- .userspacesize = XT_ALIGN(sizeof(struct ip6t_log_info)),
- .help = LOG_help,
- .init = LOG_init,
- .print = LOG_print,
- .save = LOG_save,
- .x6_parse = LOG_parse,
- .x6_options = LOG_opts,
- .xlate = LOG_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&log_tg6_reg);
-}
diff --git a/extensions/libip6t_LOG.txlate b/extensions/libip6t_LOG.txlate
index 2820a82c..29ffce72 100644
--- a/extensions/libip6t_LOG.txlate
+++ b/extensions/libip6t_LOG.txlate
@@ -1,8 +1,8 @@
iptables-translate -I INPUT -j LOG
-nft insert rule ip filter INPUT counter log
+nft 'insert rule ip filter INPUT counter log'
ip6tables-translate -A FORWARD -p tcp -j LOG --log-level debug
-nft add rule ip6 filter FORWARD meta l4proto tcp counter log level debug
+nft 'add rule ip6 filter FORWARD meta l4proto tcp counter log level debug'
ip6tables-translate -A FORWARD -p tcp -j LOG --log-prefix "Checking log"
-nft add rule ip6 filter FORWARD meta l4proto tcp counter log prefix \"Checking log\"
+nft 'add rule ip6 filter FORWARD meta l4proto tcp counter log prefix "Checking log"'
diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c
deleted file mode 100644
index f92760fa..00000000
--- a/extensions/libip6t_MASQUERADE.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
- *
- * Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT
- * funded by Astaro.
- */
-
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <xtables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_PORTS = 0,
- O_RANDOM,
- O_RANDOM_FULLY,
-};
-
-static void MASQUERADE_help(void)
-{
- printf(
-"MASQUERADE target options:\n"
-" --to-ports <port>[-<port>]\n"
-" Port (range) to map to.\n"
-" --random\n"
-" Randomize source port.\n"
-" --random-fully\n"
-" Fully randomize source port.\n");
-}
-
-static const struct xt_option_entry MASQUERADE_opts[] = {
- {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-/* Parses ports */
-static void
-parse_ports(const char *arg, struct nf_nat_range *r)
-{
- char *end;
- unsigned int port, maxport;
-
- r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
- xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
-
- switch (*end) {
- case '\0':
- r->min_proto.tcp.port
- = r->max_proto.tcp.port
- = htons(port);
- return;
- case '-':
- if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
- break;
-
- if (maxport < port)
- break;
-
- r->min_proto.tcp.port = htons(port);
- r->max_proto.tcp.port = htons(maxport);
- return;
- default:
- break;
- }
- xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
-}
-
-static void MASQUERADE_parse(struct xt_option_call *cb)
-{
- const struct ip6t_entry *entry = cb->xt_entry;
- struct nf_nat_range *r = cb->data;
- int portok;
-
- if (entry->ipv6.proto == IPPROTO_TCP ||
- entry->ipv6.proto == IPPROTO_UDP ||
- entry->ipv6.proto == IPPROTO_SCTP ||
- entry->ipv6.proto == IPPROTO_DCCP ||
- entry->ipv6.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_PORTS:
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
- parse_ports(cb->arg, r);
- break;
- case O_RANDOM:
- r->flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- case O_RANDOM_FULLY:
- r->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
- break;
- }
-}
-
-static void
-MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range *r = (const void *)target->data;
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" masq ports: ");
- printf("%hu", ntohs(r->min_proto.tcp.port));
- if (r->max_proto.tcp.port != r->min_proto.tcp.port)
- printf("-%hu", ntohs(r->max_proto.tcp.port));
- }
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" random-fully");
-}
-
-static void
-MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range *r = (const void *)target->data;
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port));
- if (r->max_proto.tcp.port != r->min_proto.tcp.port)
- printf("-%hu", ntohs(r->max_proto.tcp.port));
- }
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" --random-fully");
-}
-
-static int MASQUERADE_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range *r = (const void *)params->target->data;
-
- xt_xlate_add(xl, "masquerade");
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, " to :%hu", ntohs(r->min_proto.tcp.port));
- if (r->max_proto.tcp.port != r->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu", ntohs(r->max_proto.tcp.port));
- }
-
- xt_xlate_add(xl, " ");
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
- xt_xlate_add(xl, "random ");
-
- xt_xlate_add(xl, " ");
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- xt_xlate_add(xl, "random-fully ");
-
- return 1;
-}
-
-static struct xtables_target masquerade_tg_reg = {
- .name = "MASQUERADE",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct nf_nat_range)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
- .help = MASQUERADE_help,
- .x6_parse = MASQUERADE_parse,
- .print = MASQUERADE_print,
- .save = MASQUERADE_save,
- .x6_options = MASQUERADE_opts,
- .xlate = MASQUERADE_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&masquerade_tg_reg);
-}
diff --git a/extensions/libip6t_MASQUERADE.txlate b/extensions/libip6t_MASQUERADE.txlate
index 6c289c2b..3f003477 100644
--- a/extensions/libip6t_MASQUERADE.txlate
+++ b/extensions/libip6t_MASQUERADE.txlate
@@ -1,8 +1,17 @@
ip6tables-translate -t nat -A POSTROUTING -j MASQUERADE
-nft add rule ip6 nat POSTROUTING counter masquerade
+nft 'add rule ip6 nat POSTROUTING counter masquerade'
ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10
-nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10
+nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10'
ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random
-nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random
+nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random'
+
+ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random
+nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random'
+
+ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully
+nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade fully-random'
+
+ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully
+nft 'add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade random,fully-random'
diff --git a/extensions/libip6t_NETMAP.t b/extensions/libip6t_NETMAP.t
index 043562d2..79d47bf6 100644
--- a/extensions/libip6t_NETMAP.t
+++ b/extensions/libip6t_NETMAP.t
@@ -1,4 +1,4 @@
:PREROUTING,INPUT,OUTPUT,POSTROUTING
*nat
-j NETMAP --to dead::/64;=;OK
--j NETMAP --to dead::beef;=;OK
+-j NETMAP --to dead::beef;-j NETMAP --to dead::beef/128;OK
diff --git a/extensions/libip6t_REDIRECT.c b/extensions/libip6t_REDIRECT.c
deleted file mode 100644
index 8e04d2cd..00000000
--- a/extensions/libip6t_REDIRECT.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
- *
- * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT
- * funded by Astaro.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_PORTS = 0,
- O_RANDOM,
- F_TO_PORTS = 1 << O_TO_PORTS,
- F_RANDOM = 1 << O_RANDOM,
-};
-
-static void REDIRECT_help(void)
-{
- printf(
-"REDIRECT target options:\n"
-" --to-ports <port>[-<port>]\n"
-" Port (range) to map to.\n"
-" [--random]\n");
-}
-
-static const struct xt_option_entry REDIRECT_opts[] = {
- {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-/* Parses ports */
-static void
-parse_ports(const char *arg, struct nf_nat_range *range)
-{
- char *end = "";
- unsigned int port, maxport;
-
- range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) &&
- (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1)
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-
- switch (*end) {
- case '\0':
- range->min_proto.tcp.port
- = range->max_proto.tcp.port
- = htons(port);
- return;
- case '-':
- if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) &&
- (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1)
- break;
-
- if (maxport < port)
- break;
-
- range->min_proto.tcp.port = htons(port);
- range->max_proto.tcp.port = htons(maxport);
- return;
- default:
- break;
- }
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-}
-
-static void REDIRECT_parse(struct xt_option_call *cb)
-{
- const struct ip6t_entry *entry = cb->xt_entry;
- struct nf_nat_range *range = (void *)(*cb->target)->data;
- int portok;
-
- if (entry->ipv6.proto == IPPROTO_TCP
- || entry->ipv6.proto == IPPROTO_UDP
- || entry->ipv6.proto == IPPROTO_SCTP
- || entry->ipv6.proto == IPPROTO_DCCP
- || entry->ipv6.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_PORTS:
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
- parse_ports(cb->arg, range);
- if (cb->xflags & F_RANDOM)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- case O_RANDOM:
- if (cb->xflags & F_TO_PORTS)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- }
-}
-
-static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range *range = (const void *)target->data;
-
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" redir ports ");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- }
-}
-
-static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range *range = (const void *)target->data;
-
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" --to-ports ");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- }
-}
-
-static int REDIRECT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range *range = (const void *)params->target->data;
-
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, "redirect to :%hu",
- ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu ",
- ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- xt_xlate_add(xl, " random ");
- }
-
- return 1;
-}
-
-static struct xtables_target redirect_tg_reg = {
- .name = "REDIRECT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct nf_nat_range)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
- .help = REDIRECT_help,
- .x6_parse = REDIRECT_parse,
- .print = REDIRECT_print,
- .save = REDIRECT_save,
- .x6_options = REDIRECT_opts,
- .xlate = REDIRECT_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&redirect_tg_reg);
-}
diff --git a/extensions/libip6t_REDIRECT.t b/extensions/libip6t_REDIRECT.t
deleted file mode 100644
index a0fb0ed1..00000000
--- a/extensions/libip6t_REDIRECT.t
+++ /dev/null
@@ -1,6 +0,0 @@
-:PREROUTING,OUTPUT
-*nat
--p tcp -j REDIRECT --to-ports 42;=;OK
--p udp -j REDIRECT --to-ports 42-1234;=;OK
--p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
--j REDIRECT --to-ports 42;;FAIL
diff --git a/extensions/libip6t_REDIRECT.txlate b/extensions/libip6t_REDIRECT.txlate
deleted file mode 100644
index 209f67a4..00000000
--- a/extensions/libip6t_REDIRECT.txlate
+++ /dev/null
@@ -1,5 +0,0 @@
-ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
-nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080
-
-ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
-nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random
diff --git a/extensions/libip6t_REJECT.man b/extensions/libip6t_REJECT.man
index 3c42768e..e68d6f03 100644
--- a/extensions/libip6t_REJECT.man
+++ b/extensions/libip6t_REJECT.man
@@ -44,9 +44,10 @@ response for a packet so classed would then terminate the healthy connection.
.PP
So, instead of:
.PP
--A INPUT ... -j REJECT
+\-A INPUT ... \-j REJECT
.PP
do consider using:
.PP
--A INPUT ... -m conntrack --ctstate INVALID -j DROP
--A INPUT ... -j REJECT
+\-A INPUT ... \-m conntrack \-\-ctstate INVALID \-j DROP
+.br
+\-A INPUT ... \-j REJECT
diff --git a/extensions/libip6t_REJECT.t b/extensions/libip6t_REJECT.t
index d2b337d7..8294f0bb 100644
--- a/extensions/libip6t_REJECT.t
+++ b/extensions/libip6t_REJECT.t
@@ -1,5 +1,5 @@
:INPUT,FORWARD,OUTPUT
--j REJECT;=;OK
+-j REJECT;-j REJECT --reject-with icmp6-port-unreachable;OK
# manpage for IPv6 variant of REJECT does not show up for some reason?
-j REJECT --reject-with icmp6-no-route;=;OK
-j REJECT --reject-with icmp6-adm-prohibited;=;OK
diff --git a/extensions/libip6t_REJECT.txlate b/extensions/libip6t_REJECT.txlate
index cfa35ebf..184713d1 100644
--- a/extensions/libip6t_REJECT.txlate
+++ b/extensions/libip6t_REJECT.txlate
@@ -1,8 +1,8 @@
ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT
-nft add rule ip6 filter FORWARD tcp dport 22 counter reject
+nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject'
ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp6-reject-route
-nft add rule ip6 filter FORWARD tcp dport 22 counter reject with icmpv6 type reject-route
+nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject with icmpv6 type reject-route'
ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset
-nft add rule ip6 filter FORWARD tcp dport 22 counter reject with tcp reset
+nft 'add rule ip6 filter FORWARD tcp dport 22 counter reject with tcp reset'
diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c
deleted file mode 100644
index 7d74b3d7..00000000
--- a/extensions/libip6t_SNAT.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
- *
- * Based on Rusty Russell's IPv4 SNAT target. Development of IPv6 NAT
- * funded by Astaro.
- */
-
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <iptables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_SRC = 0,
- O_RANDOM,
- O_RANDOM_FULLY,
- O_PERSISTENT,
- O_X_TO_SRC,
- F_TO_SRC = 1 << O_TO_SRC,
- F_RANDOM = 1 << O_RANDOM,
- F_RANDOM_FULLY = 1 << O_RANDOM_FULLY,
- F_X_TO_SRC = 1 << O_X_TO_SRC,
-};
-
-static void SNAT_help(void)
-{
- printf(
-"SNAT target options:\n"
-" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
-" Address to map source to.\n"
-"[--random] [--random-fully] [--persistent]\n");
-}
-
-static const struct xt_option_entry SNAT_opts[] = {
- {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
- {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-/* Ranges expected in network order. */
-static void
-parse_to(const char *orig_arg, int portok, struct nf_nat_range *range)
-{
- char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
- const struct in6_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
-
- start = strchr(arg, '[');
- if (start == NULL) {
- start = arg;
- /* Lets assume one colon is port information. Otherwise its an IPv6 address */
- colon = strchr(arg, ':');
- if (colon && strchr(colon+1, ':'))
- colon = NULL;
- }
- else {
- start++;
- end = strchr(start, ']');
- if (end == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid address format");
-
- *end = '\0';
- colon = strchr(end + 1, ':');
- }
-
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range->min_proto.tcp.port
- = range->max_proto.tcp.port
- = htons(port);
- } else {
- int maxport;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* People are stupid. */
- xtables_error(PARAMETER_PROBLEM,
- "Port range `%s' funky\n", colon+1);
- range->min_proto.tcp.port = htons(port);
- range->max_proto.tcp.port = htons(maxport);
- }
- /* Starts with colon or [] colon? No IP info...*/
- if (colon == arg || colon == arg+2) {
- free(arg);
- return;
- }
- *colon = '\0';
- }
-
- range->flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(start, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ip6addr(start);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- start);
- range->min_addr.in6 = *ip;
- if (dash) {
- ip = xtables_numeric_to_ip6addr(dash + 1);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- dash+1);
- range->max_addr.in6 = *ip;
- } else
- range->max_addr = range->min_addr;
-
- free(arg);
- return;
-}
-
-static void SNAT_parse(struct xt_option_call *cb)
-{
- const struct ip6t_entry *entry = cb->xt_entry;
- struct nf_nat_range *range = cb->data;
- int portok;
-
- if (entry->ipv6.proto == IPPROTO_TCP ||
- entry->ipv6.proto == IPPROTO_UDP ||
- entry->ipv6.proto == IPPROTO_SCTP ||
- entry->ipv6.proto == IPPROTO_DCCP ||
- entry->ipv6.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_SRC:
- if (cb->xflags & F_X_TO_SRC) {
- xtables_error(PARAMETER_PROBLEM,
- "SNAT: Multiple --to-source not supported");
- }
- parse_to(cb->arg, portok, range);
- cb->xflags |= F_X_TO_SRC;
- break;
- case O_PERSISTENT:
- range->flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void SNAT_fcheck(struct xt_fcheck_call *cb)
-{
- static const unsigned int f = F_TO_SRC | F_RANDOM;
- static const unsigned int r = F_TO_SRC | F_RANDOM_FULLY;
- struct nf_nat_range *range = cb->data;
-
- if ((cb->xflags & f) == f)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
- if ((cb->xflags & r) == r)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
-}
-
-static void print_range(const struct nf_nat_range *range)
-{
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
- printf("[");
- printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6));
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr)))
- printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6));
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
- printf("]");
- }
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- }
-}
-
-static void SNAT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range *range = (const void *)target->data;
-
- printf(" to:");
- print_range(range);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" random-fully");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
-}
-
-static void SNAT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range *range = (const void *)target->data;
-
- printf(" --to-source ");
- print_range(range);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" --random-fully");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
-}
-
-static void print_range_xlate(const struct nf_nat_range *range,
- struct xt_xlate *xl)
-{
- bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- xt_xlate_add(xl, "%s%s%s",
- proto_specified ? "[" : "",
- xtables_ip6addr_to_numeric(&range->min_addr.in6),
- proto_specified ? "]" : "");
-
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr))) {
- xt_xlate_add(xl, "-%s%s%s",
- proto_specified ? "[" : "",
- xtables_ip6addr_to_numeric(&range->max_addr.in6),
- proto_specified ? "]" : "");
- }
- }
- if (proto_specified) {
- xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
-
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu",
- ntohs(range->max_proto.tcp.port));
- }
-}
-
-static int SNAT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range *range = (const void *)params->target->data;
- bool sep_need = false;
- const char *sep = " ";
-
- xt_xlate_add(xl, "snat to ");
- print_range_xlate(range, xl);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%sfully-random", sep);
- sep_need = true;
- }
- if (range->flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
-
- return 1;
-}
-
-static struct xtables_target snat_tg_reg = {
- .name = "SNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .revision = 1,
- .size = XT_ALIGN(sizeof(struct nf_nat_range)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
- .help = SNAT_help,
- .x6_parse = SNAT_parse,
- .x6_fcheck = SNAT_fcheck,
- .print = SNAT_print,
- .save = SNAT_save,
- .x6_options = SNAT_opts,
- .xlate = SNAT_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&snat_tg_reg);
-}
diff --git a/extensions/libip6t_SNAT.t b/extensions/libip6t_SNAT.t
index d188a6bb..98aa7602 100644
--- a/extensions/libip6t_SNAT.t
+++ b/extensions/libip6t_SNAT.t
@@ -4,6 +4,12 @@
-j SNAT --to-source dead::beef-dead::fee7;=;OK
-j SNAT --to-source [dead::beef]:1025-65535;;FAIL
-j SNAT --to-source [dead::beef] --to-source [dead::fee7];;FAIL
+-j SNAT --to-source dead::beef --random;=;OK
+-j SNAT --to-source dead::beef --random-fully;=;OK
+-j SNAT --to-source dead::beef --persistent;=;OK
+-j SNAT --to-source dead::beef --random --persistent;=;OK
+-j SNAT --to-source dead::beef --random --random-fully;=;OK
+-j SNAT --to-source dead::beef --random --random-fully --persistent;=;OK
-p tcp -j SNAT --to-source [dead::beef]:1025-65535;=;OK
-p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65535;=;OK
-p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65536;;FAIL
diff --git a/extensions/libip6t_SNAT.txlate b/extensions/libip6t_SNAT.txlate
index 44f2fcea..e5f6f735 100644
--- a/extensions/libip6t_SNAT.txlate
+++ b/extensions/libip6t_SNAT.txlate
@@ -1,11 +1,11 @@
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:80
-nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:80
+nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:80'
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:1-20
-nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:1-20
+nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:1-20'
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random
-nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 random
+nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 random'
ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random-fully --persistent
-nft add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent
+nft 'add rule ip6 nat postrouting oifname "eth0" meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent'
diff --git a/extensions/libip6t_SNPT.man b/extensions/libip6t_SNPT.man
index 97e0071b..8741c648 100644
--- a/extensions/libip6t_SNPT.man
+++ b/extensions/libip6t_SNPT.man
@@ -15,11 +15,11 @@ Set destination prefix that you want to use in the translation and length
.PP
You have to use the DNPT target to undo the translation. Example:
.IP
-ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 \! \-o vboxnet0
+ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 ! \-o vboxnet0
\-j SNPT \-\-src-pfx fd00::/64 \-\-dst-pfx 2001:e20:2000:40f::/64
.IP
ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
-\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst-pfx fd00::/64
+\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst\-pfx fd00::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
diff --git a/extensions/libip6t_ah.c b/extensions/libip6t_ah.c
index f35982f3..0f95c473 100644
--- a/extensions/libip6t_ah.c
+++ b/extensions/libip6t_ah.c
@@ -58,13 +58,18 @@ static void ah_parse(struct xt_option_call *cb)
}
}
+static bool skip_spi_match(uint32_t min, uint32_t max, bool inv)
+{
+ return min == 0 && max == UINT32_MAX && !inv;
+}
+
static void
print_spis(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFFFFFFFF || invert) {
+ if (!skip_spi_match(min, max, invert)) {
if (min == max)
printf("%s:%s%u", name, inv, min);
else
@@ -103,11 +108,10 @@ static void ah_print(const void *ip, const struct xt_entry_match *match,
static void ah_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data;
+ bool inv_spi = ahinfo->invflags & IP6T_AH_INV_SPI;
- if (!(ahinfo->spis[0] == 0
- && ahinfo->spis[1] == 0xFFFFFFFF)) {
- printf("%s --ahspi ",
- (ahinfo->invflags & IP6T_AH_INV_SPI) ? " !" : "");
+ if (!skip_spi_match(ahinfo->spis[0], ahinfo->spis[1], inv_spi)) {
+ printf("%s --ahspi ", inv_spi ? " !" : "");
if (ahinfo->spis[0]
!= ahinfo->spis[1])
printf("%u:%u",
@@ -132,11 +136,11 @@ static int ah_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ip6t_ah *ahinfo = (struct ip6t_ah *)params->match->data;
+ bool inv_spi = ahinfo->invflags & IP6T_AH_INV_SPI;
char *space = "";
- if (!(ahinfo->spis[0] == 0 && ahinfo->spis[1] == 0xFFFFFFFF)) {
- xt_xlate_add(xl, "ah spi%s ",
- (ahinfo->invflags & IP6T_AH_INV_SPI) ? " !=" : "");
+ if (!skip_spi_match(ahinfo->spis[0], ahinfo->spis[1], inv_spi)) {
+ xt_xlate_add(xl, "ah spi%s ", inv_spi ? " !=" : "");
if (ahinfo->spis[0] != ahinfo->spis[1])
xt_xlate_add(xl, "%u-%u", ahinfo->spis[0],
ahinfo->spis[1]);
@@ -158,7 +162,7 @@ static int ah_xlate(struct xt_xlate *xl,
}
if (!space[0]) /* plain '-m ah' */
- xt_xlate_add(xl, "meta l4proto ah");
+ xt_xlate_add(xl, "exthdr ah exists");
return 1;
}
diff --git a/extensions/libip6t_ah.t b/extensions/libip6t_ah.t
index c1898d44..19aa6f55 100644
--- a/extensions/libip6t_ah.t
+++ b/extensions/libip6t_ah.t
@@ -13,3 +13,9 @@
-m ah --ahspi 0:invalid;;FAIL
-m ah --ahspi;;FAIL
-m ah;=;OK
+-m ah --ahspi :;-m ah;OK
+-m ah ! --ahspi :;-m ah ! --ahspi 0:4294967295;OK
+-m ah --ahspi :3;-m ah --ahspi 0:3;OK
+-m ah --ahspi 3:;-m ah --ahspi 3:4294967295;OK
+-m ah --ahspi 3:3;-m ah --ahspi 3;OK
+-m ah --ahspi 4:3;;FAIL
diff --git a/extensions/libip6t_ah.txlate b/extensions/libip6t_ah.txlate
index c6b09a2e..32c6b7de 100644
--- a/extensions/libip6t_ah.txlate
+++ b/extensions/libip6t_ah.txlate
@@ -1,17 +1,23 @@
ip6tables-translate -A INPUT -m ah --ahspi 500 -j DROP
-nft add rule ip6 filter INPUT ah spi 500 counter drop
+nft 'add rule ip6 filter INPUT ah spi 500 counter drop'
ip6tables-translate -A INPUT -m ah --ahspi 500:550 -j DROP
-nft add rule ip6 filter INPUT ah spi 500-550 counter drop
+nft 'add rule ip6 filter INPUT ah spi 500-550 counter drop'
ip6tables-translate -A INPUT -m ah ! --ahlen 120
-nft add rule ip6 filter INPUT ah hdrlength != 120 counter
+nft 'add rule ip6 filter INPUT ah hdrlength != 120 counter'
ip6tables-translate -A INPUT -m ah --ahres
-nft add rule ip6 filter INPUT ah reserved 1 counter
+nft 'add rule ip6 filter INPUT ah reserved 1 counter'
ip6tables-translate -A INPUT -m ah --ahspi 500 ! --ahlen 120 -j DROP
-nft add rule ip6 filter INPUT ah spi 500 ah hdrlength != 120 counter drop
+nft 'add rule ip6 filter INPUT ah spi 500 ah hdrlength != 120 counter drop'
ip6tables-translate -A INPUT -m ah --ahspi 500 --ahlen 120 --ahres -j ACCEPT
-nft add rule ip6 filter INPUT ah spi 500 ah hdrlength 120 ah reserved 1 counter accept
+nft 'add rule ip6 filter INPUT ah spi 500 ah hdrlength 120 ah reserved 1 counter accept'
+
+ip6tables-translate -A INPUT -m ah --ahspi 0:4294967295
+nft 'add rule ip6 filter INPUT exthdr ah exists counter'
+
+ip6tables-translate -A INPUT -m ah ! --ahspi 0:4294967295
+nft 'add rule ip6 filter INPUT ah spi != 0-4294967295 counter'
diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c
index fe7e3403..baa010f5 100644
--- a/extensions/libip6t_dst.c
+++ b/extensions/libip6t_dst.c
@@ -57,11 +57,9 @@ parse_options(const char *optsstr, uint16_t *opts)
{
char *buffer, *cp, *next, *range;
unsigned int i;
-
- buffer = strdup(optsstr);
- if (!buffer)
- xtables_error(OTHER_PROBLEM, "strdup failed");
-
+
+ buffer = xtables_strdup(optsstr);
+
for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++)
{
next = strchr(cp, ',');
@@ -127,15 +125,15 @@ static void
print_options(unsigned int optsnr, uint16_t *optsp)
{
unsigned int i;
+ char sep = ' ';
- printf(" ");
for(i = 0; i < optsnr; i++) {
- printf("%d", (optsp[i] & 0xFF00) >> 8);
+ printf("%c%d", sep, (optsp[i] & 0xFF00) >> 8);
if ((optsp[i] & 0x00FF) != 0x00FF)
printf(":%d", (optsp[i] & 0x00FF));
- printf("%c", (i != optsnr - 1) ? ',' : ' ');
+ sep = ',';
}
}
diff --git a/extensions/libip6t_frag.c b/extensions/libip6t_frag.c
index 3842496e..ed7fe10a 100644
--- a/extensions/libip6t_frag.c
+++ b/extensions/libip6t_frag.c
@@ -89,13 +89,18 @@ static void frag_parse(struct xt_option_call *cb)
}
}
+static bool skip_ids_match(uint32_t min, uint32_t max, bool inv)
+{
+ return min == 0 && max == UINT32_MAX && !inv;
+}
+
static void
print_ids(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFFFFFFFF || invert) {
+ if (!skip_ids_match(min, max, invert)) {
printf("%s", name);
if (min == max)
printf(":%s%u", inv, min);
@@ -139,11 +144,10 @@ static void frag_print(const void *ip, const struct xt_entry_match *match,
static void frag_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_frag *fraginfo = (struct ip6t_frag *)match->data;
+ bool inv_ids = fraginfo->invflags & IP6T_FRAG_INV_IDS;
- if (!(fraginfo->ids[0] == 0
- && fraginfo->ids[1] == 0xFFFFFFFF)) {
- printf("%s --fragid ",
- (fraginfo->invflags & IP6T_FRAG_INV_IDS) ? " !" : "");
+ if (!skip_ids_match(fraginfo->ids[0], fraginfo->ids[1], inv_ids)) {
+ printf("%s --fragid ", inv_ids ? " !" : "");
if (fraginfo->ids[0]
!= fraginfo->ids[1])
printf("%u:%u",
@@ -173,41 +177,42 @@ static void frag_save(const void *ip, const struct xt_entry_match *match)
printf(" --fraglast");
}
+#define XLATE_FLAGS (IP6T_FRAG_RES | IP6T_FRAG_FST | \
+ IP6T_FRAG_MF | IP6T_FRAG_NMF)
+
static int frag_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ip6t_frag *fraginfo =
(struct ip6t_frag *)params->match->data;
- char *space= "";
+ bool inv_ids = fraginfo->invflags & IP6T_FRAG_INV_IDS;
- if (!(fraginfo->ids[0] == 0 && fraginfo->ids[1] == 0xFFFFFFFF)) {
- xt_xlate_add(xl, "frag id %s",
- (fraginfo->invflags & IP6T_FRAG_INV_IDS) ?
- "!= " : "");
+ if (!skip_ids_match(fraginfo->ids[0], fraginfo->ids[1], inv_ids)) {
+ xt_xlate_add(xl, "frag id %s", inv_ids ? "!= " : "");
if (fraginfo->ids[0] != fraginfo->ids[1])
xt_xlate_add(xl, "%u-%u", fraginfo->ids[0],
fraginfo->ids[1]);
else
xt_xlate_add(xl, "%u", fraginfo->ids[0]);
- space = " ";
+ } else if (!(fraginfo->flags & XLATE_FLAGS)) {
+ xt_xlate_add(xl, "exthdr frag exists");
+ return 1;
}
- if (fraginfo->flags & IP6T_FRAG_RES) {
- xt_xlate_add(xl, "%sfrag reserved 1", space);
- space = " ";
- }
- if (fraginfo->flags & IP6T_FRAG_FST) {
- xt_xlate_add(xl, "%sfrag frag-off 0", space);
- space = " ";
- }
- if (fraginfo->flags & IP6T_FRAG_MF) {
- xt_xlate_add(xl, "%sfrag more-fragments 1", space);
- space = " ";
- }
- if (fraginfo->flags & IP6T_FRAG_NMF) {
- xt_xlate_add(xl, "%sfrag more-fragments 0", space);
- }
+ /* ignore ineffective IP6T_FRAG_LEN bit */
+
+ if (fraginfo->flags & IP6T_FRAG_RES)
+ xt_xlate_add(xl, "frag reserved 1");
+
+ if (fraginfo->flags & IP6T_FRAG_FST)
+ xt_xlate_add(xl, "frag frag-off 0");
+
+ if (fraginfo->flags & IP6T_FRAG_MF)
+ xt_xlate_add(xl, "frag more-fragments 1");
+
+ if (fraginfo->flags & IP6T_FRAG_NMF)
+ xt_xlate_add(xl, "frag more-fragments 0");
return 1;
}
diff --git a/extensions/libip6t_frag.t b/extensions/libip6t_frag.t
index 299fa03f..ea7ac899 100644
--- a/extensions/libip6t_frag.t
+++ b/extensions/libip6t_frag.t
@@ -1,5 +1,11 @@
:INPUT,FORWARD,OUTPUT
+-m frag --fragid :;-m frag;OK
+-m frag ! --fragid :;-m frag ! --fragid 0:4294967295;OK
+-m frag --fragid :42;-m frag --fragid 0:42;OK
+-m frag --fragid 42:;-m frag --fragid 42:4294967295;OK
-m frag --fragid 1:42;=;OK
+-m frag --fragid 3:3;-m frag --fragid 3;OK
+-m frag --fragid 4:3;;FAIL
-m frag --fraglen 42;=;OK
-m frag --fragres;=;OK
-m frag --fragfirst;=;OK
diff --git a/extensions/libip6t_frag.txlate b/extensions/libip6t_frag.txlate
index e8bd9d4b..e250587e 100644
--- a/extensions/libip6t_frag.txlate
+++ b/extensions/libip6t_frag.txlate
@@ -1,17 +1,23 @@
ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 -j ACCEPT
-nft add rule ip6 filter INPUT frag id 100-200 counter accept
+nft 'add rule ip6 filter INPUT frag id 100-200 counter accept'
ip6tables-translate -t filter -A INPUT -m frag --fragid 100 --fragres --fragmore -j ACCEPT
-nft add rule ip6 filter INPUT frag id 100 frag reserved 1 frag more-fragments 1 counter accept
+nft 'add rule ip6 filter INPUT frag id 100 frag reserved 1 frag more-fragments 1 counter accept'
ip6tables-translate -t filter -A INPUT -m frag ! --fragid 100:200 -j ACCEPT
-nft add rule ip6 filter INPUT frag id != 100-200 counter accept
+nft 'add rule ip6 filter INPUT frag id != 100-200 counter accept'
ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fraglast -j ACCEPT
-nft add rule ip6 filter INPUT frag id 100-200 frag more-fragments 0 counter accept
+nft 'add rule ip6 filter INPUT frag id 100-200 frag more-fragments 0 counter accept'
ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fragfirst -j ACCEPT
-nft add rule ip6 filter INPUT frag id 100-200 frag frag-off 0 counter accept
+nft 'add rule ip6 filter INPUT frag id 100-200 frag frag-off 0 counter accept'
ip6tables-translate -t filter -A INPUT -m frag --fraglast -j ACCEPT
-nft add rule ip6 filter INPUT frag more-fragments 0 counter accept
+nft 'add rule ip6 filter INPUT frag more-fragments 0 counter accept'
+
+ip6tables-translate -t filter -A INPUT -m frag --fragid 0:4294967295
+nft 'add rule ip6 filter INPUT exthdr frag exists counter'
+
+ip6tables-translate -t filter -A INPUT -m frag ! --fragid 0:4294967295
+nft 'add rule ip6 filter INPUT frag id != 0-4294967295 counter'
diff --git a/extensions/libip6t_hbh.c b/extensions/libip6t_hbh.c
index 4cebecfd..74e87cda 100644
--- a/extensions/libip6t_hbh.c
+++ b/extensions/libip6t_hbh.c
@@ -57,10 +57,9 @@ parse_options(const char *optsstr, uint16_t *opts)
{
char *buffer, *cp, *next, *range;
unsigned int i;
-
- buffer = strdup(optsstr);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
-
+
+ buffer = xtables_strdup(optsstr);
+
for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++)
{
next=strchr(cp, ',');
diff --git a/extensions/libip6t_hbh.txlate b/extensions/libip6t_hbh.txlate
index 28101fd7..a753df0d 100644
--- a/extensions/libip6t_hbh.txlate
+++ b/extensions/libip6t_hbh.txlate
@@ -1,5 +1,5 @@
ip6tables-translate -t filter -A INPUT -m hbh --hbh-len 22
-nft add rule ip6 filter INPUT hbh hdrlength 22 counter
+nft 'add rule ip6 filter INPUT hbh hdrlength 22 counter'
ip6tables-translate -t filter -A INPUT -m hbh ! --hbh-len 22
-nft add rule ip6 filter INPUT hbh hdrlength != 22 counter
+nft 'add rule ip6 filter INPUT hbh hdrlength != 22 counter'
diff --git a/extensions/libip6t_hl.txlate b/extensions/libip6t_hl.txlate
index 17563938..9ff0df9c 100644
--- a/extensions/libip6t_hl.txlate
+++ b/extensions/libip6t_hl.txlate
@@ -1,5 +1,5 @@
ip6tables-translate -t nat -A postrouting -m hl --hl-gt 3
-nft add rule ip6 nat postrouting ip6 hoplimit gt 3 counter
+nft 'add rule ip6 nat postrouting ip6 hoplimit gt 3 counter'
ip6tables-translate -t nat -A postrouting -m hl ! --hl-eq 3
-nft add rule ip6 nat postrouting ip6 hoplimit != 3 counter
+nft 'add rule ip6 nat postrouting ip6 hoplimit != 3 counter'
diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c
index cc7bfaeb..439291ea 100644
--- a/extensions/libip6t_icmp6.c
+++ b/extensions/libip6t_icmp6.c
@@ -12,48 +12,6 @@ enum {
O_ICMPV6_TYPE = 0,
};
-static const struct xt_icmp_names icmpv6_codes[] = {
- { "destination-unreachable", 1, 0, 0xFF },
- { "no-route", 1, 0, 0 },
- { "communication-prohibited", 1, 1, 1 },
- { "beyond-scope", 1, 2, 2 },
- { "address-unreachable", 1, 3, 3 },
- { "port-unreachable", 1, 4, 4 },
- { "failed-policy", 1, 5, 5 },
- { "reject-route", 1, 6, 6 },
-
- { "packet-too-big", 2, 0, 0xFF },
-
- { "time-exceeded", 3, 0, 0xFF },
- /* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
- { "ttl-zero-during-transit", 3, 0, 0 },
- { "ttl-zero-during-reassembly", 3, 1, 1 },
-
- { "parameter-problem", 4, 0, 0xFF },
- { "bad-header", 4, 0, 0 },
- { "unknown-header-type", 4, 1, 1 },
- { "unknown-option", 4, 2, 2 },
-
- { "echo-request", 128, 0, 0xFF },
- /* Alias */ { "ping", 128, 0, 0xFF },
-
- { "echo-reply", 129, 0, 0xFF },
- /* Alias */ { "pong", 129, 0, 0xFF },
-
- { "router-solicitation", 133, 0, 0xFF },
-
- { "router-advertisement", 134, 0, 0xFF },
-
- { "neighbour-solicitation", 135, 0, 0xFF },
- /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
-
- { "neighbour-advertisement", 136, 0, 0xFF },
- /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
-
- { "redirect", 137, 0, 0xFF },
-
-};
-
static void icmp6_help(void)
{
printf(
@@ -70,59 +28,6 @@ static const struct xt_option_entry icmp6_opts[] = {
XTOPT_TABLEEND,
};
-static void
-parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[])
-{
- static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
- unsigned int match = limit;
- unsigned int i;
-
- for (i = 0; i < limit; i++) {
- if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))
- == 0) {
- if (match != limit)
- xtables_error(PARAMETER_PROBLEM,
- "Ambiguous ICMPv6 type `%s':"
- " `%s' or `%s'?",
- icmpv6type,
- icmpv6_codes[match].name,
- icmpv6_codes[i].name);
- match = i;
- }
- }
-
- if (match != limit) {
- *type = icmpv6_codes[match].type;
- code[0] = icmpv6_codes[match].code_min;
- code[1] = icmpv6_codes[match].code_max;
- } else {
- char *slash;
- char buffer[strlen(icmpv6type) + 1];
- unsigned int number;
-
- strcpy(buffer, icmpv6type);
- slash = strchr(buffer, '/');
-
- if (slash)
- *slash = '\0';
-
- if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid ICMPv6 type `%s'\n", buffer);
- *type = number;
- if (slash) {
- if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid ICMPv6 code `%s'\n",
- slash+1);
- code[0] = code[1] = number;
- } else {
- code[0] = 0;
- code[1] = 0xFF;
- }
- }
-}
-
static void icmp6_init(struct xt_entry_match *m)
{
struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
@@ -135,7 +40,7 @@ static void icmp6_parse(struct xt_option_call *cb)
struct ip6t_icmp *icmpv6info = cb->data;
xtables_option_parse(cb);
- parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
+ ipt_parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
if (cb->invert)
icmpv6info->invflags |= IP6T_ICMP_INV;
}
diff --git a/extensions/libip6t_icmp6.t b/extensions/libip6t_icmp6.t
index 028cfc16..b9a4dcd3 100644
--- a/extensions/libip6t_icmp6.t
+++ b/extensions/libip6t_icmp6.t
@@ -4,3 +4,7 @@
-p ipv6-icmp -m icmp6 --icmpv6-type 2;=;OK
# cannot use option twice:
-p ipv6-icmp -m icmp6 --icmpv6-type no-route --icmpv6-type packet-too-big;;FAIL
+-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-query;-p ipv6-icmp -m icmp6 --icmpv6-type 130;OK
+-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-report;-p ipv6-icmp -m icmp6 --icmpv6-type 131;OK
+-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-done;-p ipv6-icmp -m icmp6 --icmpv6-type 132;OK
+-p ipv6-icmp -m icmp6 --icmpv6-type mld-listener-reduction;-p ipv6-icmp -m icmp6 --icmpv6-type 132;OK
diff --git a/extensions/libip6t_icmp6.txlate b/extensions/libip6t_icmp6.txlate
index 15481ad6..324a48b9 100644
--- a/extensions/libip6t_icmp6.txlate
+++ b/extensions/libip6t_icmp6.txlate
@@ -1,8 +1,8 @@
ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type 1 -j LOG
-nft add rule ip6 filter INPUT icmpv6 type destination-unreachable counter log
+nft 'add rule ip6 filter INPUT icmpv6 type destination-unreachable counter log'
ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type neighbour-advertisement -j LOG
-nft add rule ip6 filter INPUT icmpv6 type nd-neighbor-advert counter log
+nft 'add rule ip6 filter INPUT icmpv6 type nd-neighbor-advert counter log'
ip6tables-translate -t filter -A INPUT -m icmp6 ! --icmpv6-type packet-too-big -j LOG
-nft add rule ip6 filter INPUT icmpv6 type != packet-too-big counter log
+nft 'add rule ip6 filter INPUT icmpv6 type != packet-too-big counter log'
diff --git a/extensions/libip6t_ipv6header.c b/extensions/libip6t_ipv6header.c
index 6f03087b..9e345629 100644
--- a/extensions/libip6t_ipv6header.c
+++ b/extensions/libip6t_ipv6header.c
@@ -147,7 +147,7 @@ parse_header(const char *flags) {
char *ptr;
char *buffer;
- buffer = strdup(flags);
+ buffer = xtables_strdup(flags);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
ret |= add_proto_to_mask(name_to_proto(ptr));
diff --git a/extensions/libip6t_mh.c b/extensions/libip6t_mh.c
index f4c0fd9f..3f80e28e 100644
--- a/extensions/libip6t_mh.c
+++ b/extensions/libip6t_mh.c
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_mh.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
enum {
O_MH_TYPE = 0,
@@ -97,7 +98,7 @@ static unsigned int name_to_type(const char *name)
if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
- "Invalid MH type `%s'\n", name);
+ "Invalid MH type `%s'", name);
return number;
}
}
@@ -107,7 +108,7 @@ static void parse_mh_types(const char *mhtype, uint8_t *types)
char *buffer;
char *cp;
- buffer = strdup(mhtype);
+ buffer = xtables_strdup(mhtype);
if ((cp = strchr(buffer, ':')) == NULL)
types[0] = types[1] = name_to_type(buffer);
else {
@@ -154,11 +155,16 @@ static void print_type(uint8_t type, int numeric)
printf("%s", name);
}
+static bool skip_types_match(uint8_t min, uint8_t max, bool inv)
+{
+ return min == 0 && max == UINT8_MAX && !inv;
+}
+
static void print_types(uint8_t min, uint8_t max, int invert, int numeric)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFF || invert) {
+ if (!skip_types_match(min, max, invert)) {
printf(" ");
if (min == max) {
printf("%s", inv);
@@ -189,11 +195,12 @@ static void mh_print(const void *ip, const struct xt_entry_match *match,
static void mh_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
+ bool inv_type = mhinfo->invflags & IP6T_MH_INV_TYPE;
- if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xFF)
+ if (skip_types_match(mhinfo->types[0], mhinfo->types[1], inv_type))
return;
- if (mhinfo->invflags & IP6T_MH_INV_TYPE)
+ if (inv_type)
printf(" !");
if (mhinfo->types[0] != mhinfo->types[1])
@@ -206,9 +213,14 @@ static int mh_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)params->match->data;
+ bool inv_type = mhinfo->invflags & IP6T_MH_INV_TYPE;
+ uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
- if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xff)
+ if (skip_types_match(mhinfo->types[0], mhinfo->types[1], inv_type)) {
+ if (proto != IPPROTO_MH)
+ xt_xlate_add(xl, "exthdr mh exists");
return 1;
+ }
if (mhinfo->types[0] != mhinfo->types[1])
xt_xlate_add(xl, "mh type %s%u-%u",
diff --git a/extensions/libip6t_mh.t b/extensions/libip6t_mh.t
index 6b76d13d..b628e9e3 100644
--- a/extensions/libip6t_mh.t
+++ b/extensions/libip6t_mh.t
@@ -4,3 +4,9 @@
-p mobility-header -m mh --mh-type 1;=;OK
-p mobility-header -m mh ! --mh-type 4;=;OK
-p mobility-header -m mh --mh-type 4:123;=;OK
+-p mobility-header -m mh --mh-type :;-p mobility-header -m mh;OK
+-p mobility-header -m mh ! --mh-type :;-p mobility-header -m mh ! --mh-type 0:255;OK
+-p mobility-header -m mh --mh-type :3;-p mobility-header -m mh --mh-type 0:3;OK
+-p mobility-header -m mh --mh-type 3:;-p mobility-header -m mh --mh-type 3:255;OK
+-p mobility-header -m mh --mh-type 3:3;-p mobility-header -m mh --mh-type 3;OK
+-p mobility-header -m mh --mh-type 4:3;;FAIL
diff --git a/extensions/libip6t_mh.txlate b/extensions/libip6t_mh.txlate
index f5d638c0..3364ce57 100644
--- a/extensions/libip6t_mh.txlate
+++ b/extensions/libip6t_mh.txlate
@@ -1,5 +1,14 @@
ip6tables-translate -A INPUT -p mh --mh-type 1 -j ACCEPT
-nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1 counter accept
+nft 'add rule ip6 filter INPUT meta l4proto mobility-header mh type 1 counter accept'
ip6tables-translate -A INPUT -p mh --mh-type 1:3 -j ACCEPT
-nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1-3 counter accept
+nft 'add rule ip6 filter INPUT meta l4proto mobility-header mh type 1-3 counter accept'
+
+ip6tables-translate -A INPUT -p mh --mh-type 0:255 -j ACCEPT
+nft 'add rule ip6 filter INPUT meta l4proto mobility-header counter accept'
+
+ip6tables-translate -A INPUT -m mh --mh-type 0:255 -j ACCEPT
+nft 'add rule ip6 filter INPUT exthdr mh exists counter accept'
+
+ip6tables-translate -A INPUT -p mh ! --mh-type 0:255 -j ACCEPT
+nft 'add rule ip6 filter INPUT meta l4proto mobility-header mh type != 0-255 counter accept'
diff --git a/extensions/libip6t_rt.c b/extensions/libip6t_rt.c
index 3cb3b249..6db09f0b 100644
--- a/extensions/libip6t_rt.c
+++ b/extensions/libip6t_rt.c
@@ -73,10 +73,9 @@ parse_addresses(const char *addrstr, struct in6_addr *addrp)
{
char *buffer, *cp, *next;
unsigned int i;
-
- buffer = strdup(addrstr);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
-
+
+ buffer = xtables_strdup(addrstr);
+
for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
{
next=strchr(cp, ',');
@@ -153,13 +152,18 @@ static void rt_parse(struct xt_option_call *cb)
}
}
+static bool skip_segsleft_match(uint32_t min, uint32_t max, bool inv)
+{
+ return min == 0 && max == UINT32_MAX && !inv;
+}
+
static void
print_nums(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFFFFFFFF || invert) {
+ if (!skip_segsleft_match(min, max, invert)) {
printf(" %s", name);
if (min == max) {
printf(":%s", inv);
@@ -211,6 +215,7 @@ static void rt_print(const void *ip, const struct xt_entry_match *match,
static void rt_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
+ bool inv_sgs = rtinfo->invflags & IP6T_RT_INV_SGS;
if (rtinfo->flags & IP6T_RT_TYP) {
printf("%s --rt-type %u",
@@ -218,10 +223,9 @@ static void rt_save(const void *ip, const struct xt_entry_match *match)
rtinfo->rt_type);
}
- if (!(rtinfo->segsleft[0] == 0
- && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
- printf("%s --rt-segsleft ",
- (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : "");
+ if (!skip_segsleft_match(rtinfo->segsleft[0],
+ rtinfo->segsleft[1], inv_sgs)) {
+ printf("%s --rt-segsleft ", inv_sgs ? " !" : "");
if (rtinfo->segsleft[0]
!= rtinfo->segsleft[1])
printf("%u:%u",
@@ -245,33 +249,37 @@ static void rt_save(const void *ip, const struct xt_entry_match *match)
}
+#define XLATE_FLAGS (IP6T_RT_TYP | IP6T_RT_LEN | \
+ IP6T_RT_RES | IP6T_RT_FST | IP6T_RT_FST_NSTRICT)
+
static int rt_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ip6t_rt *rtinfo = (struct ip6t_rt *)params->match->data;
- char *space = "";
+ bool inv_sgs = rtinfo->invflags & IP6T_RT_INV_SGS;
if (rtinfo->flags & IP6T_RT_TYP) {
xt_xlate_add(xl, "rt type%s %u",
(rtinfo->invflags & IP6T_RT_INV_TYP) ? " !=" : "",
rtinfo->rt_type);
- space = " ";
}
- if (!(rtinfo->segsleft[0] == 0 && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
- xt_xlate_add(xl, "%srt seg-left%s ", space,
- (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !=" : "");
+ if (!skip_segsleft_match(rtinfo->segsleft[0],
+ rtinfo->segsleft[1], inv_sgs)) {
+ xt_xlate_add(xl, "rt seg-left%s ", inv_sgs ? " !=" : "");
if (rtinfo->segsleft[0] != rtinfo->segsleft[1])
xt_xlate_add(xl, "%u-%u", rtinfo->segsleft[0],
rtinfo->segsleft[1]);
else
xt_xlate_add(xl, "%u", rtinfo->segsleft[0]);
- space = " ";
+ } else if (!(rtinfo->flags & XLATE_FLAGS)) {
+ xt_xlate_add(xl, "exthdr rt exists");
+ return 1;
}
if (rtinfo->flags & IP6T_RT_LEN) {
- xt_xlate_add(xl, "%srt hdrlength%s %u", space,
+ xt_xlate_add(xl, "rt hdrlength%s %u",
(rtinfo->invflags & IP6T_RT_INV_LEN) ? " !=" : "",
rtinfo->hdrlen);
}
diff --git a/extensions/libip6t_rt.t b/extensions/libip6t_rt.t
index 3c7b2d98..1c219d66 100644
--- a/extensions/libip6t_rt.t
+++ b/extensions/libip6t_rt.t
@@ -3,3 +3,9 @@
-m rt --rt-type 0 ! --rt-segsleft 1:23 ! --rt-len 42 --rt-0-res;=;OK
-m rt ! --rt-type 1 ! --rt-segsleft 12:23 ! --rt-len 42;=;OK
-m rt;=;OK
+-m rt --rt-segsleft :;-m rt;OK
+-m rt ! --rt-segsleft :;-m rt ! --rt-segsleft 0:4294967295;OK
+-m rt --rt-segsleft :3;-m rt --rt-segsleft 0:3;OK
+-m rt --rt-segsleft 3:;-m rt --rt-segsleft 3:4294967295;OK
+-m rt --rt-segsleft 3:3;-m rt --rt-segsleft 3;OK
+-m rt --rt-segsleft 4:3;;FAIL
diff --git a/extensions/libip6t_rt.txlate b/extensions/libip6t_rt.txlate
index 6464cf9e..1c2f74a5 100644
--- a/extensions/libip6t_rt.txlate
+++ b/extensions/libip6t_rt.txlate
@@ -1,14 +1,23 @@
ip6tables-translate -A INPUT -m rt --rt-type 0 -j DROP
-nft add rule ip6 filter INPUT rt type 0 counter drop
+nft 'add rule ip6 filter INPUT rt type 0 counter drop'
ip6tables-translate -A INPUT -m rt ! --rt-len 22 -j DROP
-nft add rule ip6 filter INPUT rt hdrlength != 22 counter drop
+nft 'add rule ip6 filter INPUT rt hdrlength != 22 counter drop'
ip6tables-translate -A INPUT -m rt --rt-segsleft 26 -j ACCEPT
-nft add rule ip6 filter INPUT rt seg-left 26 counter accept
+nft 'add rule ip6 filter INPUT rt seg-left 26 counter accept'
ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 -j DROP
-nft add rule ip6 filter INPUT rt type 0 rt hdrlength 22 counter drop
+nft 'add rule ip6 filter INPUT rt type 0 rt hdrlength 22 counter drop'
ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 ! --rt-segsleft 26 -j ACCEPT
-nft add rule ip6 filter INPUT rt type 0 rt seg-left != 26 rt hdrlength 22 counter accept
+nft 'add rule ip6 filter INPUT rt type 0 rt seg-left != 26 rt hdrlength 22 counter accept'
+
+ip6tables-translate -A INPUT -m rt --rt-segsleft 13:42 -j ACCEPT
+nft 'add rule ip6 filter INPUT rt seg-left 13-42 counter accept'
+
+ip6tables-translate -A INPUT -m rt --rt-segsleft 0:4294967295 -j ACCEPT
+nft 'add rule ip6 filter INPUT exthdr rt exists counter accept'
+
+ip6tables-translate -A INPUT -m rt ! --rt-segsleft 0:4294967295 -j ACCEPT
+nft 'add rule ip6 filter INPUT rt seg-left != 0-4294967295 counter accept'
diff --git a/extensions/libip6t_standard.t b/extensions/libip6t_standard.t
index a528af10..0c559cc5 100644
--- a/extensions/libip6t_standard.t
+++ b/extensions/libip6t_standard.t
@@ -3,3 +3,6 @@
! -d ::;! -d ::/128;OK
! -s ::;! -s ::/128;OK
-s ::/64;=;OK
+:INPUT
+-i + -d c0::fe;-d c0::fe/128;OK
+-i + -p tcp;-p tcp;OK
diff --git a/extensions/libipt_CLUSTERIP.c b/extensions/libipt_CLUSTERIP.c
index f4b638b2..b207cde3 100644
--- a/extensions/libipt_CLUSTERIP.c
+++ b/extensions/libipt_CLUSTERIP.c
@@ -87,12 +87,13 @@ static void CLUSTERIP_parse(struct xt_option_call *cb)
else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0)
cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT;
else
- xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n",
- cb->arg);
+ xtables_error(PARAMETER_PROBLEM,
+ "Unknown hashmode \"%s\"", cb->arg);
break;
case O_CLUSTERMAC:
if (!(cipinfo->clustermac[0] & 0x01))
- xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n");
+ xtables_error(PARAMETER_PROBLEM,
+ "MAC has to be a multicast ethernet address");
break;
case O_LOCAL_NODE:
cipinfo->num_local_nodes = 1;
@@ -107,7 +108,8 @@ static void CLUSTERIP_check(struct xt_fcheck_call *cb)
if ((cb->xflags & F_FULL) == F_FULL)
return;
- xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n");
+ xtables_error(PARAMETER_PROBLEM,
+ "CLUSTERIP target: Invalid parameter combination");
}
static const char *hashmode2str(enum clusterip_hashmode mode)
diff --git a/extensions/libipt_CLUSTERIP.t b/extensions/libipt_CLUSTERIP.t
deleted file mode 100644
index 5af555e0..00000000
--- a/extensions/libipt_CLUSTERIP.t
+++ /dev/null
@@ -1,4 +0,0 @@
-:INPUT
--d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 0 --hash-init 1;=;FAIL
--d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 1 --hash-init 1;=;OK
--d 10.31.3.236/32 -i lo -j CLUSTERIP --new --hashmode sourceip --clustermac 01:AA:7B:47:F7:D7 --total-nodes 2 --local-node 2 --hash-init 1;=;OK
diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c
deleted file mode 100644
index 4907a2e8..00000000
--- a/extensions/libipt_DNAT.c
+++ /dev/null
@@ -1,555 +0,0 @@
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <iptables.h> /* get_kernel_version */
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_DEST = 0,
- O_RANDOM,
- O_PERSISTENT,
- O_X_TO_DEST, /* hidden flag */
- F_TO_DEST = 1 << O_TO_DEST,
- F_RANDOM = 1 << O_RANDOM,
- F_X_TO_DEST = 1 << O_X_TO_DEST,
-};
-
-/* Dest NAT data consists of a multi-range, indicating where to map
- to. */
-struct ipt_natinfo
-{
- struct xt_entry_target t;
- struct nf_nat_ipv4_multi_range_compat mr;
-};
-
-static void DNAT_help(void)
-{
- printf(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static void DNAT_help_v2(void)
-{
- printf(
-"DNAT target options:\n"
-" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
-" Address to map destination to.\n"
-"[--random] [--persistent]\n");
-}
-
-static const struct xt_option_entry DNAT_opts[] = {
- {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-static struct ipt_natinfo *
-append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range)
-{
- unsigned int size;
-
- /* One rangesize already in struct ipt_natinfo */
- size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
-
- info = realloc(info, size);
- if (!info)
- xtables_error(OTHER_PROBLEM, "Out of memory\n");
-
- info->t.u.target_size = size;
- info->mr.range[info->mr.rangesize] = *range;
- info->mr.rangesize++;
-
- return info;
-}
-
-/* Ranges expected in network order. */
-static struct xt_entry_target *
-parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
-{
- struct nf_nat_ipv4_range range;
- char *arg, *colon, *dash, *error;
- const struct in_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
- memset(&range, 0, sizeof(range));
- colon = strchr(arg, ':');
-
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range.min.tcp.port
- = range.max.tcp.port
- = htons(port);
- } else {
- int maxport;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* People are stupid. */
- xtables_error(PARAMETER_PROBLEM,
- "Port range `%s' funky\n", colon+1);
- range.min.tcp.port = htons(port);
- range.max.tcp.port = htons(maxport);
- }
- /* Starts with a colon? No IP info...*/
- if (colon == arg) {
- free(arg);
- return &(append_range(info, &range)->t);
- }
- *colon = '\0';
- }
-
- range.flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(arg, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ipaddr(arg);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- arg);
- range.min_ip = ip->s_addr;
- if (dash) {
- ip = xtables_numeric_to_ipaddr(dash+1);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- dash+1);
- range.max_ip = ip->s_addr;
- } else
- range.max_ip = range.min_ip;
-
- free(arg);
- return &(append_range(info, &range)->t);
-}
-
-static void DNAT_parse(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- struct ipt_natinfo *info = (void *)(*cb->target);
- int portok;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_DEST:
- if (cb->xflags & F_X_TO_DEST) {
- if (!kernel_version)
- get_kernel_version();
- if (kernel_version > LINUX_VERSION(2, 6, 10))
- xtables_error(PARAMETER_PROBLEM,
- "DNAT: Multiple --to-destination not supported");
- }
- *cb->target = parse_to(cb->arg, portok, info);
- cb->xflags |= F_X_TO_DEST;
- break;
- case O_PERSISTENT:
- info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void DNAT_fcheck(struct xt_fcheck_call *cb)
-{
- static const unsigned int f = F_TO_DEST | F_RANDOM;
- struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
-
- if ((cb->xflags & f) == f)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
-}
-
-static void print_range(const struct nf_nat_ipv4_range *r)
-{
- if (r->flags & NF_NAT_RANGE_MAP_IPS) {
- struct in_addr a;
-
- a.s_addr = r->min_ip;
- printf("%s", xtables_ipaddr_to_numeric(&a));
- if (r->max_ip != r->min_ip) {
- a.s_addr = r->max_ip;
- printf("-%s", xtables_ipaddr_to_numeric(&a));
- }
- }
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- }
-}
-
-static void DNAT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
-
- printf(" to:");
- for (i = 0; i < info->mr.rangesize; i++) {
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
- }
-}
-
-static void DNAT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
-
- for (i = 0; i < info->mr.rangesize; i++) {
- printf(" --to-destination ");
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
- }
-}
-
-static void print_range_xlate(const struct nf_nat_ipv4_range *r,
- struct xt_xlate *xl)
-{
- if (r->flags & NF_NAT_RANGE_MAP_IPS) {
- struct in_addr a;
-
- a.s_addr = r->min_ip;
- xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&a));
- if (r->max_ip != r->min_ip) {
- a.s_addr = r->max_ip;
- xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&a));
- }
- }
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, ":%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port));
- }
-}
-
-static int DNAT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct ipt_natinfo *info = (const void *)params->target;
- unsigned int i = 0;
- bool sep_need = false;
- const char *sep = " ";
-
- for (i = 0; i < info->mr.rangesize; i++) {
- xt_xlate_add(xl, "dnat to ");
- print_range_xlate(&info->mr.range[i], xl);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
- }
-
- return 1;
-}
-
-static void
-parse_to_v2(const char *orig_arg, int portok, struct nf_nat_range2 *range)
-{
- char *arg, *colon, *dash, *error;
- const struct in_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
-
- colon = strchr(arg, ':');
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range->min_proto.tcp.port
- = range->max_proto.tcp.port
- = htons(port);
- } else {
- int maxport;
- char *slash;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* People are stupid. */
- xtables_error(PARAMETER_PROBLEM,
- "Port range `%s' funky\n", colon+1);
- range->min_proto.tcp.port = htons(port);
- range->max_proto.tcp.port = htons(maxport);
-
- slash = strchr(dash, '/');
- if (slash) {
- int baseport;
-
- baseport = atoi(slash + 1);
- if (baseport <= 0 || baseport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", slash+1);
- range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
- range->base_proto.tcp.port = htons(baseport);
- }
- }
- /* Starts with a colon? No IP info...*/
- if (colon == arg) {
- free(arg);
- return;
- }
- *colon = '\0';
- }
-
- range->flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(arg, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ipaddr(arg);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- arg);
- range->min_addr.in = *ip;
- if (dash) {
- ip = xtables_numeric_to_ipaddr(dash+1);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- dash+1);
- range->max_addr.in = *ip;
- } else
- range->max_addr = range->min_addr;
-
- free(arg);
- return;
-}
-
-static void DNAT_parse_v2(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- struct nf_nat_range2 *range = cb->data;
- int portok;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_DEST:
- if (cb->xflags & F_X_TO_DEST) {
- xtables_error(PARAMETER_PROBLEM,
- "DNAT: Multiple --to-destination not supported");
- }
- parse_to_v2(cb->arg, portok, range);
- cb->xflags |= F_X_TO_DEST;
- break;
- case O_PERSISTENT:
- range->flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void DNAT_fcheck_v2(struct xt_fcheck_call *cb)
-{
- static const unsigned int f = F_TO_DEST | F_RANDOM;
- struct nf_nat_range2 *range = cb->data;
-
- if ((cb->xflags & f) == f)
- range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
-}
-
-static void print_range_v2(const struct nf_nat_range2 *range)
-{
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- printf("%s", xtables_ipaddr_to_numeric(&range->min_addr.in));
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr)))
- printf("-%s", xtables_ipaddr_to_numeric(&range->max_addr.in));
- }
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- printf("-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
- printf("/%hu", ntohs(range->base_proto.tcp.port));
- }
-}
-
-static void DNAT_print_v2(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_range2 *range = (const void *)target->data;
-
- printf(" to:");
- print_range_v2(range);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
-}
-
-static void DNAT_save_v2(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_range2 *range = (const void *)target->data;
-
- printf(" --to-destination ");
- print_range_v2(range);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (range->flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
-}
-
-static void print_range_xlate_v2(const struct nf_nat_range2 *range,
- struct xt_xlate *xl)
-{
- if (range->flags & NF_NAT_RANGE_MAP_IPS) {
- xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&range->min_addr.in));
- if (memcmp(&range->min_addr, &range->max_addr,
- sizeof(range->min_addr))) {
- xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&range->max_addr.in));
- }
- }
- if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
- if (range->max_proto.tcp.port != range->min_proto.tcp.port)
- xt_xlate_add(xl, "-%hu", ntohs(range->max_proto.tcp.port));
- if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
- xt_xlate_add(xl, ";%hu", ntohs(range->base_proto.tcp.port));
- }
-}
-
-static int DNAT_xlate_v2(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_range2 *range = (const void *)params->target->data;
- bool sep_need = false;
- const char *sep = " ";
-
- xt_xlate_add(xl, "dnat to ");
- print_range_xlate_v2(range, xl);
- if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (range->flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
-
- return 1;
-}
-
-static struct xtables_target dnat_tg_reg[] = {
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .revision = 0,
- .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .help = DNAT_help,
- .print = DNAT_print,
- .save = DNAT_save,
- .x6_parse = DNAT_parse,
- .x6_fcheck = DNAT_fcheck,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate,
- },
- {
- .name = "DNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .revision = 2,
- .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
- .help = DNAT_help_v2,
- .print = DNAT_print_v2,
- .save = DNAT_save_v2,
- .x6_parse = DNAT_parse_v2,
- .x6_fcheck = DNAT_fcheck_v2,
- .x6_options = DNAT_opts,
- .xlate = DNAT_xlate_v2,
- },
-};
-
-void _init(void)
-{
- xtables_register_targets(dnat_tg_reg, ARRAY_SIZE(dnat_tg_reg));
-}
diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t
index 1c4413b9..9007572a 100644
--- a/extensions/libipt_DNAT.t
+++ b/extensions/libipt_DNAT.t
@@ -13,4 +13,8 @@
-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65535;=;OK
-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/0;;FAIL
-p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65536;;FAIL
+-p tcp -j DNAT --to-destination 1.1.1.1:ssh;-p tcp -j DNAT --to-destination 1.1.1.1:22;OK
+-p tcp -j DNAT --to-destination 1.1.1.1:ftp-data;-p tcp -j DNAT --to-destination 1.1.1.1:20;OK
+-p tcp -j DNAT --to-destination 1.1.1.1:echo-ssh;;FAIL
+-p tcp -j DNAT --to-destination 1.1.1.1:10-20/ftp;-p tcp -j DNAT --to-destination 1.1.1.1:10-20/21;OK
-j DNAT;;FAIL
diff --git a/extensions/libipt_DNAT.txlate b/extensions/libipt_DNAT.txlate
deleted file mode 100644
index e88314d9..00000000
--- a/extensions/libipt_DNAT.txlate
+++ /dev/null
@@ -1,14 +0,0 @@
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4
-
-iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10
-nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10
-
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023
-
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random
-
-iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent
-nft add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent
diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c
deleted file mode 100644
index 36e2e73b..00000000
--- a/extensions/libipt_LOG.c
+++ /dev/null
@@ -1,250 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <xtables.h>
-#include <linux/netfilter_ipv4/ipt_LOG.h>
-
-#define LOG_DEFAULT_LEVEL LOG_WARNING
-
-#ifndef IPT_LOG_UID /* Old kernel */
-#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
-#undef IPT_LOG_MASK
-#define IPT_LOG_MASK 0x0f
-#endif
-
-enum {
- O_LOG_LEVEL = 0,
- O_LOG_PREFIX,
- O_LOG_TCPSEQ,
- O_LOG_TCPOPTS,
- O_LOG_IPOPTS,
- O_LOG_UID,
- O_LOG_MAC,
-};
-
-static void LOG_help(void)
-{
- printf(
-"LOG target options:\n"
-" --log-level level Level of logging (numeric or see syslog.conf)\n"
-" --log-prefix prefix Prefix log messages with this prefix.\n\n"
-" --log-tcp-sequence Log TCP sequence numbers.\n\n"
-" --log-tcp-options Log TCP options.\n\n"
-" --log-ip-options Log IP options.\n\n"
-" --log-uid Log UID owning the local socket.\n\n"
-" --log-macdecode Decode MAC addresses and protocol.\n\n");
-}
-
-#define s struct ipt_log_info
-static const struct xt_option_entry LOG_opts[] = {
- {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, level)},
- {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1},
- {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE},
- {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE},
- {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE},
- {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE},
- {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-#undef s
-
-static void LOG_init(struct xt_entry_target *t)
-{
- struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data;
-
- loginfo->level = LOG_DEFAULT_LEVEL;
-
-}
-
-struct ipt_log_names {
- const char *name;
- unsigned int level;
-};
-
-struct ipt_log_xlate {
- const char *name;
- unsigned int level;
-};
-
-static const struct ipt_log_names ipt_log_names[]
-= { { .name = "alert", .level = LOG_ALERT },
- { .name = "crit", .level = LOG_CRIT },
- { .name = "debug", .level = LOG_DEBUG },
- { .name = "emerg", .level = LOG_EMERG },
- { .name = "error", .level = LOG_ERR }, /* DEPRECATED */
- { .name = "info", .level = LOG_INFO },
- { .name = "notice", .level = LOG_NOTICE },
- { .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */
- { .name = "warning", .level = LOG_WARNING }
-};
-
-static void LOG_parse(struct xt_option_call *cb)
-{
- struct ipt_log_info *info = cb->data;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_LOG_PREFIX:
- if (strchr(cb->arg, '\n') != NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Newlines not allowed in --log-prefix");
- break;
- case O_LOG_TCPSEQ:
- info->logflags |= IPT_LOG_TCPSEQ;
- break;
- case O_LOG_TCPOPTS:
- info->logflags |= IPT_LOG_TCPOPT;
- break;
- case O_LOG_IPOPTS:
- info->logflags |= IPT_LOG_IPOPT;
- break;
- case O_LOG_UID:
- info->logflags |= IPT_LOG_UID;
- break;
- case O_LOG_MAC:
- info->logflags |= IPT_LOG_MACDECODE;
- break;
- }
-}
-
-static void LOG_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct ipt_log_info *loginfo
- = (const struct ipt_log_info *)target->data;
- unsigned int i = 0;
-
- printf(" LOG");
- if (numeric)
- printf(" flags %u level %u",
- loginfo->logflags, loginfo->level);
- else {
- for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i)
- if (loginfo->level == ipt_log_names[i].level) {
- printf(" level %s", ipt_log_names[i].name);
- break;
- }
- if (i == ARRAY_SIZE(ipt_log_names))
- printf(" UNKNOWN level %u", loginfo->level);
- if (loginfo->logflags & IPT_LOG_TCPSEQ)
- printf(" tcp-sequence");
- if (loginfo->logflags & IPT_LOG_TCPOPT)
- printf(" tcp-options");
- if (loginfo->logflags & IPT_LOG_IPOPT)
- printf(" ip-options");
- if (loginfo->logflags & IPT_LOG_UID)
- printf(" uid");
- if (loginfo->logflags & IPT_LOG_MACDECODE)
- printf(" macdecode");
- if (loginfo->logflags & ~(IPT_LOG_MASK))
- printf(" unknown-flags");
- }
-
- if (strcmp(loginfo->prefix, "") != 0)
- printf(" prefix \"%s\"", loginfo->prefix);
-}
-
-static void LOG_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct ipt_log_info *loginfo
- = (const struct ipt_log_info *)target->data;
-
- if (strcmp(loginfo->prefix, "") != 0) {
- printf(" --log-prefix");
- xtables_save_string(loginfo->prefix);
- }
-
- if (loginfo->level != LOG_DEFAULT_LEVEL)
- printf(" --log-level %d", loginfo->level);
-
- if (loginfo->logflags & IPT_LOG_TCPSEQ)
- printf(" --log-tcp-sequence");
- if (loginfo->logflags & IPT_LOG_TCPOPT)
- printf(" --log-tcp-options");
- if (loginfo->logflags & IPT_LOG_IPOPT)
- printf(" --log-ip-options");
- if (loginfo->logflags & IPT_LOG_UID)
- printf(" --log-uid");
- if (loginfo->logflags & IPT_LOG_MACDECODE)
- printf(" --log-macdecode");
-}
-
-static const struct ipt_log_xlate ipt_log_xlate_names[] = {
- {"alert", LOG_ALERT },
- {"crit", LOG_CRIT },
- {"debug", LOG_DEBUG },
- {"emerg", LOG_EMERG },
- {"err", LOG_ERR },
- {"info", LOG_INFO },
- {"notice", LOG_NOTICE },
- {"warn", LOG_WARNING }
-};
-
-static int LOG_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct ipt_log_info *loginfo =
- (const struct ipt_log_info *)params->target->data;
- unsigned int i = 0;
-
- xt_xlate_add(xl, "log");
- if (strcmp(loginfo->prefix, "") != 0) {
- if (params->escape_quotes)
- xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix);
- else
- xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
- }
-
- for (i = 0; i < ARRAY_SIZE(ipt_log_xlate_names); ++i)
- if (loginfo->level != LOG_DEFAULT_LEVEL &&
- loginfo->level == ipt_log_xlate_names[i].level) {
- xt_xlate_add(xl, " level %s",
- ipt_log_xlate_names[i].name);
- break;
- }
-
- if ((loginfo->logflags & IPT_LOG_MASK) == IPT_LOG_MASK) {
- xt_xlate_add(xl, " flags all");
- } else {
- if (loginfo->logflags & (IPT_LOG_TCPSEQ | IPT_LOG_TCPOPT)) {
- const char *delim = " ";
-
- xt_xlate_add(xl, " flags tcp");
- if (loginfo->logflags & IPT_LOG_TCPSEQ) {
- xt_xlate_add(xl, " sequence");
- delim = ",";
- }
- if (loginfo->logflags & IPT_LOG_TCPOPT)
- xt_xlate_add(xl, "%soptions", delim);
- }
- if (loginfo->logflags & IPT_LOG_IPOPT)
- xt_xlate_add(xl, " flags ip options");
- if (loginfo->logflags & IPT_LOG_UID)
- xt_xlate_add(xl, " flags skuid");
- if (loginfo->logflags & IPT_LOG_MACDECODE)
- xt_xlate_add(xl, " flags ether");
- }
-
- return 1;
-}
-static struct xtables_target log_tg_reg = {
- .name = "LOG",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(sizeof(struct ipt_log_info)),
- .userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)),
- .help = LOG_help,
- .init = LOG_init,
- .print = LOG_print,
- .save = LOG_save,
- .x6_parse = LOG_parse,
- .x6_options = LOG_opts,
- .xlate = LOG_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&log_tg_reg);
-}
diff --git a/extensions/libipt_LOG.txlate b/extensions/libipt_LOG.txlate
index 81f64fb2..13a2ef55 100644
--- a/extensions/libipt_LOG.txlate
+++ b/extensions/libipt_LOG.txlate
@@ -1,5 +1,5 @@
iptables-translate -A FORWARD -p tcp -j LOG --log-level error
-nft add rule ip filter FORWARD ip protocol tcp counter log level err
+nft 'add rule ip filter FORWARD ip protocol tcp counter log level err'
iptables-translate -A FORWARD -p tcp -j LOG --log-prefix "Random prefix"
-nft add rule ip filter FORWARD ip protocol tcp counter log prefix \"Random prefix\"
+nft 'add rule ip filter FORWARD ip protocol tcp counter log prefix "Random prefix"'
diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c
deleted file mode 100644
index 90bf6065..00000000
--- a/extensions/libipt_MASQUERADE.c
+++ /dev/null
@@ -1,190 +0,0 @@
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <xtables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_PORTS = 0,
- O_RANDOM,
- O_RANDOM_FULLY,
-};
-
-static void MASQUERADE_help(void)
-{
- printf(
-"MASQUERADE target options:\n"
-" --to-ports <port>[-<port>]\n"
-" Port (range) to map to.\n"
-" --random\n"
-" Randomize source port.\n"
-" --random-fully\n"
-" Fully randomize source port.\n");
-}
-
-static const struct xt_option_entry MASQUERADE_opts[] = {
- {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-static void MASQUERADE_init(struct xt_entry_target *t)
-{
- struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data;
-
- /* Actually, it's 0, but it's ignored at the moment. */
- mr->rangesize = 1;
-}
-
-/* Parses ports */
-static void
-parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr)
-{
- char *end;
- unsigned int port, maxport;
-
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
- xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
-
- switch (*end) {
- case '\0':
- mr->range[0].min.tcp.port
- = mr->range[0].max.tcp.port
- = htons(port);
- return;
- case '-':
- if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
- break;
-
- if (maxport < port)
- break;
-
- mr->range[0].min.tcp.port = htons(port);
- mr->range[0].max.tcp.port = htons(maxport);
- return;
- default:
- break;
- }
- xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
-}
-
-static void MASQUERADE_parse(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- int portok;
- struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_PORTS:
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
- parse_ports(cb->arg, mr);
- break;
- case O_RANDOM:
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- case O_RANDOM_FULLY:
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
- break;
- }
-}
-
-static void
-MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" masq ports: ");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- }
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" random-fully");
-}
-
-static void
-MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" --to-ports %hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- }
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
-
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" --random-fully");
-}
-
-static int MASQUERADE_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr =
- (const void *)params->target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- xt_xlate_add(xl, "masquerade");
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, " to :%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port));
- }
-
- xt_xlate_add(xl, " ");
- if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
- xt_xlate_add(xl, "random ");
-
- return 1;
-}
-
-static struct xtables_target masquerade_tg_reg = {
- .name = "MASQUERADE",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .help = MASQUERADE_help,
- .init = MASQUERADE_init,
- .x6_parse = MASQUERADE_parse,
- .print = MASQUERADE_print,
- .save = MASQUERADE_save,
- .x6_options = MASQUERADE_opts,
- .xlate = MASQUERADE_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&masquerade_tg_reg);
-}
diff --git a/extensions/libipt_MASQUERADE.txlate b/extensions/libipt_MASQUERADE.txlate
index 40b6958a..0293b05b 100644
--- a/extensions/libipt_MASQUERADE.txlate
+++ b/extensions/libipt_MASQUERADE.txlate
@@ -1,8 +1,17 @@
iptables-translate -t nat -A POSTROUTING -j MASQUERADE
-nft add rule ip nat POSTROUTING counter masquerade
+nft 'add rule ip nat POSTROUTING counter masquerade'
iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10
-nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10
+nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10'
iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random
-nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random
+nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random'
+
+iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random
+nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade random'
+
+iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random-fully
+nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade fully-random'
+
+iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --random --random-fully
+nft 'add rule ip nat POSTROUTING ip protocol tcp counter masquerade random,fully-random'
diff --git a/extensions/libipt_NETMAP.t b/extensions/libipt_NETMAP.t
index 31924b98..0de856f0 100644
--- a/extensions/libipt_NETMAP.t
+++ b/extensions/libipt_NETMAP.t
@@ -1,4 +1,4 @@
:PREROUTING,INPUT,OUTPUT,POSTROUTING
*nat
-j NETMAP --to 1.2.3.0/24;=;OK
--j NETMAP --to 1.2.3.4;=;OK
+-j NETMAP --to 1.2.3.4;-j NETMAP --to 1.2.3.4/32;OK
diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c
deleted file mode 100644
index 7850306f..00000000
--- a/extensions/libipt_REDIRECT.c
+++ /dev/null
@@ -1,174 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_PORTS = 0,
- O_RANDOM,
- F_TO_PORTS = 1 << O_TO_PORTS,
- F_RANDOM = 1 << O_RANDOM,
-};
-
-static void REDIRECT_help(void)
-{
- printf(
-"REDIRECT target options:\n"
-" --to-ports <port>[-<port>]\n"
-" Port (range) to map to.\n"
-" [--random]\n");
-}
-
-static const struct xt_option_entry REDIRECT_opts[] = {
- {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-static void REDIRECT_init(struct xt_entry_target *t)
-{
- struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data;
-
- /* Actually, it's 0, but it's ignored at the moment. */
- mr->rangesize = 1;
-}
-
-/* Parses ports */
-static void
-parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr)
-{
- char *end = "";
- unsigned int port, maxport;
-
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) &&
- (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1)
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-
- switch (*end) {
- case '\0':
- mr->range[0].min.tcp.port
- = mr->range[0].max.tcp.port
- = htons(port);
- return;
- case '-':
- if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) &&
- (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1)
- break;
-
- if (maxport < port)
- break;
-
- mr->range[0].min.tcp.port = htons(port);
- mr->range[0].max.tcp.port = htons(maxport);
- return;
- default:
- break;
- }
- xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
-}
-
-static void REDIRECT_parse(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- struct nf_nat_ipv4_multi_range_compat *mr = (void *)(*cb->target)->data;
- int portok;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_PORTS:
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
- parse_ports(cb->arg, mr);
- if (cb->xflags & F_RANDOM)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- case O_RANDOM:
- if (cb->xflags & F_TO_PORTS)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- }
-}
-
-static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" redir ports ");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- }
-}
-
-static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(" --to-ports ");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- }
-}
-
-static int REDIRECT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct nf_nat_ipv4_multi_range_compat *mr =
- (const void *)params->target->data;
- const struct nf_nat_ipv4_range *r = &mr->range[0];
-
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, "redirect to :%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- xt_xlate_add(xl, "-%hu ", ntohs(r->max.tcp.port));
- if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
- xt_xlate_add(xl, " random ");
- }
-
- return 1;
-}
-
-static struct xtables_target redirect_tg_reg = {
- .name = "REDIRECT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .help = REDIRECT_help,
- .init = REDIRECT_init,
- .x6_parse = REDIRECT_parse,
- .print = REDIRECT_print,
- .save = REDIRECT_save,
- .x6_options = REDIRECT_opts,
- .xlate = REDIRECT_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&redirect_tg_reg);
-}
diff --git a/extensions/libipt_REDIRECT.t b/extensions/libipt_REDIRECT.t
deleted file mode 100644
index a0fb0ed1..00000000
--- a/extensions/libipt_REDIRECT.t
+++ /dev/null
@@ -1,6 +0,0 @@
-:PREROUTING,OUTPUT
-*nat
--p tcp -j REDIRECT --to-ports 42;=;OK
--p udp -j REDIRECT --to-ports 42-1234;=;OK
--p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
--j REDIRECT --to-ports 42;;FAIL
diff --git a/extensions/libipt_REDIRECT.txlate b/extensions/libipt_REDIRECT.txlate
deleted file mode 100644
index 815bb771..00000000
--- a/extensions/libipt_REDIRECT.txlate
+++ /dev/null
@@ -1,5 +0,0 @@
-iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
-nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080
-
-iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
-nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random
diff --git a/extensions/libipt_REJECT.man b/extensions/libipt_REJECT.man
index cc47aead..a7196cdc 100644
--- a/extensions/libipt_REJECT.man
+++ b/extensions/libipt_REJECT.man
@@ -44,9 +44,10 @@ response for a packet so classed would then terminate the healthy connection.
.PP
So, instead of:
.PP
--A INPUT ... -j REJECT
+\-A INPUT ... \-j REJECT
.PP
do consider using:
.PP
--A INPUT ... -m conntrack --ctstate INVALID -j DROP
--A INPUT ... -j REJECT
+\-A INPUT ... \-m conntrack \-\-ctstate INVALID \-j DROP
+.br
+\-A INPUT ... \-j REJECT
diff --git a/extensions/libipt_REJECT.t b/extensions/libipt_REJECT.t
index 5b26b107..3f69a729 100644
--- a/extensions/libipt_REJECT.t
+++ b/extensions/libipt_REJECT.t
@@ -1,5 +1,5 @@
:INPUT,FORWARD,OUTPUT
--j REJECT;=;OK
+-j REJECT;-j REJECT --reject-with icmp-port-unreachable;OK
-j REJECT --reject-with icmp-net-unreachable;=;OK
-j REJECT --reject-with icmp-host-unreachable;=;OK
-j REJECT --reject-with icmp-port-unreachable;=;OK
diff --git a/extensions/libipt_REJECT.txlate b/extensions/libipt_REJECT.txlate
index a1bfb5f4..022166a6 100644
--- a/extensions/libipt_REJECT.txlate
+++ b/extensions/libipt_REJECT.txlate
@@ -1,8 +1,8 @@
iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT
-nft add rule ip filter FORWARD tcp dport 22 counter reject
+nft 'add rule ip filter FORWARD tcp dport 22 counter reject'
iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp-net-unreachable
-nft add rule ip filter FORWARD tcp dport 22 counter reject with icmp type net-unreachable
+nft 'add rule ip filter FORWARD tcp dport 22 counter reject with icmp type net-unreachable'
iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset
-nft add rule ip filter FORWARD tcp dport 22 counter reject with tcp reset
+nft 'add rule ip filter FORWARD tcp dport 22 counter reject with tcp reset'
diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c
deleted file mode 100644
index e92d811c..00000000
--- a/extensions/libipt_SNAT.c
+++ /dev/null
@@ -1,325 +0,0 @@
-#include <stdio.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <iptables.h>
-#include <limits.h> /* INT_MAX in ip_tables.h */
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter/nf_nat.h>
-
-enum {
- O_TO_SRC = 0,
- O_RANDOM,
- O_RANDOM_FULLY,
- O_PERSISTENT,
- O_X_TO_SRC,
- F_TO_SRC = 1 << O_TO_SRC,
- F_RANDOM = 1 << O_RANDOM,
- F_RANDOM_FULLY = 1 << O_RANDOM_FULLY,
- F_X_TO_SRC = 1 << O_X_TO_SRC,
-};
-
-/* Source NAT data consists of a multi-range, indicating where to map
- to. */
-struct ipt_natinfo
-{
- struct xt_entry_target t;
- struct nf_nat_ipv4_multi_range_compat mr;
-};
-
-static void SNAT_help(void)
-{
- printf(
-"SNAT target options:\n"
-" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
-" Address to map source to.\n"
-"[--random] [--random-fully] [--persistent]\n");
-}
-
-static const struct xt_option_entry SNAT_opts[] = {
- {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_MULTI},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
- {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-static struct ipt_natinfo *
-append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range)
-{
- unsigned int size;
-
- /* One rangesize already in struct ipt_natinfo */
- size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
-
- info = realloc(info, size);
- if (!info)
- xtables_error(OTHER_PROBLEM, "Out of memory\n");
-
- info->t.u.target_size = size;
- info->mr.range[info->mr.rangesize] = *range;
- info->mr.rangesize++;
-
- return info;
-}
-
-/* Ranges expected in network order. */
-static struct xt_entry_target *
-parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
-{
- struct nf_nat_ipv4_range range;
- char *arg, *colon, *dash, *error;
- const struct in_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
- memset(&range, 0, sizeof(range));
- colon = strchr(arg, ':');
-
- if (colon) {
- int port;
-
- if (!portok)
- xtables_error(PARAMETER_PROBLEM,
- "Need TCP, UDP, SCTP or DCCP with port specification");
-
- range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-
- port = atoi(colon+1);
- if (port <= 0 || port > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", colon+1);
-
- error = strchr(colon+1, ':');
- if (error)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid port:port syntax - use dash\n");
-
- dash = strchr(colon, '-');
- if (!dash) {
- range.min.tcp.port
- = range.max.tcp.port
- = htons(port);
- } else {
- int maxport;
-
- maxport = atoi(dash + 1);
- if (maxport <= 0 || maxport > 65535)
- xtables_error(PARAMETER_PROBLEM,
- "Port `%s' not valid\n", dash+1);
- if (maxport < port)
- /* People are stupid. */
- xtables_error(PARAMETER_PROBLEM,
- "Port range `%s' funky\n", colon+1);
- range.min.tcp.port = htons(port);
- range.max.tcp.port = htons(maxport);
- }
- /* Starts with a colon? No IP info...*/
- if (colon == arg) {
- free(arg);
- return &(append_range(info, &range)->t);
- }
- *colon = '\0';
- }
-
- range.flags |= NF_NAT_RANGE_MAP_IPS;
- dash = strchr(arg, '-');
- if (colon && dash && dash > colon)
- dash = NULL;
-
- if (dash)
- *dash = '\0';
-
- ip = xtables_numeric_to_ipaddr(arg);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- arg);
- range.min_ip = ip->s_addr;
- if (dash) {
- ip = xtables_numeric_to_ipaddr(dash+1);
- if (!ip)
- xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
- dash+1);
- range.max_ip = ip->s_addr;
- } else
- range.max_ip = range.min_ip;
-
- free(arg);
- return &(append_range(info, &range)->t);
-}
-
-static void SNAT_parse(struct xt_option_call *cb)
-{
- const struct ipt_entry *entry = cb->xt_entry;
- struct ipt_natinfo *info = (void *)(*cb->target);
- int portok;
-
- if (entry->ip.proto == IPPROTO_TCP
- || entry->ip.proto == IPPROTO_UDP
- || entry->ip.proto == IPPROTO_SCTP
- || entry->ip.proto == IPPROTO_DCCP
- || entry->ip.proto == IPPROTO_ICMP)
- portok = 1;
- else
- portok = 0;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_SRC:
- if (cb->xflags & F_X_TO_SRC) {
- if (!kernel_version)
- get_kernel_version();
- if (kernel_version > LINUX_VERSION(2, 6, 10))
- xtables_error(PARAMETER_PROBLEM,
- "SNAT: Multiple --to-source not supported");
- }
- *cb->target = parse_to(cb->arg, portok, info);
- cb->xflags |= F_X_TO_SRC;
- break;
- case O_PERSISTENT:
- info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT;
- break;
- }
-}
-
-static void SNAT_fcheck(struct xt_fcheck_call *cb)
-{
- static const unsigned int f = F_TO_SRC | F_RANDOM;
- static const unsigned int r = F_TO_SRC | F_RANDOM_FULLY;
- struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
-
- if ((cb->xflags & f) == f)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
- if ((cb->xflags & r) == r)
- mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
-}
-
-static void print_range(const struct nf_nat_ipv4_range *r)
-{
- if (r->flags & NF_NAT_RANGE_MAP_IPS) {
- struct in_addr a;
-
- a.s_addr = r->min_ip;
- printf("%s", xtables_ipaddr_to_numeric(&a));
- if (r->max_ip != r->min_ip) {
- a.s_addr = r->max_ip;
- printf("-%s", xtables_ipaddr_to_numeric(&a));
- }
- }
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- printf(":");
- printf("%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- printf("-%hu", ntohs(r->max.tcp.port));
- }
-}
-
-static void SNAT_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
-
- printf(" to:");
- for (i = 0; i < info->mr.rangesize; i++) {
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" random-fully");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" persistent");
- }
-}
-
-static void SNAT_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct ipt_natinfo *info = (const void *)target;
- unsigned int i = 0;
-
- for (i = 0; i < info->mr.rangesize; i++) {
- printf(" --to-source ");
- print_range(&info->mr.range[i]);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
- printf(" --random");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
- printf(" --random-fully");
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
- printf(" --persistent");
- }
-}
-
-static void print_range_xlate(const struct nf_nat_ipv4_range *r,
- struct xt_xlate *xl)
-{
- if (r->flags & NF_NAT_RANGE_MAP_IPS) {
- struct in_addr a;
-
- a.s_addr = r->min_ip;
- xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&a));
- if (r->max_ip != r->min_ip) {
- a.s_addr = r->max_ip;
- xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&a));
- }
- }
- if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
- xt_xlate_add(xl, ":");
- xt_xlate_add(xl, "%hu", ntohs(r->min.tcp.port));
- if (r->max.tcp.port != r->min.tcp.port)
- xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port));
- }
-}
-
-static int SNAT_xlate(struct xt_xlate *xl,
- const struct xt_xlate_tg_params *params)
-{
- const struct ipt_natinfo *info = (const void *)params->target;
- unsigned int i = 0;
- bool sep_need = false;
- const char *sep = " ";
-
- for (i = 0; i < info->mr.rangesize; i++) {
- xt_xlate_add(xl, "snat to ");
- print_range_xlate(&info->mr.range[i], xl);
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) {
- xt_xlate_add(xl, " random");
- sep_need = true;
- }
- if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%sfully-random", sep);
- sep_need = true;
- }
- if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) {
- if (sep_need)
- sep = ",";
- xt_xlate_add(xl, "%spersistent", sep);
- }
- }
-
- return 1;
-}
-
-static struct xtables_target snat_tg_reg = {
- .name = "SNAT",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
- .help = SNAT_help,
- .x6_parse = SNAT_parse,
- .x6_fcheck = SNAT_fcheck,
- .print = SNAT_print,
- .save = SNAT_save,
- .x6_options = SNAT_opts,
- .xlate = SNAT_xlate,
-};
-
-void _init(void)
-{
- xtables_register_target(&snat_tg_reg);
-}
diff --git a/extensions/libipt_SNAT.t b/extensions/libipt_SNAT.t
index 186e1cb8..c31d6e7c 100644
--- a/extensions/libipt_SNAT.t
+++ b/extensions/libipt_SNAT.t
@@ -4,6 +4,12 @@
-j SNAT --to-source 1.1.1.1-1.1.1.10;=;OK
-j SNAT --to-source 1.1.1.1:1025-65535;;FAIL
-j SNAT --to-source 1.1.1.1 --to-source 2.2.2.2;;FAIL
+-j SNAT --to-source 1.1.1.1 --random;=;OK
+-j SNAT --to-source 1.1.1.1 --random-fully;=;OK
+-j SNAT --to-source 1.1.1.1 --persistent;=;OK
+-j SNAT --to-source 1.1.1.1 --random --persistent;=;OK
+-j SNAT --to-source 1.1.1.1 --random --random-fully;=;OK
+-j SNAT --to-source 1.1.1.1 --random --random-fully --persistent;=;OK
-p tcp -j SNAT --to-source 1.1.1.1:1025-65535;=;OK
-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65535;=;OK
-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65536;;FAIL
diff --git a/extensions/libipt_SNAT.txlate b/extensions/libipt_SNAT.txlate
index 01592fad..83afef95 100644
--- a/extensions/libipt_SNAT.txlate
+++ b/extensions/libipt_SNAT.txlate
@@ -1,14 +1,14 @@
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4
-nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4
+nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4'
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
-nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4-1.2.3.6
+nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4-1.2.3.6'
iptables-translate -t nat -A postrouting -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
-nft add rule ip nat postrouting oifname "eth0" ip protocol tcp counter snat to 1.2.3.4:1-1023
+nft 'add rule ip nat postrouting oifname "eth0" ip protocol tcp counter snat to 1.2.3.4:1-1023'
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random
-nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random
+nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random'
iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random --persistent
-nft add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random,persistent
+nft 'add rule ip nat postrouting oifname "eth0" counter snat to 1.2.3.4 random,persistent'
diff --git a/extensions/libipt_ULOG.man b/extensions/libipt_ULOG.man
index c91f7764..eb37d4fb 100644
--- a/extensions/libipt_ULOG.man
+++ b/extensions/libipt_ULOG.man
@@ -1,4 +1,4 @@
-This is the deprecated ipv4-only predecessor of the NFLOG target.
+This is the deprecated IPv4-only predecessor of the NFLOG target.
It provides userspace logging of matching packets. When this
target is set for a rule, the Linux kernel will multicast this packet
through a
@@ -9,7 +9,7 @@ Like LOG, this is a "non-terminating target", i.e. rule traversal
continues at the next rule.
.TP
\fB\-\-ulog\-nlgroup\fP \fInlgroup\fP
-This specifies the netlink group (1-32) to which the packet is sent.
+This specifies the netlink group (1\(en32) to which the packet is sent.
Default value is 1.
.TP
\fB\-\-ulog\-prefix\fP \fIprefix\fP
diff --git a/extensions/libipt_ah.c b/extensions/libipt_ah.c
index fec5705c..39e3013d 100644
--- a/extensions/libipt_ah.c
+++ b/extensions/libipt_ah.c
@@ -39,13 +39,18 @@ static void ah_parse(struct xt_option_call *cb)
ahinfo->invflags |= IPT_AH_INV_SPI;
}
+static bool skip_spi_match(uint32_t min, uint32_t max, bool inv)
+{
+ return min == 0 && max == UINT32_MAX && !inv;
+}
+
static void
print_spis(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFFFFFFFF || invert) {
+ if (!skip_spi_match(min, max, invert)) {
printf("%s", name);
if (min == max) {
printf(":%s", inv);
@@ -75,11 +80,10 @@ static void ah_print(const void *ip, const struct xt_entry_match *match,
static void ah_save(const void *ip, const struct xt_entry_match *match)
{
const struct ipt_ah *ahinfo = (struct ipt_ah *)match->data;
+ bool inv_spi = ahinfo->invflags & IPT_AH_INV_SPI;
- if (!(ahinfo->spis[0] == 0
- && ahinfo->spis[1] == 0xFFFFFFFF)) {
- printf("%s --ahspi ",
- (ahinfo->invflags & IPT_AH_INV_SPI) ? " !" : "");
+ if (!skip_spi_match(ahinfo->spis[0], ahinfo->spis[1], inv_spi)) {
+ printf("%s --ahspi ", inv_spi ? " !" : "");
if (ahinfo->spis[0]
!= ahinfo->spis[1])
printf("%u:%u",
@@ -96,15 +100,17 @@ static int ah_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ipt_ah *ahinfo = (struct ipt_ah *)params->match->data;
+ bool inv_spi = ahinfo->invflags & IPT_AH_INV_SPI;
- if (!(ahinfo->spis[0] == 0 && ahinfo->spis[1] == 0xFFFFFFFF)) {
- xt_xlate_add(xl, "ah spi%s ",
- (ahinfo->invflags & IPT_AH_INV_SPI) ? " !=" : "");
+ if (!skip_spi_match(ahinfo->spis[0], ahinfo->spis[1], inv_spi)) {
+ xt_xlate_add(xl, "ah spi%s ", inv_spi ? " !=" : "");
if (ahinfo->spis[0] != ahinfo->spis[1])
xt_xlate_add(xl, "%u-%u", ahinfo->spis[0],
ahinfo->spis[1]);
else
xt_xlate_add(xl, "%u", ahinfo->spis[0]);
+ } else {
+ xt_xlate_add(xl, "meta l4proto ah");
}
return 1;
diff --git a/extensions/libipt_ah.t b/extensions/libipt_ah.t
index cd853865..60593660 100644
--- a/extensions/libipt_ah.t
+++ b/extensions/libipt_ah.t
@@ -11,3 +11,9 @@
-m ah --ahspi;;FAIL
-m ah;;FAIL
-p ah -m ah;=;OK
+-p ah -m ah --ahspi :;-p ah -m ah;OK
+-p ah -m ah ! --ahspi :;-p ah -m ah ! --ahspi 0:4294967295;OK
+-p ah -m ah --ahspi :3;-p ah -m ah --ahspi 0:3;OK
+-p ah -m ah --ahspi 3:;-p ah -m ah --ahspi 3:4294967295;OK
+-p ah -m ah --ahspi 3:3;-p ah -m ah --ahspi 3;OK
+-p ah -m ah --ahspi 4:3;;FAIL
diff --git a/extensions/libipt_ah.txlate b/extensions/libipt_ah.txlate
index ea3ef3e9..baf5a0ae 100644
--- a/extensions/libipt_ah.txlate
+++ b/extensions/libipt_ah.txlate
@@ -1,8 +1,14 @@
iptables-translate -A INPUT -p 51 -m ah --ahspi 500 -j DROP
-nft add rule ip filter INPUT ah spi 500 counter drop
+nft 'add rule ip filter INPUT ah spi 500 counter drop'
iptables-translate -A INPUT -p 51 -m ah --ahspi 500:600 -j DROP
-nft add rule ip filter INPUT ah spi 500-600 counter drop
+nft 'add rule ip filter INPUT ah spi 500-600 counter drop'
iptables-translate -A INPUT -p 51 -m ah ! --ahspi 50 -j DROP
-nft add rule ip filter INPUT ah spi != 50 counter drop
+nft 'add rule ip filter INPUT ah spi != 50 counter drop'
+
+iptables-translate -A INPUT -p 51 -m ah --ahspi 0:4294967295 -j DROP
+nft 'add rule ip filter INPUT meta l4proto ah counter drop'
+
+iptables-translate -A INPUT -p 51 -m ah ! --ahspi 0:4294967295 -j DROP
+nft 'add rule ip filter INPUT ah spi != 0-4294967295 counter drop'
diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c
index e5e23661..171b3b39 100644
--- a/extensions/libipt_icmp.c
+++ b/extensions/libipt_icmp.c
@@ -19,61 +19,6 @@ enum {
O_ICMP_TYPE = 0,
};
-static const struct xt_icmp_names icmp_codes[] = {
- { "any", 0xFF, 0, 0xFF },
- { "echo-reply", 0, 0, 0xFF },
- /* Alias */ { "pong", 0, 0, 0xFF },
-
- { "destination-unreachable", 3, 0, 0xFF },
- { "network-unreachable", 3, 0, 0 },
- { "host-unreachable", 3, 1, 1 },
- { "protocol-unreachable", 3, 2, 2 },
- { "port-unreachable", 3, 3, 3 },
- { "fragmentation-needed", 3, 4, 4 },
- { "source-route-failed", 3, 5, 5 },
- { "network-unknown", 3, 6, 6 },
- { "host-unknown", 3, 7, 7 },
- { "network-prohibited", 3, 9, 9 },
- { "host-prohibited", 3, 10, 10 },
- { "TOS-network-unreachable", 3, 11, 11 },
- { "TOS-host-unreachable", 3, 12, 12 },
- { "communication-prohibited", 3, 13, 13 },
- { "host-precedence-violation", 3, 14, 14 },
- { "precedence-cutoff", 3, 15, 15 },
-
- { "source-quench", 4, 0, 0xFF },
-
- { "redirect", 5, 0, 0xFF },
- { "network-redirect", 5, 0, 0 },
- { "host-redirect", 5, 1, 1 },
- { "TOS-network-redirect", 5, 2, 2 },
- { "TOS-host-redirect", 5, 3, 3 },
-
- { "echo-request", 8, 0, 0xFF },
- /* Alias */ { "ping", 8, 0, 0xFF },
-
- { "router-advertisement", 9, 0, 0xFF },
-
- { "router-solicitation", 10, 0, 0xFF },
-
- { "time-exceeded", 11, 0, 0xFF },
- /* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
- { "ttl-zero-during-transit", 11, 0, 0 },
- { "ttl-zero-during-reassembly", 11, 1, 1 },
-
- { "parameter-problem", 12, 0, 0xFF },
- { "ip-header-bad", 12, 0, 0 },
- { "required-option-missing", 12, 1, 1 },
-
- { "timestamp-request", 13, 0, 0xFF },
-
- { "timestamp-reply", 14, 0, 0xFF },
-
- { "address-mask-request", 17, 0, 0xFF },
-
- { "address-mask-reply", 18, 0, 0xFF }
-};
-
static void icmp_help(void)
{
printf(
@@ -90,59 +35,6 @@ static const struct xt_option_entry icmp_opts[] = {
XTOPT_TABLEEND,
};
-static void
-parse_icmp(const char *icmptype, uint8_t *type, uint8_t code[])
-{
- static const unsigned int limit = ARRAY_SIZE(icmp_codes);
- unsigned int match = limit;
- unsigned int i;
-
- for (i = 0; i < limit; i++) {
- if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype))
- == 0) {
- if (match != limit)
- xtables_error(PARAMETER_PROBLEM,
- "Ambiguous ICMP type `%s':"
- " `%s' or `%s'?",
- icmptype,
- icmp_codes[match].name,
- icmp_codes[i].name);
- match = i;
- }
- }
-
- if (match != limit) {
- *type = icmp_codes[match].type;
- code[0] = icmp_codes[match].code_min;
- code[1] = icmp_codes[match].code_max;
- } else {
- char *slash;
- char buffer[strlen(icmptype) + 1];
- unsigned int number;
-
- strcpy(buffer, icmptype);
- slash = strchr(buffer, '/');
-
- if (slash)
- *slash = '\0';
-
- if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid ICMP type `%s'\n", buffer);
- *type = number;
- if (slash) {
- if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid ICMP code `%s'\n",
- slash+1);
- code[0] = code[1] = number;
- } else {
- code[0] = 0;
- code[1] = 0xFF;
- }
- }
-}
-
static void icmp_init(struct xt_entry_match *m)
{
struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
@@ -156,7 +48,7 @@ static void icmp_parse(struct xt_option_call *cb)
struct ipt_icmp *icmpinfo = cb->data;
xtables_option_parse(cb);
- parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
+ ipt_parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
if (cb->invert)
icmpinfo->invflags |= IPT_ICMP_INV;
}
@@ -216,7 +108,8 @@ static void icmp_save(const void *ip, const struct xt_entry_match *match)
printf(" !");
/* special hack for 'any' case */
- if (icmp->type == 0xFF) {
+ if (icmp->type == 0xFF &&
+ icmp->code[0] == 0 && icmp->code[1] == 0xFF) {
printf(" --icmp-type any");
} else {
printf(" --icmp-type %u", icmp->type);
diff --git a/extensions/libipt_icmp.t b/extensions/libipt_icmp.t
index f4ba65c2..4ea93621 100644
--- a/extensions/libipt_icmp.t
+++ b/extensions/libipt_icmp.t
@@ -1,11 +1,8 @@
:INPUT,FORWARD,OUTPUT
-p icmp -m icmp --icmp-type any;=;OK
-# output uses the number, better use the name?
-# ERROR: cannot find: iptables -I INPUT -p icmp -m icmp --icmp-type echo-reply
-# -p icmp -m icmp --icmp-type echo-reply;=;OK
-# output uses the number, better use the name?
-# ERROR: annot find: iptables -I INPUT -p icmp -m icmp --icmp-type destination-unreachable
-# -p icmp -m icmp --icmp-type destination-unreachable;=;OK
+# XXX: output uses the number, better use the name?
+-p icmp -m icmp --icmp-type echo-reply;-p icmp -m icmp --icmp-type 0;OK
+-p icmp -m icmp --icmp-type destination-unreachable;-p icmp -m icmp --icmp-type 3;OK
# it does not acccept name/name, should we accept this?
# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable
# -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable;=;OK
@@ -13,3 +10,5 @@
# we accept "iptables -I INPUT -p tcp -m tcp", why not this below?
# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp
# -p icmp -m icmp;=;OK
+-p icmp -m icmp --icmp-type 255/255;=;OK
+-p icmp -m icmp --icmp-type 255/0:255;-p icmp -m icmp --icmp-type any;OK
diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate
index a2aec8e2..e7208d8b 100644
--- a/extensions/libipt_icmp.txlate
+++ b/extensions/libipt_icmp.txlate
@@ -1,11 +1,11 @@
iptables-translate -t filter -A INPUT -m icmp --icmp-type echo-reply -j ACCEPT
-nft add rule ip filter INPUT icmp type echo-reply counter accept
+nft 'add rule ip filter INPUT icmp type echo-reply counter accept'
iptables-translate -t filter -A INPUT -m icmp --icmp-type 3 -j ACCEPT
-nft add rule ip filter INPUT icmp type destination-unreachable counter accept
+nft 'add rule ip filter INPUT icmp type destination-unreachable counter accept'
iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT
-nft add rule ip filter INPUT icmp type != destination-unreachable counter accept
+nft 'add rule ip filter INPUT icmp type != destination-unreachable counter accept'
iptables-translate -t filter -A INPUT -m icmp --icmp-type any -j ACCEPT
-nft add rule ip filter INPUT ip protocol icmp counter accept
+nft 'add rule ip filter INPUT ip protocol icmp counter accept'
diff --git a/extensions/libipt_realm.txlate b/extensions/libipt_realm.txlate
index 7d710294..6d134546 100644
--- a/extensions/libipt_realm.txlate
+++ b/extensions/libipt_realm.txlate
@@ -1,11 +1,11 @@
iptables-translate -A PREROUTING -m realm --realm 4
-nft add rule ip filter PREROUTING rtclassid 0x4 counter
+nft 'add rule ip filter PREROUTING rtclassid 0x4 counter'
iptables-translate -A PREROUTING -m realm --realm 5/5
-nft add rule ip filter PREROUTING rtclassid and 0x5 == 0x5 counter
+nft 'add rule ip filter PREROUTING rtclassid and 0x5 == 0x5 counter'
iptables-translate -A PREROUTING -m realm ! --realm 50
-nft add rule ip filter PREROUTING rtclassid != 0x32 counter
+nft 'add rule ip filter PREROUTING rtclassid != 0x32 counter'
iptables-translate -A INPUT -m realm --realm 1/0xf
-nft add rule ip filter INPUT rtclassid and 0xf == 0x1 counter
+nft 'add rule ip filter INPUT rtclassid and 0xf == 0x1 counter'
diff --git a/extensions/libipt_ttl.c b/extensions/libipt_ttl.c
index 6bdd2196..86ba554e 100644
--- a/extensions/libipt_ttl.c
+++ b/extensions/libipt_ttl.c
@@ -106,7 +106,7 @@ static int ttl_xlate(struct xt_xlate *xl,
const struct ipt_ttl_info *info =
(struct ipt_ttl_info *) params->match->data;
- switch (info->mode) {
+ switch (info->mode) {
case IPT_TTL_EQ:
xt_xlate_add(xl, "ip ttl");
break;
@@ -121,7 +121,7 @@ static int ttl_xlate(struct xt_xlate *xl,
break;
default:
/* Should not happen. */
- break;
+ return 0;
}
xt_xlate_add(xl, " %u", info->ttl);
diff --git a/extensions/libipt_ttl.txlate b/extensions/libipt_ttl.txlate
index 3d5d6a70..6b90ff99 100644
--- a/extensions/libipt_ttl.txlate
+++ b/extensions/libipt_ttl.txlate
@@ -1,5 +1,5 @@
iptables-translate -A INPUT -m ttl --ttl-eq 3 -j ACCEPT
-nft add rule ip filter INPUT ip ttl 3 counter accept
+nft 'add rule ip filter INPUT ip ttl 3 counter accept'
iptables-translate -A INPUT -m ttl --ttl-gt 5 -j ACCEPT
-nft add rule ip filter INPUT ip ttl gt 5 counter accept
+nft 'add rule ip filter INPUT ip ttl gt 5 counter accept'
diff --git a/extensions/libxt_AUDIT.txlate b/extensions/libxt_AUDIT.txlate
index abd11eae..c1650b9a 100644
--- a/extensions/libxt_AUDIT.txlate
+++ b/extensions/libxt_AUDIT.txlate
@@ -1,8 +1,8 @@
iptables-translate -t filter -A INPUT -j AUDIT --type accept
-nft add rule ip filter INPUT counter log level audit
+nft 'add rule ip filter INPUT counter log level audit'
iptables-translate -t filter -A INPUT -j AUDIT --type drop
-nft add rule ip filter INPUT counter log level audit
+nft 'add rule ip filter INPUT counter log level audit'
iptables-translate -t filter -A INPUT -j AUDIT --type reject
-nft add rule ip filter INPUT counter log level audit
+nft 'add rule ip filter INPUT counter log level audit'
diff --git a/extensions/libxt_CLASSIFY.txlate b/extensions/libxt_CLASSIFY.txlate
index 3b349237..3150c69e 100644
--- a/extensions/libxt_CLASSIFY.txlate
+++ b/extensions/libxt_CLASSIFY.txlate
@@ -1,8 +1,8 @@
iptables-translate -A OUTPUT -j CLASSIFY --set-class 0:0
-nft add rule ip filter OUTPUT counter meta priority set none
+nft 'add rule ip filter OUTPUT counter meta priority set none'
iptables-translate -A OUTPUT -j CLASSIFY --set-class ffff:ffff
-nft add rule ip filter OUTPUT counter meta priority set root
+nft 'add rule ip filter OUTPUT counter meta priority set root'
iptables-translate -A OUTPUT -j CLASSIFY --set-class 1:234
-nft add rule ip filter OUTPUT counter meta priority set 1:234
+nft 'add rule ip filter OUTPUT counter meta priority set 1:234'
diff --git a/extensions/libxt_CONNMARK.c b/extensions/libxt_CONNMARK.c
index 21e10913..a6568c99 100644
--- a/extensions/libxt_CONNMARK.c
+++ b/extensions/libxt_CONNMARK.c
@@ -595,11 +595,11 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl,
{
const struct xt_connmark_tginfo2 *info =
(const void *)params->target->data;
- const char *shift_op = xt_connmark_shift_ops[info->shift_dir];
+ const char *braces = info->shift_bits ? "( " : "";
switch (info->mode) {
case XT_CONNMARK_SET:
- xt_xlate_add(xl, "ct mark set ");
+ xt_xlate_add(xl, "ct mark set %s", braces);
if (info->ctmask == 0xFFFFFFFFU)
xt_xlate_add(xl, "0x%x ", info->ctmark);
else if (info->ctmark == 0)
@@ -615,26 +615,31 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl,
info->ctmark, ~info->ctmask);
break;
case XT_CONNMARK_SAVE:
- xt_xlate_add(xl, "ct mark set mark");
+ xt_xlate_add(xl, "ct mark set %smark", braces);
if (!(info->nfmask == UINT32_MAX &&
info->ctmask == UINT32_MAX)) {
if (info->nfmask == info->ctmask)
xt_xlate_add(xl, " and 0x%x", info->nfmask);
+ else
+ return 0;
}
break;
case XT_CONNMARK_RESTORE:
- xt_xlate_add(xl, "meta mark set ct mark");
+ xt_xlate_add(xl, "meta mark set %sct mark", braces);
if (!(info->nfmask == UINT32_MAX &&
info->ctmask == UINT32_MAX)) {
if (info->nfmask == info->ctmask)
xt_xlate_add(xl, " and 0x%x", info->nfmask);
+ else
+ return 0;
}
break;
}
if (info->mode <= XT_CONNMARK_RESTORE &&
info->shift_bits != 0) {
- xt_xlate_add(xl, " %s %u", shift_op, info->shift_bits);
+ xt_xlate_add(xl, " ) %s %u",
+ info->shift_dir ? ">>" : "<<", info->shift_bits);
}
return 1;
diff --git a/extensions/libxt_CONNMARK.man b/extensions/libxt_CONNMARK.man
index 93179239..ccd7da61 100644
--- a/extensions/libxt_CONNMARK.man
+++ b/extensions/libxt_CONNMARK.man
@@ -8,7 +8,7 @@ Zero out the bits given by \fImask\fP and XOR \fIvalue\fP into the ctmark.
Copy the packet mark (nfmark) to the connection mark (ctmark) using the given
masks. The new nfmark value is determined as follows:
.IP
-ctmark = (ctmark & ~ctmask) ^ (nfmark & nfmask)
+ctmark = (ctmark & \(tictmask) \(ha (nfmark & nfmask)
.IP
i.e. \fIctmask\fP defines what bits to clear and \fInfmask\fP what bits of the
nfmark to XOR into the ctmark. \fIctmask\fP and \fInfmask\fP default to
@@ -18,7 +18,7 @@ nfmark to XOR into the ctmark. \fIctmask\fP and \fInfmask\fP default to
Copy the connection mark (ctmark) to the packet mark (nfmark) using the given
masks. The new ctmark value is determined as follows:
.IP
-nfmark = (nfmark & ~\fInfmask\fP) ^ (ctmark & \fIctmask\fP);
+nfmark = (nfmark & \(ti\fInfmask\fP) \(ha (ctmark & \fIctmask\fP);
.IP
i.e. \fInfmask\fP defines what bits to clear and \fIctmask\fP what bits of the
ctmark to XOR into the nfmark. \fIctmask\fP and \fInfmask\fP default to
diff --git a/extensions/libxt_CONNMARK.t b/extensions/libxt_CONNMARK.t
index 79a838fe..c9b2b4a5 100644
--- a/extensions/libxt_CONNMARK.t
+++ b/extensions/libxt_CONNMARK.t
@@ -1,7 +1,7 @@
:PREROUTING,FORWARD,OUTPUT,POSTROUTING
*mangle
--j CONNMARK --restore-mark;=;OK
--j CONNMARK --save-mark;=;OK
--j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --save-mark;OK
--j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --restore-mark;OK
+-j CONNMARK --restore-mark;-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff;OK
+-j CONNMARK --save-mark;-j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff;OK
+-j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;=;OK
+-j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;=;OK
-j CONNMARK;;FAIL
diff --git a/extensions/libxt_CONNMARK.txlate b/extensions/libxt_CONNMARK.txlate
index ce40ae5e..5da4d6c7 100644
--- a/extensions/libxt_CONNMARK.txlate
+++ b/extensions/libxt_CONNMARK.txlate
@@ -1,20 +1,23 @@
iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0
-nft add rule ip mangle PREROUTING counter ct mark set 0x0
+nft 'add rule ip mangle PREROUTING counter ct mark set 0x0'
iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x16
-nft add rule ip mangle PREROUTING counter ct mark set 0x16
+nft 'add rule ip mangle PREROUTING counter ct mark set 0x16'
iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-xmark 0x16/0x12
-nft add rule ip mangle PREROUTING counter ct mark set ct mark xor 0x16 and 0xffffffed
+nft 'add rule ip mangle PREROUTING counter ct mark set ct mark xor 0x16 and 0xffffffed'
iptables-translate -t mangle -A PREROUTING -j CONNMARK --and-mark 0x16
-nft add rule ip mangle PREROUTING counter ct mark set ct mark and 0x16
+nft 'add rule ip mangle PREROUTING counter ct mark set ct mark and 0x16'
iptables-translate -t mangle -A PREROUTING -j CONNMARK --or-mark 0x16
-nft add rule ip mangle PREROUTING counter ct mark set ct mark or 0x16
+nft 'add rule ip mangle PREROUTING counter ct mark set ct mark or 0x16'
iptables-translate -t mangle -A PREROUTING -j CONNMARK --save-mark
-nft add rule ip mangle PREROUTING counter ct mark set mark
+nft 'add rule ip mangle PREROUTING counter ct mark set mark'
iptables-translate -t mangle -A PREROUTING -j CONNMARK --restore-mark
-nft add rule ip mangle PREROUTING counter meta mark set ct mark
+nft 'add rule ip mangle PREROUTING counter meta mark set ct mark'
+
+iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x23/0x42 --right-shift-mark 5
+nft 'add rule ip mangle PREROUTING counter ct mark set ( ct mark xor 0x23 and 0xffffff9c ) >> 5'
diff --git a/extensions/libxt_CONNSECMARK.c b/extensions/libxt_CONNSECMARK.c
index 0b3cd79d..6da589d3 100644
--- a/extensions/libxt_CONNSECMARK.c
+++ b/extensions/libxt_CONNSECMARK.c
@@ -66,7 +66,8 @@ static void print_connsecmark(const struct xt_connsecmark_target_info *info)
break;
default:
- xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode);
+ xtables_error(OTHER_PROBLEM,
+ PFX "invalid mode %hhu", info->mode);
}
}
diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
index fbbbe266..18824665 100644
--- a/extensions/libxt_CT.c
+++ b/extensions/libxt_CT.c
@@ -117,7 +117,7 @@ static void ct_parse_zone_id(const char *opt, unsigned int opt_id,
if (!xtables_strtoul(opt, NULL, &val, 0, UINT16_MAX))
xtables_error(PARAMETER_PROBLEM,
- "Cannot parse %s as a zone ID\n", opt);
+ "Cannot parse %s as a zone ID", opt);
*zone_id = (uint16_t)val;
}
diff --git a/extensions/libxt_CT.man b/extensions/libxt_CT.man
index fc692f9a..7523ead4 100644
--- a/extensions/libxt_CT.man
+++ b/extensions/libxt_CT.man
@@ -20,12 +20,12 @@ the ctmark, not nfmark), \fBnatseqinfo\fP, \fBsecmark\fP (ctsecmark).
Only generate the specified expectation events for this connection.
Possible event types are: \fBnew\fP.
.TP
-\fB\-\-zone-orig\fP {\fIid\fP|\fBmark\fP}
+\fB\-\-zone\-orig\fP {\fIid\fP|\fBmark\fP}
For traffic coming from ORIGINAL direction, assign this packet to zone
\fIid\fP and only have lookups done in that zone. If \fBmark\fP is used
instead of \fIid\fP, the zone is derived from the packet nfmark.
.TP
-\fB\-\-zone-reply\fP {\fIid\fP|\fBmark\fP}
+\fB\-\-zone\-reply\fP {\fIid\fP|\fBmark\fP}
For traffic coming from REPLY direction, assign this packet to zone
\fIid\fP and only have lookups done in that zone. If \fBmark\fP is used
instead of \fIid\fP, the zone is derived from the packet nfmark.
diff --git a/extensions/libxt_DNAT.man b/extensions/libxt_DNAT.man
index 225274ff..090ecb42 100644
--- a/extensions/libxt_DNAT.man
+++ b/extensions/libxt_DNAT.man
@@ -10,7 +10,7 @@ should be modified (and all future packets in this connection will
also be mangled), and rules should cease being examined. It takes the
following options:
.TP
-\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]]
+\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP[\fB/\fIbaseport\fP]]]
which can specify a single new destination IP address, an inclusive
range of IP addresses. Optionally a port range,
if the rule also specifies one of the following protocols:
@@ -18,17 +18,14 @@ if the rule also specifies one of the following protocols:
If no port range is specified, then the destination port will never be
modified. If no IP address is specified then only the destination port
will be modified.
-In Kernels up to 2.6.10 you can add several \-\-to\-destination options. For
-those kernels, if you specify more than one destination address, either via an
-address range or multiple \-\-to\-destination options, a simple round-robin (one
-after another in cycle) load balancing takes place between these addresses.
-Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
-anymore.
+If \fBbaseport\fP is given, the difference of the original destination port and
+its value is used as offset into the mapping port range. This allows one to create
+shifted portmap ranges and is available since kernel version 4.18.
+For a single port or \fIbaseport\fP, a service name as listed in
+\fB/etc/services\fP may be used.
.TP
\fB\-\-random\fP
-If option
-\fB\-\-random\fP
-is used then port mapping will be randomized (kernel >= 2.6.22).
+Randomize source port mapping (kernel >= 2.6.22).
.TP
\fB\-\-persistent\fP
Gives a client the same source-/destination-address for each connection.
diff --git a/extensions/libxt_DNAT.txlate b/extensions/libxt_DNAT.txlate
new file mode 100644
index 00000000..e005245d
--- /dev/null
+++ b/extensions/libxt_DNAT.txlate
@@ -0,0 +1,35 @@
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4
+nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4'
+
+iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10
+nft 'add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10'
+
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023
+nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4:1-1023'
+
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random
+nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random'
+
+iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent
+nft 'add rule ip nat prerouting oifname "eth0" ip protocol tcp counter dnat to 1.2.3.4 random,persistent'
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234
+nft 'add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234'
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 8080 -j DNAT --to-destination fec0::1234-fec0::2000
+nft 'add rule ip6 nat prerouting tcp dport 8080 counter dnat to fec0::1234-fec0::2000'
+
+ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80
+nft 'add rule ip6 nat prerouting iifname "eth1" tcp dport 8080 counter dnat to [fec0::1234]:80'
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20
+nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20'
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234-fec0::2000]:1-20
+nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234-fec0::2000]:1-20'
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent
+nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent'
+
+ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent
+nft 'add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent'
diff --git a/extensions/libxt_DSCP.t b/extensions/libxt_DSCP.t
index fcc55986..762fcd31 100644
--- a/extensions/libxt_DSCP.t
+++ b/extensions/libxt_DSCP.t
@@ -1,6 +1,6 @@
:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
*mangle
--j DSCP --set-dscp 0;=;OK
+-j DSCP --set-dscp 0x00;=;OK
-j DSCP --set-dscp 0x3f;=;OK
-j DSCP --set-dscp -1;;FAIL
-j DSCP --set-dscp 0x40;;FAIL
diff --git a/extensions/libxt_DSCP.txlate b/extensions/libxt_DSCP.txlate
index 442742ef..f7801a83 100644
--- a/extensions/libxt_DSCP.txlate
+++ b/extensions/libxt_DSCP.txlate
@@ -1,5 +1,5 @@
iptables-translate -A OUTPUT -j DSCP --set-dscp 1
-nft add rule ip filter OUTPUT counter ip dscp set 0x01
+nft 'add rule ip filter OUTPUT counter ip dscp set 0x01'
ip6tables-translate -A OUTPUT -j DSCP --set-dscp 6
-nft add rule ip6 filter OUTPUT counter ip6 dscp set 0x06
+nft 'add rule ip6 filter OUTPUT counter ip6 dscp set 0x06'
diff --git a/extensions/libxt_HMARK.c b/extensions/libxt_HMARK.c
index 94aebe9a..83ce5003 100644
--- a/extensions/libxt_HMARK.c
+++ b/extensions/libxt_HMARK.c
@@ -41,6 +41,7 @@ static void HMARK_help(void)
#define hi struct xt_hmark_info
+/* values must match XT_HMARK_* ones (apart from O_HMARK_TYPE) */
enum {
O_HMARK_SADDR_MASK,
O_HMARK_DADDR_MASK,
@@ -88,32 +89,32 @@ static const struct xt_option_entry HMARK_opts[] = {
{ .name = "hmark-sport-mask",
.type = XTTYPE_UINT16,
.id = O_HMARK_SPORT_MASK,
- .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.p16.src)
+ .flags = XTOPT_PUT | XTOPT_NBO, XTOPT_POINTER(hi, port_mask.p16.src)
},
{ .name = "hmark-dport-mask",
.type = XTTYPE_UINT16,
.id = O_HMARK_DPORT_MASK,
- .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.p16.dst)
+ .flags = XTOPT_PUT | XTOPT_NBO, XTOPT_POINTER(hi, port_mask.p16.dst)
},
{ .name = "hmark-spi-mask",
.type = XTTYPE_UINT32,
.id = O_HMARK_SPI_MASK,
- .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.v32)
+ .flags = XTOPT_PUT | XTOPT_NBO, XTOPT_POINTER(hi, port_mask.v32)
},
{ .name = "hmark-sport",
.type = XTTYPE_UINT16,
.id = O_HMARK_SPORT,
- .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.p16.src)
+ .flags = XTOPT_PUT | XTOPT_NBO, XTOPT_POINTER(hi, port_set.p16.src)
},
{ .name = "hmark-dport",
.type = XTTYPE_UINT16,
.id = O_HMARK_DPORT,
- .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.p16.dst)
+ .flags = XTOPT_PUT | XTOPT_NBO, XTOPT_POINTER(hi, port_set.p16.dst)
},
{ .name = "hmark-spi",
.type = XTTYPE_UINT32,
.id = O_HMARK_SPI,
- .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.v32)
+ .flags = XTOPT_PUT | XTOPT_NBO, XTOPT_POINTER(hi, port_set.v32)
},
{ .name = "hmark-proto-mask",
.type = XTTYPE_UINT16,
@@ -211,53 +212,10 @@ static void HMARK_parse(struct xt_option_call *cb, int plen)
case O_HMARK_TYPE:
hmark_parse_type(cb);
break;
- case O_HMARK_SADDR_MASK:
- info->flags |= XT_HMARK_FLAG(XT_HMARK_SADDR_MASK);
- break;
- case O_HMARK_DADDR_MASK:
- info->flags |= XT_HMARK_FLAG(XT_HMARK_DADDR_MASK);
- break;
- case O_HMARK_SPI:
- info->port_set.v32 = htonl(cb->val.u32);
- info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI);
- break;
- case O_HMARK_SPORT:
- info->port_set.p16.src = htons(cb->val.u16);
- info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT);
- break;
- case O_HMARK_DPORT:
- info->port_set.p16.dst = htons(cb->val.u16);
- info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT);
- break;
- case O_HMARK_SPORT_MASK:
- info->port_mask.p16.src = htons(cb->val.u16);
- info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT_MASK);
- break;
- case O_HMARK_DPORT_MASK:
- info->port_mask.p16.dst = htons(cb->val.u16);
- info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT_MASK);
- break;
- case O_HMARK_SPI_MASK:
- info->port_mask.v32 = htonl(cb->val.u32);
- info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI_MASK);
- break;
- case O_HMARK_PROTO_MASK:
- info->flags |= XT_HMARK_FLAG(XT_HMARK_PROTO_MASK);
- break;
- case O_HMARK_RND:
- info->flags |= XT_HMARK_FLAG(XT_HMARK_RND);
- break;
- case O_HMARK_MODULUS:
- info->flags |= XT_HMARK_FLAG(XT_HMARK_MODULUS);
- break;
- case O_HMARK_OFFSET:
- info->flags |= XT_HMARK_FLAG(XT_HMARK_OFFSET);
- break;
- case O_HMARK_CT:
- info->flags |= XT_HMARK_FLAG(XT_HMARK_CT);
+ default:
+ info->flags |= XT_HMARK_FLAG(cb->entry->id);
break;
}
- cb->xflags |= (1 << cb->entry->id);
}
static void HMARK_ip4_parse(struct xt_option_call *cb)
diff --git a/extensions/libxt_HMARK.man b/extensions/libxt_HMARK.man
index cd7ffd54..63d18cb5 100644
--- a/extensions/libxt_HMARK.man
+++ b/extensions/libxt_HMARK.man
@@ -53,7 +53,7 @@ A 32 bit random custom value to feed hash calculation.
\fIExamples:\fP
.PP
iptables \-t mangle \-A PREROUTING \-m conntrack \-\-ctstate NEW
- \-j HMARK \-\-hmark-tuple ct,src,dst,proto \-\-hmark-offset 10000
+ \-j HMARK \-\-hmark-tuple ct,src,dst,proto \-\-hmark\-offset 10000
\-\-hmark\-mod 10 \-\-hmark\-rnd 0xfeedcafe
.PP
iptables \-t mangle \-A PREROUTING \-j HMARK \-\-hmark\-offset 10000
diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t
index e8f306d2..3345d5be 100644
--- a/extensions/libxt_IDLETIMER.t
+++ b/extensions/libxt_IDLETIMER.t
@@ -2,4 +2,4 @@
-j IDLETIMER --timeout;;FAIL
-j IDLETIMER --timeout 42;;FAIL
-j IDLETIMER --timeout 42 --label foo;=;OK
--j IDLETIMER --timeout 42 --label foo --alarm;;OK
+-j IDLETIMER --timeout 42 --label bar --alarm;=;OK
diff --git a/extensions/libxt_LED.man b/extensions/libxt_LED.man
index 81c2f296..d92fd940 100644
--- a/extensions/libxt_LED.man
+++ b/extensions/libxt_LED.man
@@ -6,9 +6,9 @@ the trigger behavior:
.TP
\fB\-\-led\-trigger\-id\fP \fIname\fP
This is the name given to the LED trigger. The actual name of the trigger
-will be prefixed with "netfilter-".
+will be prefixed with "netfilter\-".
.TP
-\fB\-\-led-delay\fP \fIms\fP
+\fB\-\-led\-delay\fP \fIms\fP
This indicates how long (in milliseconds) the LED should be left illuminated
when a packet arrives before being switched off again. The default is 0
(blink as fast as possible.) The special value \fIinf\fP can be given to
diff --git a/extensions/libxt_LOG.c b/extensions/libxt_LOG.c
new file mode 100644
index 00000000..b6fe0b2e
--- /dev/null
+++ b/extensions/libxt_LOG.c
@@ -0,0 +1,204 @@
+#include <stdio.h>
+#include <string.h>
+#define SYSLOG_NAMES
+#include <syslog.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_LOG.h>
+
+#define LOG_DEFAULT_LEVEL LOG_WARNING
+
+enum {
+ /* make sure the values correspond with XT_LOG_* bit positions */
+ O_LOG_TCPSEQ = 0,
+ O_LOG_TCPOPTS,
+ O_LOG_IPOPTS,
+ O_LOG_UID,
+ __O_LOG_NFLOG,
+ O_LOG_MAC,
+ O_LOG_LEVEL,
+ O_LOG_PREFIX,
+};
+
+static void LOG_help(void)
+{
+ printf(
+"LOG target options:\n"
+" --log-level level Level of logging (numeric or see syslog.conf)\n"
+" --log-prefix prefix Prefix log messages with this prefix.\n"
+" --log-tcp-sequence Log TCP sequence numbers.\n"
+" --log-tcp-options Log TCP options.\n"
+" --log-ip-options Log IP options.\n"
+" --log-uid Log UID owning the local socket.\n"
+" --log-macdecode Decode MAC addresses and protocol.\n");
+}
+
+#define s struct xt_log_info
+static const struct xt_option_entry LOG_opts[] = {
+ {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL,
+ .flags = XTOPT_PUT, XTOPT_POINTER(s, level)},
+ {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING,
+ .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1},
+ {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE},
+ {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE},
+ {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE},
+ {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE},
+ {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+#undef s
+
+static void LOG_init(struct xt_entry_target *t)
+{
+ struct xt_log_info *loginfo = (void *)t->data;
+
+ loginfo->level = LOG_DEFAULT_LEVEL;
+}
+
+static void LOG_parse(struct xt_option_call *cb)
+{
+ struct xt_log_info *info = cb->data;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_LOG_PREFIX:
+ if (strchr(cb->arg, '\n') != NULL)
+ xtables_error(PARAMETER_PROBLEM,
+ "Newlines not allowed in --log-prefix");
+ break;
+ case O_LOG_TCPSEQ:
+ case O_LOG_TCPOPTS:
+ case O_LOG_IPOPTS:
+ case O_LOG_UID:
+ case O_LOG_MAC:
+ info->logflags |= 1 << cb->entry->id;
+ break;
+ }
+}
+
+static const char *priority2name(unsigned char level)
+{
+ int i;
+
+ for (i = 0; prioritynames[i].c_name; ++i) {
+ if (level == prioritynames[i].c_val)
+ return prioritynames[i].c_name;
+ }
+ return NULL;
+}
+
+static void LOG_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct xt_log_info *loginfo = (const void *)target->data;
+
+ printf(" LOG");
+ if (numeric)
+ printf(" flags %u level %u",
+ loginfo->logflags, loginfo->level);
+ else {
+ const char *pname = priority2name(loginfo->level);
+
+ if (pname)
+ printf(" level %s", pname);
+ else
+ printf(" UNKNOWN level %u", loginfo->level);
+ if (loginfo->logflags & XT_LOG_TCPSEQ)
+ printf(" tcp-sequence");
+ if (loginfo->logflags & XT_LOG_TCPOPT)
+ printf(" tcp-options");
+ if (loginfo->logflags & XT_LOG_IPOPT)
+ printf(" ip-options");
+ if (loginfo->logflags & XT_LOG_UID)
+ printf(" uid");
+ if (loginfo->logflags & XT_LOG_MACDECODE)
+ printf(" macdecode");
+ if (loginfo->logflags & ~(XT_LOG_MASK))
+ printf(" unknown-flags");
+ }
+
+ if (strcmp(loginfo->prefix, "") != 0)
+ printf(" prefix \"%s\"", loginfo->prefix);
+}
+
+static void LOG_save(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_log_info *loginfo = (const void *)target->data;
+
+ if (strcmp(loginfo->prefix, "") != 0) {
+ printf(" --log-prefix");
+ xtables_save_string(loginfo->prefix);
+ }
+
+ if (loginfo->level != LOG_DEFAULT_LEVEL)
+ printf(" --log-level %d", loginfo->level);
+
+ if (loginfo->logflags & XT_LOG_TCPSEQ)
+ printf(" --log-tcp-sequence");
+ if (loginfo->logflags & XT_LOG_TCPOPT)
+ printf(" --log-tcp-options");
+ if (loginfo->logflags & XT_LOG_IPOPT)
+ printf(" --log-ip-options");
+ if (loginfo->logflags & XT_LOG_UID)
+ printf(" --log-uid");
+ if (loginfo->logflags & XT_LOG_MACDECODE)
+ printf(" --log-macdecode");
+}
+
+static int LOG_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_log_info *loginfo = (const void *)params->target->data;
+ const char *pname = priority2name(loginfo->level);
+
+ xt_xlate_add(xl, "log");
+ if (strcmp(loginfo->prefix, "") != 0)
+ xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
+
+ if (loginfo->level != LOG_DEFAULT_LEVEL && pname)
+ xt_xlate_add(xl, " level %s", pname);
+ else if (!pname)
+ return 0;
+
+ if ((loginfo->logflags & XT_LOG_MASK) == XT_LOG_MASK) {
+ xt_xlate_add(xl, " flags all");
+ } else {
+ if (loginfo->logflags & (XT_LOG_TCPSEQ | XT_LOG_TCPOPT)) {
+ const char *delim = " ";
+
+ xt_xlate_add(xl, " flags tcp");
+ if (loginfo->logflags & XT_LOG_TCPSEQ) {
+ xt_xlate_add(xl, " sequence");
+ delim = ",";
+ }
+ if (loginfo->logflags & XT_LOG_TCPOPT)
+ xt_xlate_add(xl, "%soptions", delim);
+ }
+ if (loginfo->logflags & XT_LOG_IPOPT)
+ xt_xlate_add(xl, " flags ip options");
+ if (loginfo->logflags & XT_LOG_UID)
+ xt_xlate_add(xl, " flags skuid");
+ if (loginfo->logflags & XT_LOG_MACDECODE)
+ xt_xlate_add(xl, " flags ether");
+ }
+
+ return 1;
+}
+static struct xtables_target log_tg_reg = {
+ .name = "LOG",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_UNSPEC,
+ .size = XT_ALIGN(sizeof(struct xt_log_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_log_info)),
+ .help = LOG_help,
+ .init = LOG_init,
+ .print = LOG_print,
+ .save = LOG_save,
+ .x6_parse = LOG_parse,
+ .x6_options = LOG_opts,
+ .xlate = LOG_xlate,
+};
+
+void _init(void)
+{
+ xtables_register_target(&log_tg_reg);
+}
diff --git a/extensions/libxt_LOG.man b/extensions/libxt_LOG.man
index 354edf4c..1d5071ba 100644
--- a/extensions/libxt_LOG.man
+++ b/extensions/libxt_LOG.man
@@ -30,3 +30,6 @@ Log options from the IP/IPv6 packet header.
.TP
\fB\-\-log\-uid\fP
Log the userid of the process which generated the packet.
+.TP
+\fB\-\-log\-macdecode\fP
+Log MAC addresses and protocol.
diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c
index b765af6c..703d894f 100644
--- a/extensions/libxt_MARK.c
+++ b/extensions/libxt_MARK.c
@@ -1,4 +1,3 @@
-#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <xtables.h>
@@ -69,6 +68,16 @@ static const struct xt_option_entry mark_tg_opts[] = {
XTOPT_TABLEEND,
};
+static const struct xt_option_entry mark_tg_arp_opts[] = {
+ {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_UINT32,
+ .base = 16, .excl = F_ANY},
+ {.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32,
+ .base = 16, .excl = F_ANY},
+ {.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32,
+ .base = 16, .excl = F_ANY},
+ XTOPT_TABLEEND,
+};
+
static void mark_tg_help(void)
{
printf(
@@ -77,8 +86,7 @@ static void mark_tg_help(void)
" --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n"
" --and-mark bits Binary AND the nfmark with bits\n"
" --or-mark bits Binary OR the nfmark with bits\n"
-" --xor-mark bits Binary XOR the nfmark with bits\n"
-"\n");
+" --xor-mark bits Binary XOR the nfmark with bits\n");
}
static void MARK_parse_v0(struct xt_option_call *cb)
@@ -137,6 +145,8 @@ static void mark_tg_parse(struct xt_option_call *cb)
case O_SET_MARK:
info->mark = cb->val.mark;
info->mask = cb->val.mark | cb->val.mask;
+ if (cb->entry->type == XTTYPE_UINT32)
+ info->mask = UINT32_MAX;
break;
case O_AND_MARK:
info->mark = 0;
@@ -264,69 +274,6 @@ static void mark_tg_arp_print(const void *ip,
mark_tg_arp_save(ip, target);
}
-#define MARK_OPT 1
-#define AND_MARK_OPT 2
-#define OR_MARK_OPT 3
-
-static struct option mark_tg_arp_opts[] = {
- { .name = "set-mark", .has_arg = required_argument, .flag = 0, .val = MARK_OPT },
- { .name = "and-mark", .has_arg = required_argument, .flag = 0, .val = AND_MARK_OPT },
- { .name = "or-mark", .has_arg = required_argument, .flag = 0, .val = OR_MARK_OPT },
- { .name = NULL}
-};
-
-static int
-mark_tg_arp_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
-{
- struct xt_mark_tginfo2 *info =
- (struct xt_mark_tginfo2 *)(*target)->data;
- int i;
-
- switch (c) {
- case MARK_OPT:
- if (sscanf(argv[optind-1], "%x", &i) != 1) {
- xtables_error(PARAMETER_PROBLEM,
- "Bad mark value `%s'", optarg);
- return 0;
- }
- info->mark = i;
- if (*flags)
- xtables_error(PARAMETER_PROBLEM,
- "MARK: Can't specify --set-mark twice");
- *flags = 1;
- break;
- case AND_MARK_OPT:
- if (sscanf(argv[optind-1], "%x", &i) != 1) {
- xtables_error(PARAMETER_PROBLEM,
- "Bad mark value `%s'", optarg);
- return 0;
- }
- info->mark = 0;
- info->mask = ~i;
- if (*flags)
- xtables_error(PARAMETER_PROBLEM,
- "MARK: Can't specify --and-mark twice");
- *flags = 1;
- break;
- case OR_MARK_OPT:
- if (sscanf(argv[optind-1], "%x", &i) != 1) {
- xtables_error(PARAMETER_PROBLEM,
- "Bad mark value `%s'", optarg);
- return 0;
- }
- info->mark = info->mask = i;
- if (*flags)
- xtables_error(PARAMETER_PROBLEM,
- "MARK: Can't specify --or-mark twice");
- *flags = 1;
- break;
- default:
- return 0;
- }
- return 1;
-}
-
static int mark_tg_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
@@ -367,6 +314,8 @@ static int MARK_xlate(struct xt_xlate *xl,
case XT_MARK_OR:
xt_xlate_add(xl, "mark or 0x%x ", (uint32_t)markinfo->mark);
break;
+ default:
+ return 0;
}
return 1;
@@ -427,8 +376,10 @@ static struct xtables_target mark_tg_reg[] = {
.help = mark_tg_help,
.print = mark_tg_arp_print,
.save = mark_tg_arp_save,
- .parse = mark_tg_arp_parse,
- .extra_opts = mark_tg_arp_opts,
+ .x6_parse = mark_tg_parse,
+ .x6_fcheck = mark_tg_check,
+ .x6_options = mark_tg_arp_opts,
+ .xlate = mark_tg_xlate,
},
};
diff --git a/extensions/libxt_MARK.t b/extensions/libxt_MARK.t
index 9d1aa7d7..ae026dbb 100644
--- a/extensions/libxt_MARK.t
+++ b/extensions/libxt_MARK.t
@@ -1,7 +1,7 @@
:INPUT,FORWARD,OUTPUT
-j MARK --set-xmark 0xfeedcafe/0xfeedcafe;=;OK
--j MARK --set-xmark 0;=;OK
--j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff;OK
+-j MARK --set-xmark 0x0;-j MARK --set-xmark 0x0/0xffffffff;OK
+-j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff/0xffffffff;OK
-j MARK --set-xmark 4294967296;;FAIL
-j MARK --set-xmark -1;;FAIL
-j MARK;;FAIL
diff --git a/extensions/libxt_MARK.txlate b/extensions/libxt_MARK.txlate
index d3250ab6..cef8239a 100644
--- a/extensions/libxt_MARK.txlate
+++ b/extensions/libxt_MARK.txlate
@@ -1,26 +1,35 @@
iptables-translate -t mangle -A OUTPUT -j MARK --set-mark 0
-nft add rule ip mangle OUTPUT counter meta mark set 0x0
+nft 'add rule ip mangle OUTPUT counter meta mark set 0x0'
iptables-translate -t mangle -A OUTPUT -j MARK --set-mark 64
-nft add rule ip mangle OUTPUT counter meta mark set 0x40
+nft 'add rule ip mangle OUTPUT counter meta mark set 0x40'
iptables-translate -t mangle -A OUTPUT -j MARK --set-xmark 0x40/0x32
-nft add rule ip mangle OUTPUT counter meta mark set mark and 0xffffffcd xor 0x40
+nft 'add rule ip mangle OUTPUT counter meta mark set mark and 0xffffffcd xor 0x40'
iptables-translate -t mangle -A OUTPUT -j MARK --or-mark 64
-nft add rule ip mangle OUTPUT counter meta mark set mark or 0x40
+nft 'add rule ip mangle OUTPUT counter meta mark set mark or 0x40'
iptables-translate -t mangle -A OUTPUT -j MARK --and-mark 64
-nft add rule ip mangle OUTPUT counter meta mark set mark and 0x40
+nft 'add rule ip mangle OUTPUT counter meta mark set mark and 0x40'
iptables-translate -t mangle -A OUTPUT -j MARK --xor-mark 64
-nft add rule ip mangle OUTPUT counter meta mark set mark xor 0x40
+nft 'add rule ip mangle OUTPUT counter meta mark set mark xor 0x40'
iptables-translate -t mangle -A PREROUTING -j MARK --set-mark 0x64
-nft add rule ip mangle PREROUTING counter meta mark set 0x64
+nft 'add rule ip mangle PREROUTING counter meta mark set 0x64'
iptables-translate -t mangle -A PREROUTING -j MARK --and-mark 0x64
-nft add rule ip mangle PREROUTING counter meta mark set mark and 0x64
+nft 'add rule ip mangle PREROUTING counter meta mark set mark and 0x64'
iptables-translate -t mangle -A PREROUTING -j MARK --or-mark 0x64
-nft add rule ip mangle PREROUTING counter meta mark set mark or 0x64
+nft 'add rule ip mangle PREROUTING counter meta mark set mark or 0x64'
+
+arptables-translate -A OUTPUT -j MARK --set-mark 0x4
+nft 'add rule arp filter OUTPUT arp htype 1 arp hlen 6 arp plen 4 counter meta mark set 0x4'
+
+arptables-translate -I OUTPUT -o odev -j MARK --and-mark 0x8
+nft 'insert rule arp filter OUTPUT oifname "odev" arp htype 1 arp hlen 6 arp plen 4 counter meta mark set mark and 0x8'
+
+arptables-translate -t mangle -A OUTPUT -o odev -j MARK --or-mark 16
+nft 'add rule arp mangle OUTPUT oifname "odev" arp htype 1 arp hlen 6 arp plen 4 counter meta mark set mark or 0x16'
diff --git a/extensions/libxt_MASQUERADE.man b/extensions/libxt_MASQUERADE.man
index 7746f473..5c236447 100644
--- a/extensions/libxt_MASQUERADE.man
+++ b/extensions/libxt_MASQUERADE.man
@@ -15,21 +15,15 @@ any established connections are lost anyway).
\fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP]
This specifies a range of source ports to use, overriding the default
.B SNAT
-source port-selection heuristics (see above). This is only valid
+source port selection heuristics (see above). This is only valid
if the rule also specifies one of the following protocols:
\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP.
.TP
\fB\-\-random\fP
-Randomize source port mapping
-If option
-\fB\-\-random\fP
-is used then port mapping will be randomized (kernel >= 2.6.21).
-Since kernel 5.0, \fB\-\-random\fP is identical to \fB\-\-random-fully\fP.
+Randomize source port mapping (kernel >= 2.6.21).
+Since kernel 5.0, \fB\-\-random\fP is identical to \fB\-\-random\-fully\fP.
.TP
-\fB\-\-random-fully\fP
-Full randomize source port mapping
-If option
-\fB\-\-random-fully\fP
-is used then port mapping will be fully randomized (kernel >= 3.13).
+\fB\-\-random\-fully\fP
+Fully randomize source port mapping (kernel >= 3.13).
.TP
IPv6 support available since Linux kernels >= 3.7.
diff --git a/extensions/libxt_NAT.c b/extensions/libxt_NAT.c
new file mode 100644
index 00000000..2a634398
--- /dev/null
+++ b/extensions/libxt_NAT.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
+ *
+ * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT
+ * funded by Astaro.
+ */
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xtables.h>
+#include <iptables.h> /* get_kernel_version */
+#include <limits.h> /* INT_MAX in ip_tables.h */
+#include <arpa/inet.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/nf_nat.h>
+
+#define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr))
+#define RANGE2_INIT_FROM_IPV4_MRC(ptr) { \
+ .flags = TO_IPV4_MRC(ptr)->range[0].flags, \
+ .min_addr.ip = TO_IPV4_MRC(ptr)->range[0].min_ip, \
+ .max_addr.ip = TO_IPV4_MRC(ptr)->range[0].max_ip, \
+ .min_proto = TO_IPV4_MRC(ptr)->range[0].min, \
+ .max_proto = TO_IPV4_MRC(ptr)->range[0].max, \
+};
+#define TO_NF_NAT_RANGE(ptr) ((const struct nf_nat_range *)(ptr))
+#define RANGE2_INIT_FROM_RANGE(ptr) { \
+ .flags = TO_NF_NAT_RANGE(ptr)->flags, \
+ .min_addr = TO_NF_NAT_RANGE(ptr)->min_addr, \
+ .max_addr = TO_NF_NAT_RANGE(ptr)->max_addr, \
+ .min_proto = TO_NF_NAT_RANGE(ptr)->min_proto, \
+ .max_proto = TO_NF_NAT_RANGE(ptr)->max_proto, \
+};
+
+enum {
+ O_TO_DEST = 0,
+ O_TO_SRC,
+ O_TO_PORTS,
+ O_RANDOM,
+ O_RANDOM_FULLY,
+ O_PERSISTENT,
+};
+
+static void SNAT_help(void)
+{
+ printf(
+"SNAT target options:\n"
+" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
+" Address to map source to.\n"
+"[--random] [--random-fully] [--persistent]\n");
+}
+
+static void MASQUERADE_help(void)
+{
+ printf(
+"MASQUERADE target options:\n"
+" --to-ports <port>[-<port>]\n"
+" Port (range) to map to.\n"
+" --random\n"
+" Randomize source port.\n"
+" --random-fully\n"
+" Fully randomize source port.\n");
+}
+
+static void DNAT_help(void)
+{
+ printf(
+"DNAT target options:\n"
+" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
+" Address to map destination to.\n"
+"[--random] [--persistent]\n");
+}
+
+static void DNAT_help_v2(void)
+{
+ printf(
+"DNAT target options:\n"
+" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
+" Address to map destination to.\n"
+"[--random] [--persistent]\n");
+}
+
+static void REDIRECT_help(void)
+{
+ printf(
+"REDIRECT target options:\n"
+" --to-ports <port>[-<port>]\n"
+" Port (range) to map to.\n"
+" [--random]\n");
+}
+
+static const struct xt_option_entry SNAT_opts[] = {
+ {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND},
+ {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
+ {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+
+static const struct xt_option_entry MASQUERADE_opts[] = {
+ {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
+ {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+
+static const struct xt_option_entry DNAT_opts[] = {
+ {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND},
+ {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+
+static const struct xt_option_entry REDIRECT_opts[] = {
+ {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
+ {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+
+/* Parses ports */
+static void
+parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range)
+{
+ unsigned int port, maxport, baseport;
+ char *end = NULL;
+
+ if (!portok)
+ xtables_error(PARAMETER_PROBLEM,
+ "Need TCP, UDP, SCTP or DCCP with port specification");
+
+ range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
+
+ if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) {
+ port = xtables_service_to_port(arg, NULL);
+ if (port == (unsigned)-1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid", arg);
+ end = "";
+ }
+
+ switch (*end) {
+ case '\0':
+ range->min_proto.tcp.port
+ = range->max_proto.tcp.port
+ = htons(port);
+ return;
+ case '-':
+ arg = end + 1;
+ break;
+ case ':':
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid port:port syntax - use dash");
+ default:
+ xtables_error(PARAMETER_PROBLEM,
+ "Garbage after port value: `%s'", end);
+ }
+
+ /* it is a range, don't allow service names here */
+ if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX))
+ xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg);
+
+ if (maxport < port)
+ /* People are stupid. */
+ xtables_error(PARAMETER_PROBLEM,
+ "Port range `%s' funky", arg);
+
+ range->min_proto.tcp.port = htons(port);
+ range->max_proto.tcp.port = htons(maxport);
+
+ switch (*end) {
+ case '\0':
+ return;
+ case '/':
+ arg = end + 1;
+ break;
+ default:
+ xtables_error(PARAMETER_PROBLEM,
+ "Garbage after port range: `%s'", end);
+ }
+
+ if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) {
+ baseport = xtables_service_to_port(arg, NULL);
+ if (baseport == (unsigned)-1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid", arg);
+ }
+
+ range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
+ range->base_proto.tcp.port = htons(baseport);
+}
+
+/* Ranges expected in network order. */
+static void
+parse_to(const char *orig_arg, bool portok,
+ struct nf_nat_range2 *range, int family)
+{
+ char *arg, *start, *end, *colon, *dash;
+
+ arg = xtables_strdup(orig_arg);
+ start = strchr(arg, '[');
+ if (!start) {
+ start = arg;
+ /* Lets assume one colon is port information.
+ * Otherwise its an IPv6 address */
+ colon = strchr(arg, ':');
+ if (colon && strchr(colon + 1, ':'))
+ colon = NULL;
+ } else {
+ start++;
+ end = strchr(start, ']');
+ if (end == NULL || family == AF_INET)
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid address format");
+
+ *end = '\0';
+ colon = strchr(end + 1, ':');
+ }
+
+ if (colon) {
+ parse_ports(colon + 1, portok, range);
+
+ /* Starts with colon or [] colon? No IP info...*/
+ if (colon == arg || colon == arg + 2) {
+ free(arg);
+ return;
+ }
+ *colon = '\0';
+ }
+
+ range->flags |= NF_NAT_RANGE_MAP_IPS;
+ dash = strchr(start, '-');
+ if (colon && dash && dash > colon)
+ dash = NULL;
+
+ if (dash)
+ *dash = '\0';
+
+ if (!inet_pton(family, start, &range->min_addr))
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad IP address \"%s\"", start);
+ if (dash) {
+ if (!inet_pton(family, dash + 1, &range->max_addr))
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad IP address \"%s\"", dash + 1);
+ } else {
+ range->max_addr = range->min_addr;
+ }
+ free(arg);
+ return;
+}
+
+static void __NAT_parse(struct xt_option_call *cb, __u16 proto,
+ struct nf_nat_range2 *range, int family)
+{
+ bool portok = proto == IPPROTO_TCP ||
+ proto == IPPROTO_UDP ||
+ proto == IPPROTO_SCTP ||
+ proto == IPPROTO_DCCP ||
+ proto == IPPROTO_ICMP;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_TO_DEST:
+ case O_TO_SRC:
+ parse_to(cb->arg, portok, range, family);
+ break;
+ case O_TO_PORTS:
+ parse_ports(cb->arg, portok, range);
+ break;
+ case O_PERSISTENT:
+ range->flags |= NF_NAT_RANGE_PERSISTENT;
+ break;
+ case O_RANDOM:
+ range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
+ break;
+ case O_RANDOM_FULLY:
+ range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
+ break;
+ }
+}
+
+static void NAT_parse(struct xt_option_call *cb)
+{
+ struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data;
+ const struct ipt_entry *entry = cb->xt_entry;
+ struct nf_nat_range2 range = {};
+
+ __NAT_parse(cb, entry->ip.proto, &range, AF_INET);
+
+ switch (cb->entry->id) {
+ case O_TO_DEST:
+ case O_TO_SRC:
+ mr->range->min_ip = range.min_addr.ip;
+ mr->range->max_ip = range.max_addr.ip;
+ /* fall through */
+ case O_TO_PORTS:
+ mr->range->min = range.min_proto;
+ mr->range->max = range.max_proto;
+ /* fall through */
+ case O_PERSISTENT:
+ case O_RANDOM:
+ case O_RANDOM_FULLY:
+ mr->range->flags |= range.flags;
+ break;
+ }
+}
+
+static void NAT_parse6(struct xt_option_call *cb)
+{
+ struct nf_nat_range2 range = RANGE2_INIT_FROM_RANGE(cb->data);
+ struct nf_nat_range *range_v1 = (void *)cb->data;
+ const struct ip6t_entry *entry = cb->xt_entry;
+
+ __NAT_parse(cb, entry->ipv6.proto, &range, AF_INET6);
+ memcpy(range_v1, &range, sizeof(*range_v1));
+}
+
+static void DNAT_parse_v2(struct xt_option_call *cb)
+{
+ const struct ipt_entry *entry = cb->xt_entry;
+
+ __NAT_parse(cb, entry->ip.proto, cb->data, AF_INET);
+}
+
+static void DNAT_parse6_v2(struct xt_option_call *cb)
+{
+ const struct ip6t_entry *entry = cb->xt_entry;
+
+ __NAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6);
+}
+
+static void SNAT_fcheck(struct xt_fcheck_call *cb)
+{
+ struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
+
+ mr->rangesize = 1;
+}
+
+static void DNAT_fcheck(struct xt_fcheck_call *cb)
+{
+ struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
+
+ mr->rangesize = 1;
+
+ if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET)
+ xtables_error(PARAMETER_PROBLEM,
+ "Shifted portmap ranges not supported with this kernel");
+}
+
+static void DNAT_fcheck6(struct xt_fcheck_call *cb)
+{
+ struct nf_nat_range *range = (void *)cb->data;
+
+ if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
+ xtables_error(PARAMETER_PROBLEM,
+ "Shifted portmap ranges not supported with this kernel");
+}
+
+static char *sprint_range(const struct nf_nat_range2 *r, int family)
+{
+ bool brackets = family == AF_INET6 &&
+ r->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
+ static char buf[INET6_ADDRSTRLEN * 2 + 3 + 6 * 3];
+
+ buf[0] = '\0';
+
+ if (r->flags & NF_NAT_RANGE_MAP_IPS) {
+ if (brackets)
+ strcat(buf, "[");
+ inet_ntop(family, &r->min_addr,
+ buf + strlen(buf), INET6_ADDRSTRLEN);
+ if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) {
+ strcat(buf, "-");
+ inet_ntop(family, &r->max_addr,
+ buf + strlen(buf), INET6_ADDRSTRLEN);
+ }
+ if (brackets)
+ strcat(buf, "]");
+ }
+ if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ sprintf(buf + strlen(buf), ":%hu",
+ ntohs(r->min_proto.tcp.port));
+ if (r->max_proto.tcp.port != r->min_proto.tcp.port)
+ sprintf(buf + strlen(buf), "-%hu",
+ ntohs(r->max_proto.tcp.port));
+ if (r->flags & NF_NAT_RANGE_PROTO_OFFSET)
+ sprintf(buf + strlen(buf), "/%hu",
+ ntohs(r->base_proto.tcp.port));
+ }
+ return buf;
+}
+
+static void __NAT_print(const struct nf_nat_range2 *r, int family,
+ const char *rangeopt, const char *flag_pfx,
+ bool skip_colon)
+{
+ char *range_str = sprint_range(r, family);
+
+ if (strlen(range_str)) {
+ if (range_str[0] == ':' && skip_colon)
+ range_str++;
+ printf(" %s%s", rangeopt, range_str);
+ }
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ printf(" %srandom", flag_pfx);
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ printf(" %srandom-fully", flag_pfx);
+ if (r->flags & NF_NAT_RANGE_PERSISTENT)
+ printf(" %spersistent", flag_pfx);
+}
+
+static int
+__NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r,
+ int family, const char *tgt)
+{
+ char *range_str = sprint_range(r, family);
+ const char *sep = " ";
+
+ /* shifted portmap ranges are not supported by nftables */
+ if (r->flags & NF_NAT_RANGE_PROTO_OFFSET)
+ return 0;
+
+ xt_xlate_add(xl, "%s", tgt);
+ if (strlen(range_str))
+ xt_xlate_add(xl, " to %s", range_str);
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, "%srandom", sep);
+ sep = ",";
+ }
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+ xt_xlate_add(xl, "%sfully-random", sep);
+ sep = ",";
+ }
+ if (r->flags & NF_NAT_RANGE_PERSISTENT) {
+ xt_xlate_add(xl, "%spersistent", sep);
+ sep = ",";
+ }
+ return 1;
+}
+
+#define PSX_GEN(name, converter, family, \
+ print_rangeopt, save_rangeopt, skip_colon, xlate) \
+static void name##_print(const void *ip, const struct xt_entry_target *target, \
+ int numeric) \
+{ \
+ struct nf_nat_range2 range = converter(target->data); \
+ \
+ __NAT_print(&range, family, print_rangeopt, "", skip_colon); \
+} \
+static void name##_save(const void *ip, const struct xt_entry_target *target) \
+{ \
+ struct nf_nat_range2 range = converter(target->data); \
+ \
+ __NAT_print(&range, family, save_rangeopt, "--", skip_colon); \
+} \
+static int name##_xlate(struct xt_xlate *xl, \
+ const struct xt_xlate_tg_params *params) \
+{ \
+ struct nf_nat_range2 range = converter(params->target->data); \
+ \
+ return __NAT_xlate(xl, &range, family, xlate); \
+}
+
+PSX_GEN(DNAT, RANGE2_INIT_FROM_IPV4_MRC, \
+ AF_INET, "to:", "--to-destination ", false, "dnat")
+
+PSX_GEN(DNATv2, *(struct nf_nat_range2 *), \
+ AF_INET, "to:", "--to-destination ", false, "dnat")
+
+PSX_GEN(DNAT6, RANGE2_INIT_FROM_RANGE, \
+ AF_INET6, "to:", "--to-destination ", false, "dnat")
+
+PSX_GEN(DNAT6v2, *(struct nf_nat_range2 *), \
+ AF_INET6, "to:", "--to-destination ", false, "dnat")
+
+PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \
+ AF_INET, "redir ports ", "--to-ports ", true, "redirect")
+
+PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \
+ AF_INET6, "redir ports ", "--to-ports ", true, "redirect")
+
+PSX_GEN(SNAT, RANGE2_INIT_FROM_IPV4_MRC, \
+ AF_INET, "to:", "--to-source ", false, "snat")
+
+PSX_GEN(SNAT6, RANGE2_INIT_FROM_RANGE, \
+ AF_INET6, "to:", "--to-source ", false, "snat")
+
+PSX_GEN(MASQUERADE, RANGE2_INIT_FROM_IPV4_MRC, \
+ AF_INET, "masq ports: ", "--to-ports ", true, "masquerade")
+
+PSX_GEN(MASQUERADE6, RANGE2_INIT_FROM_RANGE, \
+ AF_INET6, "masq ports: ", "--to-ports ", true, "masquerade")
+
+static struct xtables_target nat_tg_reg[] = {
+ {
+ .name = "SNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .help = SNAT_help,
+ .x6_parse = NAT_parse,
+ .x6_fcheck = SNAT_fcheck,
+ .print = SNAT_print,
+ .save = SNAT_save,
+ .x6_options = SNAT_opts,
+ .xlate = SNAT_xlate,
+ },
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .help = DNAT_help,
+ .print = DNAT_print,
+ .save = DNAT_save,
+ .x6_parse = NAT_parse,
+ .x6_fcheck = DNAT_fcheck,
+ .x6_options = DNAT_opts,
+ .xlate = DNAT_xlate,
+ },
+ {
+ .name = "MASQUERADE",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .help = MASQUERADE_help,
+ .x6_parse = NAT_parse,
+ .x6_fcheck = SNAT_fcheck,
+ .print = MASQUERADE_print,
+ .save = MASQUERADE_save,
+ .x6_options = MASQUERADE_opts,
+ .xlate = MASQUERADE_xlate,
+ },
+ {
+ .name = "MASQUERADE",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .help = MASQUERADE_help,
+ .x6_parse = NAT_parse6,
+ .print = MASQUERADE6_print,
+ .save = MASQUERADE6_save,
+ .x6_options = MASQUERADE_opts,
+ .xlate = MASQUERADE6_xlate,
+ },
+ {
+ .name = "REDIRECT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
+ .help = REDIRECT_help,
+ .print = REDIRECT_print,
+ .save = REDIRECT_save,
+ .x6_parse = NAT_parse,
+ .x6_fcheck = DNAT_fcheck,
+ .x6_options = REDIRECT_opts,
+ .xlate = REDIRECT_xlate,
+ },
+ {
+ .name = "SNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .help = SNAT_help,
+ .x6_parse = NAT_parse6,
+ .print = SNAT6_print,
+ .save = SNAT6_save,
+ .x6_options = SNAT_opts,
+ .xlate = SNAT6_xlate,
+ },
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .help = DNAT_help,
+ .print = DNAT6_print,
+ .save = DNAT6_save,
+ .x6_parse = NAT_parse6,
+ .x6_fcheck = DNAT_fcheck6,
+ .x6_options = DNAT_opts,
+ .xlate = DNAT6_xlate,
+ },
+ {
+ .name = "REDIRECT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
+ .help = REDIRECT_help,
+ .print = REDIRECT6_print,
+ .save = REDIRECT6_save,
+ .x6_parse = NAT_parse6,
+ .x6_fcheck = DNAT_fcheck6,
+ .x6_options = REDIRECT_opts,
+ .xlate = REDIRECT6_xlate,
+ },
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV4,
+ .revision = 2,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .help = DNAT_help_v2,
+ .print = DNATv2_print,
+ .save = DNATv2_save,
+ .x6_parse = DNAT_parse_v2,
+ .x6_options = DNAT_opts,
+ .xlate = DNATv2_xlate,
+ },
+ {
+ .name = "DNAT",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_IPV6,
+ .revision = 2,
+ .size = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range2)),
+ .help = DNAT_help_v2,
+ .print = DNAT6v2_print,
+ .save = DNAT6v2_save,
+ .x6_parse = DNAT_parse6_v2,
+ .x6_options = DNAT_opts,
+ .xlate = DNAT6v2_xlate,
+ },
+};
+
+void _init(void)
+{
+ xtables_register_targets(nat_tg_reg, ARRAY_SIZE(nat_tg_reg));
+}
diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c
index 02a1b4aa..d12ef044 100644
--- a/extensions/libxt_NFLOG.c
+++ b/extensions/libxt_NFLOG.c
@@ -5,6 +5,7 @@
#include <getopt.h>
#include <xtables.h>
+#include <linux/netfilter/nf_log.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_NFLOG.h>
@@ -53,12 +54,16 @@ static void NFLOG_init(struct xt_entry_target *t)
static void NFLOG_parse(struct xt_option_call *cb)
{
+ char *nf_log_prefix = cb->udata;
+
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_PREFIX:
if (strchr(cb->arg, '\n') != NULL)
xtables_error(PARAMETER_PROBLEM,
"Newlines not allowed in --log-prefix");
+
+ snprintf(nf_log_prefix, NF_LOG_PREFIXLEN, "%s", cb->arg);
break;
}
}
@@ -69,7 +74,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb)
if (cb->xflags & F_RANGE)
fprintf(stderr, "warn: --nflog-range has never worked and is no"
- " longer supported, please use --nflog-size insted\n");
+ " longer supported, please use --nflog-size instead\n");
if (cb->xflags & F_SIZE)
info->flags |= XT_NFLOG_F_COPY_LEN;
@@ -78,7 +83,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb)
static void nflog_print(const struct xt_nflog_info *info, char *prefix)
{
if (info->prefix[0] != '\0') {
- printf(" %snflog-prefix ", prefix);
+ printf(" %snflog-prefix", prefix);
xtables_save_string(info->prefix);
}
if (info->group)
@@ -107,16 +112,12 @@ static void NFLOG_save(const void *ip, const struct xt_entry_target *target)
}
static void nflog_print_xlate(const struct xt_nflog_info *info,
- struct xt_xlate *xl, bool escape_quotes)
+ struct xt_xlate *xl)
{
xt_xlate_add(xl, "log ");
- if (info->prefix[0] != '\0') {
- if (escape_quotes)
- xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix);
- else
- xt_xlate_add(xl, "prefix \"%s\" ", info->prefix);
+ if (info->prefix[0] != '\0')
+ xt_xlate_add(xl, "prefix \"%s\" ", info->prefix);
- }
if (info->flags & XT_NFLOG_F_COPY_LEN)
xt_xlate_add(xl, "snaplen %u ", info->len);
if (info->threshold != XT_NFLOG_DEFAULT_THRESHOLD)
@@ -130,7 +131,7 @@ static int NFLOG_xlate(struct xt_xlate *xl,
const struct xt_nflog_info *info =
(struct xt_nflog_info *)params->target->data;
- nflog_print_xlate(info, xl, params->escape_quotes);
+ nflog_print_xlate(info, xl);
return 1;
}
@@ -149,6 +150,7 @@ static struct xtables_target nflog_target = {
.save = NFLOG_save,
.x6_options = NFLOG_opts,
.xlate = NFLOG_xlate,
+ .udata_size = NF_LOG_PREFIXLEN
};
void _init(void)
diff --git a/extensions/libxt_NFLOG.man b/extensions/libxt_NFLOG.man
index 318e6305..86ebb210 100644
--- a/extensions/libxt_NFLOG.man
+++ b/extensions/libxt_NFLOG.man
@@ -9,7 +9,7 @@ may subscribe to the group to receive the packets. Like LOG, this is a
non-terminating target, i.e. rule traversal continues at the next rule.
.TP
\fB\-\-nflog\-group\fP \fInlgroup\fP
-The netlink group (0 - 2^16\-1) to which packets are (only applicable for
+The netlink group (0\(en2\(ha16\-1) to which packets are (only applicable for
nfnetlink_log). The default value is 0.
.TP
\fB\-\-nflog\-prefix\fP \fIprefix\fP
@@ -17,7 +17,7 @@ A prefix string to include in the log message, up to 64 characters
long, useful for distinguishing messages in the logs.
.TP
\fB\-\-nflog\-range\fP \fIsize\fP
-This option has never worked, use --nflog-size instead
+This option has never worked, use \-\-nflog\-size instead
.TP
\fB\-\-nflog\-size\fP \fIsize\fP
The number of bytes to be copied to userspace (only applicable for
diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t
index 933fa221..0cd81c64 100644
--- a/extensions/libxt_NFLOG.t
+++ b/extensions/libxt_NFLOG.t
@@ -3,8 +3,10 @@
-j NFLOG --nflog-group 65535;=;OK
-j NFLOG --nflog-group 65536;;FAIL
-j NFLOG --nflog-group 0;-j NFLOG;OK
--j NFLOG --nflog-range 1;=;OK
--j NFLOG --nflog-range 4294967295;=;OK
+# `--nflog-range` is broken and only supported by xtables-legacy.
+# It has been superseded by `--nflog--group`.
+-j NFLOG --nflog-range 1;=;OK;LEGACY;NOMATCH
+-j NFLOG --nflog-range 4294967295;=;OK;LEGACY;NOMATCH
-j NFLOG --nflog-range 4294967296;;FAIL
-j NFLOG --nflog-range -1;;FAIL
-j NFLOG --nflog-size 0;=;OK
@@ -12,10 +14,8 @@
-j NFLOG --nflog-size 4294967295;=;OK
-j NFLOG --nflog-size 4294967296;;FAIL
-j NFLOG --nflog-size -1;;FAIL
-# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...]
-# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
-# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...]
-# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK;LEGACY;=
-j NFLOG --nflog-threshold 1;=;OK
# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0
# -j NFLOG --nflog-threshold 0;;FAIL
diff --git a/extensions/libxt_NFLOG.txlate b/extensions/libxt_NFLOG.txlate
index a0872c9e..ebd81be3 100644
--- a/extensions/libxt_NFLOG.txlate
+++ b/extensions/libxt_NFLOG.txlate
@@ -1,14 +1,14 @@
iptables-translate -A FORWARD -j NFLOG --nflog-group 32 --nflog-prefix "Prefix 1.0"
-nft add rule ip filter FORWARD counter log prefix \"Prefix 1.0\" group 32
+nft 'add rule ip filter FORWARD counter log prefix "Prefix 1.0" group 32'
iptables-translate -A OUTPUT -j NFLOG --nflog-group 30
-nft add rule ip filter OUTPUT counter log group 30
+nft 'add rule ip filter OUTPUT counter log group 30'
iptables-translate -I INPUT -j NFLOG --nflog-threshold 2
-nft insert rule ip filter INPUT counter log queue-threshold 2 group 0
+nft 'insert rule ip filter INPUT counter log queue-threshold 2 group 0'
iptables-translate -I INPUT -j NFLOG --nflog-size 256
-nft insert rule ip filter INPUT counter log snaplen 256 group 0
+nft 'insert rule ip filter INPUT counter log snaplen 256 group 0'
iptables-translate -I INPUT -j NFLOG --nflog-threshold 25
-nft insert rule ip filter INPUT counter log queue-threshold 25 group 0
+nft 'insert rule ip filter INPUT counter log queue-threshold 25 group 0'
diff --git a/extensions/libxt_NFQUEUE.c b/extensions/libxt_NFQUEUE.c
index fe519078..ca6cdaf4 100644
--- a/extensions/libxt_NFQUEUE.c
+++ b/extensions/libxt_NFQUEUE.c
@@ -64,7 +64,7 @@ static const struct xt_option_entry NFQUEUE_opts[] = {
{.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16,
.flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum),
.excl = F_QUEUE_BALANCE},
- {.name = "queue-balance", .id = O_QUEUE_BALANCE,
+ {.name = "queue-balance", .id = O_QUEUE_BALANCE, .max = UINT16_MAX - 1,
.type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM},
{.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE},
{.name = "queue-cpu-fanout", .id = O_QUEUE_CPU_FANOUT,
diff --git a/extensions/libxt_NFQUEUE.man b/extensions/libxt_NFQUEUE.man
index 1bfb7b84..cb963bec 100644
--- a/extensions/libxt_NFQUEUE.man
+++ b/extensions/libxt_NFQUEUE.man
@@ -6,8 +6,9 @@ reinject the packet into the kernel. Please see libnetfilter_queue
for details.
.B
nfnetlink_queue
-was added in Linux 2.6.14. The \fBqueue-balance\fP option was added in Linux 2.6.31,
-\fBqueue-bypass\fP in 2.6.39.
+was added in Linux 2.6.14. The \fBqueue\-balance\fP option was added in Linux
+2.6.31,
+\fBqueue\-bypass\fP in 2.6.39.
.TP
\fB\-\-queue\-num\fP \fIvalue\fP
This specifies the QUEUE number to use. Valid queue numbers are 0 to 65535. The default value is 0.
@@ -18,6 +19,8 @@ This specifies a range of queues to use. Packets are then balanced across the gi
This is useful for multicore systems: start multiple instances of the userspace program on
queues x, x+1, .. x+n and use "\-\-queue\-balance \fIx\fP\fB:\fP\fIx+n\fP".
Packets belonging to the same connection are put into the same nfqueue.
+Due to implementation details, a lower range value of 0 limits the higher range
+value to 65534, i.e. one can only balance between at most 65535 queues.
.PP
.TP
\fB\-\-queue\-bypass\fP
@@ -26,8 +29,8 @@ are dropped. When this option is used, the NFQUEUE rule behaves like ACCEPT ins
will move on to the next table.
.PP
.TP
-\fB\-\-queue\-cpu-fanout\fP
+\fB\-\-queue\-cpu\-fanout\fP
Available starting Linux kernel 3.10. When used together with
-\fB--queue-balance\fP this will use the CPU ID as an index to map packets to
+\fB\-\-queue\-balance\fP this will use the CPU ID as an index to map packets to
the queues. The idea is that you can improve performance if there's a queue
-per CPU. This requires \fB--queue-balance\fP to be specified.
+per CPU. This requires \fB\-\-queue\-balance\fP to be specified.
diff --git a/extensions/libxt_NFQUEUE.t b/extensions/libxt_NFQUEUE.t
index b51b19fd..94050500 100644
--- a/extensions/libxt_NFQUEUE.t
+++ b/extensions/libxt_NFQUEUE.t
@@ -1,14 +1,20 @@
:INPUT,FORWARD,OUTPUT
--j NFQUEUE;=;OK
+-j NFQUEUE;-j NFQUEUE --queue-num 0;OK
-j NFQUEUE --queue-num 0;=;OK
-j NFQUEUE --queue-num 65535;=;OK
-j NFQUEUE --queue-num 65536;;FAIL
-j NFQUEUE --queue-num -1;;FAIL
-# it says "NFQUEUE: number of total queues is 0", overflow in NFQUEUE_parse_v1?
-# ERROR: cannot load: iptables -A INPUT -j NFQUEUE --queue-balance 0:65535
-# -j NFQUEUE --queue-balance 0:65535;=;OK
+-j NFQUEUE --queue-balance 0:65534;=;OK
+-j NFQUEUE --queue-balance 0:65535;;FAIL
-j NFQUEUE --queue-balance 0:65536;;FAIL
-j NFQUEUE --queue-balance -1:65535;;FAIL
+-j NFQUEUE --queue-balance 4;;FAIL
+-j NFQUEUE --queue-balance :;-j NFQUEUE --queue-balance 0:65534;OK
+-j NFQUEUE --queue-balance :4;-j NFQUEUE --queue-balance 0:4;OK
+-j NFQUEUE --queue-balance 4:;-j NFQUEUE --queue-balance 4:65534;OK
+-j NFQUEUE --queue-balance 3:4;=;OK
+-j NFQUEUE --queue-balance 4:4;;FAIL
+-j NFQUEUE --queue-balance 4:3;;FAIL
-j NFQUEUE --queue-num 10 --queue-bypass;=;OK
-j NFQUEUE --queue-balance 0:6 --queue-cpu-fanout --queue-bypass;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK
-j NFQUEUE --queue-bypass --queue-balance 0:6 --queue-cpu-fanout;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK
diff --git a/extensions/libxt_NFQUEUE.txlate b/extensions/libxt_NFQUEUE.txlate
index 3d188a7a..3698dcbc 100644
--- a/extensions/libxt_NFQUEUE.txlate
+++ b/extensions/libxt_NFQUEUE.txlate
@@ -1,8 +1,8 @@
iptables-translate -t nat -A PREROUTING -p tcp --dport 80 -j NFQUEUE --queue-num 30
-nft add rule ip nat PREROUTING tcp dport 80 counter queue num 30
+nft 'add rule ip nat PREROUTING tcp dport 80 counter queue num 30'
iptables-translate -A FORWARD -j NFQUEUE --queue-num 0 --queue-bypass -p TCP --sport 80
-nft add rule ip filter FORWARD tcp sport 80 counter queue num 0 bypass
+nft 'add rule ip filter FORWARD tcp sport 80 counter queue num 0 bypass'
iptables-translate -A FORWARD -j NFQUEUE --queue-bypass -p TCP --sport 80 --queue-balance 0:3 --queue-cpu-fanout
-nft add rule ip filter FORWARD tcp sport 80 counter queue num 0-3 bypass,fanout
+nft 'add rule ip filter FORWARD tcp sport 80 counter queue num 0-3 bypass,fanout'
diff --git a/extensions/libxt_NOTRACK.txlate b/extensions/libxt_NOTRACK.txlate
index 9d35619d..9490ee8f 100644
--- a/extensions/libxt_NOTRACK.txlate
+++ b/extensions/libxt_NOTRACK.txlate
@@ -1,2 +1,2 @@
iptables-translate -A PREROUTING -t raw -j NOTRACK
-nft add rule ip raw PREROUTING counter notrack
+nft 'add rule ip raw PREROUTING counter notrack'
diff --git a/extensions/libxt_REDIRECT.man b/extensions/libxt_REDIRECT.man
index 28d4d10b..1cbdb9ba 100644
--- a/extensions/libxt_REDIRECT.man
+++ b/extensions/libxt_REDIRECT.man
@@ -16,10 +16,9 @@ This specifies a destination port or range of ports to use: without
this, the destination port is never altered. This is only valid
if the rule also specifies one of the following protocols:
\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP.
+For a single port, a service name as listed in \fB/etc/services\fP may be used.
.TP
\fB\-\-random\fP
-If option
-\fB\-\-random\fP
-is used then port mapping will be randomized (kernel >= 2.6.22).
+Randomize source port mapping (kernel >= 2.6.22).
.TP
IPv6 support available starting Linux kernels >= 3.7.
diff --git a/extensions/libxt_REDIRECT.t b/extensions/libxt_REDIRECT.t
new file mode 100644
index 00000000..362efa84
--- /dev/null
+++ b/extensions/libxt_REDIRECT.t
@@ -0,0 +1,17 @@
+:PREROUTING,OUTPUT
+*nat
+-p tcp -j REDIRECT --to-ports 42;=;OK
+-p tcp -j REDIRECT --to-ports 0;=;OK
+-p tcp -j REDIRECT --to-ports 65535;=;OK
+-p tcp -j REDIRECT --to-ports 65536;;FAIL
+-p udp -j REDIRECT --to-ports 0-0;-p udp -j REDIRECT --to-ports 0;OK
+-p udp -j REDIRECT --to-ports 512-512;-p udp -j REDIRECT --to-ports 512;OK
+-p udp -j REDIRECT --to-ports 42-1234;=;OK
+-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
+-p tcp -j REDIRECT --to-ports 42-1234/567;;FAIL
+-p tcp -j REDIRECT --to-ports ssh;-p tcp -j REDIRECT --to-ports 22;OK
+-p tcp -j REDIRECT --to-ports ftp-data;-p tcp -j REDIRECT --to-ports 20;OK
+-p tcp -j REDIRECT --to-ports ftp-ssh;;FAIL
+-p tcp -j REDIRECT --to-ports 10-ssh;;FAIL
+-j REDIRECT --to-ports 42;;FAIL
+-j REDIRECT --random;=;OK
diff --git a/extensions/libxt_REDIRECT.txlate b/extensions/libxt_REDIRECT.txlate
new file mode 100644
index 00000000..dc473340
--- /dev/null
+++ b/extensions/libxt_REDIRECT.txlate
@@ -0,0 +1,29 @@
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT
+nft 'add rule ip nat prerouting tcp dport 80 counter redirect'
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0
+nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :0'
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
+nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :8080'
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0-65535
+nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :0-65535'
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 10-22
+nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :10-22'
+
+iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
+nft 'add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random'
+
+iptables-translate -t nat -A prerouting -j REDIRECT --random
+nft 'add rule ip nat prerouting counter redirect random'
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT
+nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect'
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080
+nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080'
+
+ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random
+nft 'add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random'
diff --git a/extensions/libxt_SECMARK.c b/extensions/libxt_SECMARK.c
index 6ba86063..a4ee60f0 100644
--- a/extensions/libxt_SECMARK.c
+++ b/extensions/libxt_SECMARK.c
@@ -29,6 +29,13 @@ static const struct xt_option_entry SECMARK_opts[] = {
XTOPT_TABLEEND,
};
+static const struct xt_option_entry SECMARK_opts_v1[] = {
+ {.name = "selctx", .id = O_SELCTX, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_secmark_target_info_v1, secctx)},
+ XTOPT_TABLEEND,
+};
+
static void SECMARK_parse(struct xt_option_call *cb)
{
struct xt_secmark_target_info *info = cb->data;
@@ -37,15 +44,23 @@ static void SECMARK_parse(struct xt_option_call *cb)
info->mode = SECMARK_MODE_SEL;
}
-static void print_secmark(const struct xt_secmark_target_info *info)
+static void SECMARK_parse_v1(struct xt_option_call *cb)
+{
+ struct xt_secmark_target_info_v1 *info = cb->data;
+
+ xtables_option_parse(cb);
+ info->mode = SECMARK_MODE_SEL;
+}
+
+static void print_secmark(__u8 mode, const char *secctx)
{
- switch (info->mode) {
+ switch (mode) {
case SECMARK_MODE_SEL:
- printf("selctx %s", info->secctx);
+ printf("selctx %s", secctx);
break;
-
+
default:
- xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode);
+ xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu", mode);
}
}
@@ -56,7 +71,17 @@ static void SECMARK_print(const void *ip, const struct xt_entry_target *target,
(struct xt_secmark_target_info*)(target)->data;
printf(" SECMARK ");
- print_secmark(info);
+ print_secmark(info->mode, info->secctx);
+}
+
+static void SECMARK_print_v1(const void *ip,
+ const struct xt_entry_target *target, int numeric)
+{
+ const struct xt_secmark_target_info_v1 *info =
+ (struct xt_secmark_target_info_v1 *)(target)->data;
+
+ printf(" SECMARK ");
+ print_secmark(info->mode, info->secctx);
}
static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
@@ -65,24 +90,49 @@ static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
(struct xt_secmark_target_info*)target->data;
printf(" --");
- print_secmark(info);
+ print_secmark(info->mode, info->secctx);
}
-static struct xtables_target secmark_target = {
- .family = NFPROTO_UNSPEC,
- .name = "SECMARK",
- .version = XTABLES_VERSION,
- .revision = 0,
- .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
- .help = SECMARK_help,
- .print = SECMARK_print,
- .save = SECMARK_save,
- .x6_parse = SECMARK_parse,
- .x6_options = SECMARK_opts,
+static void SECMARK_save_v1(const void *ip,
+ const struct xt_entry_target *target)
+{
+ const struct xt_secmark_target_info_v1 *info =
+ (struct xt_secmark_target_info_v1 *)target->data;
+
+ printf(" --");
+ print_secmark(info->mode, info->secctx);
+}
+
+static struct xtables_target secmark_tg_reg[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "SECMARK",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+ .help = SECMARK_help,
+ .print = SECMARK_print,
+ .save = SECMARK_save,
+ .x6_parse = SECMARK_parse,
+ .x6_options = SECMARK_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "SECMARK",
+ .version = XTABLES_VERSION,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct xt_secmark_target_info_v1)),
+ .userspacesize = XT_ALIGN(offsetof(struct xt_secmark_target_info_v1, secid)),
+ .help = SECMARK_help,
+ .print = SECMARK_print_v1,
+ .save = SECMARK_save_v1,
+ .x6_parse = SECMARK_parse_v1,
+ .x6_options = SECMARK_opts_v1,
+ }
};
void _init(void)
{
- xtables_register_target(&secmark_target);
+ xtables_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
}
diff --git a/extensions/libxt_SECMARK.t b/extensions/libxt_SECMARK.t
new file mode 100644
index 00000000..39d4c093
--- /dev/null
+++ b/extensions/libxt_SECMARK.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+*security
+-j SECMARK --selctx system_u:object_r:firewalld_exec_t:s0;=;OK
+-j SECMARK;;FAIL
diff --git a/extensions/libxt_SET.man b/extensions/libxt_SET.man
index c4713378..7332acb0 100644
--- a/extensions/libxt_SET.man
+++ b/extensions/libxt_SET.man
@@ -25,8 +25,8 @@ one from the set definition
when adding an entry if it already exists, reset the timeout value
to the specified one or to the default from the set definition
.TP
-\fB\-\-map\-set\fP \fIset\-name\fP
-the set-name should be created with --skbinfo option
+\fB\-\-map\-set\fP \fIset-name\fP
+the set-name should be created with \-\-skbinfo option
\fB\-\-map\-mark\fP
map firewall mark to packet by lookup of value in the set
\fB\-\-map\-prio\fP
diff --git a/extensions/libxt_SNAT.man b/extensions/libxt_SNAT.man
index 8cd0b80e..d879c871 100644
--- a/extensions/libxt_SNAT.man
+++ b/extensions/libxt_SNAT.man
@@ -19,22 +19,12 @@ If no port range is specified, then source ports below 512 will be
mapped to other ports below 512: those between 512 and 1023 inclusive
will be mapped to ports below 1024, and other ports will be mapped to
1024 or above. Where possible, no port alteration will occur.
-In Kernels up to 2.6.10, you can add several \-\-to\-source options. For those
-kernels, if you specify more than one source address, either via an address
-range or multiple \-\-to\-source options, a simple round-robin (one after another
-in cycle) takes place between these addresses.
-Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
-anymore.
.TP
\fB\-\-random\fP
-If option
-\fB\-\-random\fP
-is used then port mapping will be randomized through a hash-based algorithm (kernel >= 2.6.21).
+Randomize source port mapping through a hash-based algorithm (kernel >= 2.6.21).
.TP
-\fB\-\-random-fully\fP
-If option
-\fB\-\-random-fully\fP
-is used then port mapping will be fully randomized through a PRNG (kernel >= 3.14).
+\fB\-\-random\-fully\fP
+Fully randomize source port mapping through a PRNG (kernel >= 3.14).
.TP
\fB\-\-persistent\fP
Gives a client the same source-/destination-address for each connection.
diff --git a/extensions/libxt_SYNPROXY.man b/extensions/libxt_SYNPROXY.man
index 30a71ed2..04fffedb 100644
--- a/extensions/libxt_SYNPROXY.man
+++ b/extensions/libxt_SYNPROXY.man
@@ -22,7 +22,7 @@ Example:
.PP
Determine tcp options used by backend, from an external system
.IP
-tcpdump -pni eth0 -c 1 'tcp[tcpflags] == (tcp-syn|tcp-ack)'
+tcpdump \-pni eth0 \-c 1 'tcp[tcpflags] == (tcp\-syn|tcp\-ack)'
.br
port 80 &
.br
@@ -40,7 +40,7 @@ telnet 192.0.2.42 80
.br
length 0
.PP
-Switch tcp_loose mode off, so conntrack will mark out\-of\-flow
+Switch tcp_loose mode off, so conntrack will mark out-of-flow
packets as state INVALID.
.IP
echo 0 > /proc/sys/net/netfilter/nf_conntrack_tcp_loose
diff --git a/extensions/libxt_SYNPROXY.txlate b/extensions/libxt_SYNPROXY.txlate
index b3de2b2a..b996c4b7 100644
--- a/extensions/libxt_SYNPROXY.txlate
+++ b/extensions/libxt_SYNPROXY.txlate
@@ -1,2 +1,2 @@
iptables-translate -t mangle -A INPUT -i iifname -p tcp -m tcp --dport 80 -m state --state INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
-nft add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460
+nft 'add rule ip mangle INPUT iifname "iifname" tcp dport 80 ct state invalid,untracked counter synproxy sack-perm timestamp wscale 7 mss 1460'
diff --git a/extensions/libxt_TCPMSS.c b/extensions/libxt_TCPMSS.c
index 0d9b200e..251a5532 100644
--- a/extensions/libxt_TCPMSS.c
+++ b/extensions/libxt_TCPMSS.c
@@ -131,6 +131,7 @@ static struct xtables_target tcpmss_tg_reg[] = {
.x6_parse = TCPMSS_parse,
.x6_fcheck = TCPMSS_check,
.x6_options = TCPMSS6_opts,
+ .xlate = TCPMSS_xlate,
},
};
diff --git a/extensions/libxt_TCPMSS.t b/extensions/libxt_TCPMSS.t
index 553a3452..b3639cc1 100644
--- a/extensions/libxt_TCPMSS.t
+++ b/extensions/libxt_TCPMSS.t
@@ -1,6 +1,6 @@
:FORWARD,OUTPUT,POSTROUTING
*mangle
-j TCPMSS;;FAIL
--p tcp -j TCPMSS --set-mss 42;;FAIL
+-p tcp -j TCPMSS --set-mss 42;=;FAIL;LEGACY
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --set-mss 42;=;OK
-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --clamp-mss-to-pmtu;=;OK
diff --git a/extensions/libxt_TCPMSS.txlate b/extensions/libxt_TCPMSS.txlate
index 6a64d2ce..a059c602 100644
--- a/extensions/libxt_TCPMSS.txlate
+++ b/extensions/libxt_TCPMSS.txlate
@@ -1,5 +1,5 @@
iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
-nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set rt mtu
+nft 'add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set rt mtu'
iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 90
-nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set 90
+nft 'add rule ip filter FORWARD tcp flags syn / syn,rst counter tcp option maxseg size set 90'
diff --git a/extensions/libxt_TCPOPTSTRIP.c b/extensions/libxt_TCPOPTSTRIP.c
index 6ea34892..ff873f98 100644
--- a/extensions/libxt_TCPOPTSTRIP.c
+++ b/extensions/libxt_TCPOPTSTRIP.c
@@ -142,6 +142,13 @@ tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
}
}
+static bool tcpoptstrip_empty(const struct xt_tcpoptstrip_target_info *info)
+{
+ static const struct xt_tcpoptstrip_target_info empty = {};
+
+ return memcmp(info, &empty, sizeof(empty)) == 0;
+}
+
static void
tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
@@ -149,6 +156,9 @@ tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
const struct xt_tcpoptstrip_target_info *info =
(const void *)target->data;
+ if (tcpoptstrip_empty(info))
+ return;
+
printf(" TCPOPTSTRIP options ");
tcpoptstrip_print_list(info, numeric);
}
@@ -159,6 +169,9 @@ tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
const struct xt_tcpoptstrip_target_info *info =
(const void *)target->data;
+ if (tcpoptstrip_empty(info))
+ return;
+
printf(" --strip-options ");
tcpoptstrip_print_list(info, true);
}
diff --git a/extensions/libxt_TEE.txlate b/extensions/libxt_TEE.txlate
index 9fcee254..fa1d5fe3 100644
--- a/extensions/libxt_TEE.txlate
+++ b/extensions/libxt_TEE.txlate
@@ -1,11 +1,11 @@
# iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2 --oif eth0
-# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2 device eth0
+# nft 'add rule ip mangle PREROUTING counter dup to 192.168.0.2 device eth0
#
# iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2
-# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2
+# nft 'add rule ip mangle PREROUTING counter dup to 192.168.0.2
ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba::
-nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba::
+nft 'add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba::'
ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba:: --oif eth0
-nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: device eth0
+nft 'add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: device eth0'
diff --git a/extensions/libxt_TOS.c b/extensions/libxt_TOS.c
index b66fa329..4fc849bd 100644
--- a/extensions/libxt_TOS.c
+++ b/extensions/libxt_TOS.c
@@ -183,28 +183,41 @@ static void tos_tg_save(const void *ip, const struct xt_entry_target *target)
printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask);
}
+static int __tos_xlate(struct xt_xlate *xl, const char *ip,
+ uint8_t tos, uint8_t tosmask)
+{
+ xt_xlate_add(xl, "%s dscp set ", ip);
+ if ((tosmask & 0x3f) == 0x3f)
+ xt_xlate_add(xl, "0x%02x", tos >> 2);
+ else if (!tos)
+ xt_xlate_add(xl, "%s dscp and 0x%02x",
+ ip, (uint8_t)~tosmask >> 2);
+ else if (tos == tosmask)
+ xt_xlate_add(xl, "%s dscp or 0x%02x", ip, tos >> 2);
+ else if (!tosmask)
+ xt_xlate_add(xl, "%s dscp xor 0x%02x", ip, tos >> 2);
+ else
+ xt_xlate_add(xl, "%s dscp and 0x%02x xor 0x%02x",
+ ip, (uint8_t)~tosmask >> 2, tos >> 2);
+ return 1;
+}
+
static int tos_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
const struct ipt_tos_target_info *info =
(struct ipt_tos_target_info *) params->target->data;
- uint8_t dscp = info->tos >> 2;
-
- xt_xlate_add(xl, "ip dscp set 0x%02x", dscp);
- return 1;
+ return __tos_xlate(xl, "ip", info->tos, UINT8_MAX);
}
static int tos_xlate6(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
- const struct ipt_tos_target_info *info =
- (struct ipt_tos_target_info *) params->target->data;
- uint8_t dscp = info->tos >> 2;
+ const struct xt_tos_target_info *info =
+ (struct xt_tos_target_info *)params->target->data;
- xt_xlate_add(xl, "ip6 dscp set 0x%02x", dscp);
-
- return 1;
+ return __tos_xlate(xl, "ip6", info->tos_value, info->tos_mask);
}
static struct xtables_target tos_tg_reg[] = {
diff --git a/extensions/libxt_TOS.man b/extensions/libxt_TOS.man
index de2d22dc..2c8d4694 100644
--- a/extensions/libxt_TOS.man
+++ b/extensions/libxt_TOS.man
@@ -32,5 +32,5 @@ longterm releases 2.6.32 (>=.42), 2.6.33 (>=.15), and 2.6.35 (>=.14), there is
a bug whereby IPv6 TOS mangling does not behave as documented and differs from
the IPv4 version. The TOS mask indicates the bits one wants to zero out, so it
needs to be inverted before applying it to the original TOS field. However, the
-aformentioned kernels forgo the inversion which breaks \-\-set\-tos and its
+aforementioned kernels forgo the inversion which breaks \-\-set\-tos and its
mnemonics.
diff --git a/extensions/libxt_TOS.t b/extensions/libxt_TOS.t
index ae8531cc..9f8e33fd 100644
--- a/extensions/libxt_TOS.t
+++ b/extensions/libxt_TOS.t
@@ -1,15 +1,15 @@
:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
*mangle
--j TOS --set-tos 0x1f;=;OK
+-j TOS --set-tos 0x1f;-j TOS --set-tos 0x1f/0xff;OK
-j TOS --set-tos 0x1f/0x1f;=;OK
# maximum TOS is 0x1f (5 bits)
# ERROR: should fail: iptables -A PREROUTING -t mangle -j TOS --set-tos 0xff
# -j TOS --set-tos 0xff;;FAIL
--j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10;OK
--j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08;OK
--j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04;OK
--j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02;OK
--j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00;OK
+-j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10/0x3f;OK
+-j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08/0x3f;OK
+-j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04/0x3f;OK
+-j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02/0x3f;OK
+-j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00/0x3f;OK
-j TOS --and-tos 0x12;-j TOS --set-tos 0x00/0xed;OK
-j TOS --or-tos 0x12;-j TOS --set-tos 0x12/0x12;OK
-j TOS --xor-tos 0x12;-j TOS --set-tos 0x12/0x00;OK
diff --git a/extensions/libxt_TOS.txlate b/extensions/libxt_TOS.txlate
index 0952310e..37ef1d86 100644
--- a/extensions/libxt_TOS.txlate
+++ b/extensions/libxt_TOS.txlate
@@ -1,23 +1,26 @@
ip6tables-translate -A INPUT -j TOS --set-tos 0x1f
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x07
+nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x07'
ip6tables-translate -A INPUT -j TOS --set-tos 0xff
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x3f
+nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x3f'
ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Delay
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x04
+nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x04'
ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Cost
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x00
+nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x00'
ip6tables-translate -A INPUT -j TOS --set-tos Normal-Service
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x00
+nft 'add rule ip6 filter INPUT counter ip6 dscp set 0x00'
ip6tables-translate -A INPUT -j TOS --and-tos 0x12
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x00
+nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x04'
ip6tables-translate -A INPUT -j TOS --or-tos 0x12
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x04
+nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp or 0x04'
ip6tables-translate -A INPUT -j TOS --xor-tos 0x12
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x04
+nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp xor 0x04'
+
+ip6tables-translate -A INPUT -j TOS --set-tos 0x12/0x34
+nft 'add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x32 xor 0x04'
diff --git a/extensions/libxt_TPROXY.c b/extensions/libxt_TPROXY.c
index d13ec85f..ffc9da13 100644
--- a/extensions/libxt_TPROXY.c
+++ b/extensions/libxt_TPROXY.c
@@ -147,6 +147,62 @@ static void tproxy_tg1_parse(struct xt_option_call *cb)
}
}
+static int tproxy_tg_xlate(struct xt_xlate *xl,
+ const struct xt_tproxy_target_info_v1 *info)
+{
+ int family = xt_xlate_get_family(xl);
+ uint32_t mask = info->mark_mask;
+ bool port_mandatory = false;
+ char buf[INET6_ADDRSTRLEN];
+
+ xt_xlate_add(xl, "tproxy to");
+
+ inet_ntop(family, &info->laddr, buf, sizeof(buf));
+
+ if (family == AF_INET6 && !IN6_IS_ADDR_UNSPECIFIED(&info->laddr.in6))
+ xt_xlate_add(xl, "[%s]", buf);
+ else if (family == AF_INET && info->laddr.ip)
+ xt_xlate_add(xl, "%s", buf);
+ else
+ port_mandatory = true;
+
+ if (port_mandatory)
+ xt_xlate_add(xl, " :%d", ntohs(info->lport));
+ else if (info->lport)
+ xt_xlate_add(xl, ":%d", ntohs(info->lport));
+
+ /* xt_TPROXY.c does: skb->mark = (skb->mark & ~mark_mask) ^ mark_value */
+ if (mask == 0xffffffff)
+ xt_xlate_add(xl, "meta mark set 0x%x", info->mark_value);
+ else if (mask || info->mark_value)
+ xt_xlate_add(xl, "meta mark set meta mark & 0x%x xor 0x%x",
+ ~mask, info->mark_value);
+
+ return 1;
+}
+
+static int tproxy_tg_xlate_v1(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_tproxy_target_info_v1 *data = (const void *)params->target->data;
+
+ return tproxy_tg_xlate(xl, data);
+}
+
+static int tproxy_tg_xlate_v0(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_tproxy_target_info *info = (const void *)params->target->data;
+ struct xt_tproxy_target_info_v1 t = {
+ .mark_mask = info->mark_mask,
+ .mark_value = info->mark_value,
+ .laddr.ip = info->laddr,
+ .lport = info->lport,
+ };
+
+ return tproxy_tg_xlate(xl, &t);
+}
+
static struct xtables_target tproxy_tg_reg[] = {
{
.name = "TPROXY",
@@ -160,6 +216,7 @@ static struct xtables_target tproxy_tg_reg[] = {
.save = tproxy_tg_save,
.x6_options = tproxy_tg0_opts,
.x6_parse = tproxy_tg0_parse,
+ .xlate = tproxy_tg_xlate_v0,
},
{
.name = "TPROXY",
@@ -173,6 +230,7 @@ static struct xtables_target tproxy_tg_reg[] = {
.save = tproxy_tg_save4,
.x6_options = tproxy_tg1_opts,
.x6_parse = tproxy_tg1_parse,
+ .xlate = tproxy_tg_xlate_v1,
},
{
.name = "TPROXY",
@@ -186,6 +244,7 @@ static struct xtables_target tproxy_tg_reg[] = {
.save = tproxy_tg_save6,
.x6_options = tproxy_tg1_opts,
.x6_parse = tproxy_tg1_parse,
+ .xlate = tproxy_tg_xlate_v1,
},
};
diff --git a/extensions/libxt_TPROXY.txlate b/extensions/libxt_TPROXY.txlate
new file mode 100644
index 00000000..239bbe0d
--- /dev/null
+++ b/extensions/libxt_TPROXY.txlate
@@ -0,0 +1,20 @@
+iptables-translate -t mangle -A PREROUTING -p tcp -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff
+nft 'add rule ip mangle PREROUTING ip protocol tcp counter tproxy to 10.0.0.1:12345 meta mark set meta mark & 0xffffff00 xor 0x23'
+
+iptables-translate -t mangle -A PREROUTING -p udp -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23
+nft 'add rule ip mangle PREROUTING ip protocol udp counter tproxy to 10.0.0.1:12345 meta mark set 0x23'
+
+iptables-translate -t mangle -A PREROUTING -p udp -j TPROXY --on-port 12345 --on-ip 10.0.0.1
+nft 'add rule ip mangle PREROUTING ip protocol udp counter tproxy to 10.0.0.1:12345'
+
+iptables-translate -t mangle -A PREROUTING -p udp -j TPROXY --on-ip 10.0.0.1 --on-port 0
+nft 'add rule ip mangle PREROUTING ip protocol udp counter tproxy to 10.0.0.1'
+
+iptables-translate -t mangle -A PREROUTING -p tcp -j TPROXY --on-port 12345
+nft 'add rule ip mangle PREROUTING ip protocol tcp counter tproxy to :12345'
+
+iptables-translate -t mangle -A PREROUTING -p tcp -j TPROXY --on-port 0
+nft 'add rule ip mangle PREROUTING ip protocol tcp counter tproxy to :0'
+
+ip6tables-translate -t mangle -A PREROUTING -p tcp -j TPROXY --on-port 12345 --on-ip dead::beef --tproxy-mark 0x23/0xffff
+nft 'add rule ip6 mangle PREROUTING meta l4proto tcp counter tproxy to [dead::beef]:12345 meta mark set meta mark & 0xffff0000 xor 0x23'
diff --git a/extensions/libxt_TRACE.man b/extensions/libxt_TRACE.man
index 5187a8d2..9cfa2711 100644
--- a/extensions/libxt_TRACE.man
+++ b/extensions/libxt_TRACE.man
@@ -15,6 +15,6 @@ With iptables-nft, the target is translated into nftables'
.B "meta nftrace"
expression. Hence the kernel sends trace events via netlink to userspace where
they may be displayed using
-.B "xtables-monitor --trace"
+.B "xtables\-monitor \-\-trace"
command. For details, refer to
-.BR xtables-monitor (8).
+.BR xtables\-monitor (8).
diff --git a/extensions/libxt_TRACE.txlate b/extensions/libxt_TRACE.txlate
index 8e3d2a7a..a9d28fe0 100644
--- a/extensions/libxt_TRACE.txlate
+++ b/extensions/libxt_TRACE.txlate
@@ -1,2 +1,2 @@
iptables-translate -t raw -A PREROUTING -j TRACE
-nft add rule ip raw PREROUTING counter nftrace set 1
+nft 'add rule ip raw PREROUTING counter nftrace set 1'
diff --git a/extensions/libxt_addrtype.txlate b/extensions/libxt_addrtype.txlate
index a719b2c9..70c0a345 100644
--- a/extensions/libxt_addrtype.txlate
+++ b/extensions/libxt_addrtype.txlate
@@ -1,11 +1,11 @@
iptables-translate -A INPUT -m addrtype --src-type LOCAL
-nft add rule ip filter INPUT fib saddr type local counter
+nft 'add rule ip filter INPUT fib saddr type local counter'
iptables-translate -A INPUT -m addrtype --dst-type LOCAL
-nft add rule ip filter INPUT fib daddr type local counter
+nft 'add rule ip filter INPUT fib daddr type local counter'
iptables-translate -A INPUT -m addrtype ! --dst-type ANYCAST,LOCAL
-nft add rule ip filter INPUT fib daddr type != { local, anycast } counter
+nft 'add rule ip filter INPUT fib daddr type != { local, anycast } counter'
iptables-translate -A INPUT -m addrtype --limit-iface-in --dst-type ANYCAST,LOCAL
-nft add rule ip filter INPUT fib daddr . iif type { local, anycast } counter
+nft 'add rule ip filter INPUT fib daddr . iif type { local, anycast } counter'
diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
index eeae86e5..5e035837 100644
--- a/extensions/libxt_bpf.c
+++ b/extensions/libxt_bpf.c
@@ -83,8 +83,7 @@ static int bpf_obj_get_readonly(const char *filepath)
attr.file_flags = 0;
return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
#else
- xtables_error(OTHER_PROBLEM,
- "No bpf header, kernel headers too old?\n");
+ xtables_error(OTHER_PROBLEM, "No bpf header, kernel headers too old?");
return -EINVAL;
#endif
}
diff --git a/extensions/libxt_bpf.man b/extensions/libxt_bpf.man
index d6da2043..b79c21db 100644
--- a/extensions/libxt_bpf.man
+++ b/extensions/libxt_bpf.man
@@ -28,7 +28,7 @@ without the comments or trailing whitespace:
.IP
4 # number of instructions
.br
-48 0 0 9 # load byte ip->proto
+48 0 0 9 # load byte ip\->proto
.br
21 0 1 6 # jump equal IPPROTO_TCP
.br
@@ -44,7 +44,7 @@ Or instead, you can invoke the nfbpf_compile utility.
.IP
iptables \-A OUTPUT \-m bpf \-\-bytecode "`nfbpf_compile RAW 'ip proto 6'`" \-j ACCEPT
.PP
-Or use tcpdump -ddd. In that case, generate BPF targeting a device with the
+Or use tcpdump \-ddd. In that case, generate BPF targeting a device with the
same data link type as the xtables match. Iptables passes packets from the
network layer up, without mac layer. Select a device with data link type RAW,
such as a tun device:
@@ -53,8 +53,8 @@ ip tuntap add tun0 mode tun
.br
ip link set tun0 up
.br
-tcpdump -ddd -i tun0 ip proto 6
+tcpdump \-ddd \-i tun0 ip proto 6
.PP
-See tcpdump -L -i $dev for a list of known data link types for a given device.
+See tcpdump \-L \-i $dev for a list of known data link types for a given device.
.PP
You may want to learn more about BPF from FreeBSD's bpf(4) manpage.
diff --git a/extensions/libxt_cgroup.man b/extensions/libxt_cgroup.man
index 4d5d1d86..140afb48 100644
--- a/extensions/libxt_cgroup.man
+++ b/extensions/libxt_cgroup.man
@@ -15,7 +15,7 @@ option and \-\-path can't be used together.
.PP
Example:
.IP
-iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-path service/http-server \-j DROP
+iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-path service/http\-server \-j DROP
.IP
iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-cgroup 1
\-j DROP
diff --git a/extensions/libxt_cgroup.txlate b/extensions/libxt_cgroup.txlate
index 75f2e6ae..6e3aab76 100644
--- a/extensions/libxt_cgroup.txlate
+++ b/extensions/libxt_cgroup.txlate
@@ -1,5 +1,5 @@
iptables-translate -t filter -A INPUT -m cgroup --cgroup 0 -j ACCEPT
-nft add rule ip filter INPUT meta cgroup 0 counter accept
+nft 'add rule ip filter INPUT meta cgroup 0 counter accept'
iptables-translate -t filter -A INPUT -m cgroup ! --cgroup 0 -j ACCEPT
-nft add rule ip filter INPUT meta cgroup != 0 counter accept
+nft 'add rule ip filter INPUT meta cgroup != 0 counter accept'
diff --git a/extensions/libxt_cluster.man b/extensions/libxt_cluster.man
index 23448e26..63054471 100644
--- a/extensions/libxt_cluster.man
+++ b/extensions/libxt_cluster.man
@@ -22,7 +22,7 @@ Example:
iptables \-A PREROUTING \-t mangle \-i eth1 \-m cluster
\-\-cluster\-total\-nodes 2 \-\-cluster\-local\-node 1
\-\-cluster\-hash\-seed 0xdeadbeef
-\-j MARK \-\-set-mark 0xffff
+\-j MARK \-\-set\-mark 0xffff
.IP
iptables \-A PREROUTING \-t mangle \-i eth2 \-m cluster
\-\-cluster\-total\-nodes 2 \-\-cluster\-local\-node 1
@@ -42,10 +42,10 @@ ip maddr add 01:00:5e:00:01:01 dev eth1
ip maddr add 01:00:5e:00:01:02 dev eth2
.IP
arptables \-A OUTPUT \-o eth1 \-\-h\-length 6
-\-j mangle \-\-mangle-mac-s 01:00:5e:00:01:01
+\-j mangle \-\-mangle\-mac\-s 01:00:5e:00:01:01
.IP
-arptables \-A INPUT \-i eth1 \-\-h-length 6
-\-\-destination-mac 01:00:5e:00:01:01
+arptables \-A INPUT \-i eth1 \-\-h\-length 6
+\-\-destination\-mac 01:00:5e:00:01:01
\-j mangle \-\-mangle\-mac\-d 00:zz:yy:xx:5a:27
.IP
arptables \-A OUTPUT \-o eth2 \-\-h\-length 6
diff --git a/extensions/libxt_cluster.txlate b/extensions/libxt_cluster.txlate
index 9dcf5707..4dc1c691 100644
--- a/extensions/libxt_cluster.txlate
+++ b/extensions/libxt_cluster.txlate
@@ -1,26 +1,26 @@
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-node 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 32 meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 32 meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 6 meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef eq 6 meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef { 0, 2 } meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 32 seed 0xdeadbeef { 0, 2 } meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-nodemask 9 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef { 0, 3 } meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef { 0, 3 } meta pkttype set host counter meta mark set 0xffff'
iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-node 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff
-nft add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef eq 5 meta pkttype set host counter meta mark set 0xffff
+nft 'add rule ip mangle PREROUTING iifname "eth1" jhash ct original saddr mod 7 seed 0xdeadbeef eq 5 meta pkttype set host counter meta mark set 0xffff'
diff --git a/extensions/libxt_comment.c b/extensions/libxt_comment.c
index 69795b6c..e9c539f6 100644
--- a/extensions/libxt_comment.c
+++ b/extensions/libxt_comment.c
@@ -55,12 +55,7 @@ static int comment_xlate(struct xt_xlate *xl,
char comment[XT_MAX_COMMENT_LEN + sizeof("\\\"\\\"")];
commentinfo->comment[XT_MAX_COMMENT_LEN - 1] = '\0';
- if (params->escape_quotes)
- snprintf(comment, sizeof(comment), "\\\"%s\\\"",
- commentinfo->comment);
- else
- snprintf(comment, sizeof(comment), "\"%s\"",
- commentinfo->comment);
+ snprintf(comment, sizeof(comment), "\"%s\"", commentinfo->comment);
xt_xlate_add_comment(xl, comment);
diff --git a/extensions/libxt_comment.txlate b/extensions/libxt_comment.txlate
index c610b0e5..5d4ce59d 100644
--- a/extensions/libxt_comment.txlate
+++ b/extensions/libxt_comment.txlate
@@ -1,8 +1,8 @@
iptables-translate -A INPUT -s 192.168.0.0 -m comment --comment "A privatized IP block"
-nft add rule ip filter INPUT ip saddr 192.168.0.0 counter comment \"A privatized IP block\"
+nft 'add rule ip filter INPUT ip saddr 192.168.0.0 counter comment "A privatized IP block"'
iptables-translate -A INPUT -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j LONGNACCEPT -m comment --comment "foobar"
-nft add rule ip filter INPUT ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter jump LONGNACCEPT comment \"foobar\"
+nft 'add rule ip filter INPUT ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter jump LONGNACCEPT comment "foobar"'
iptables-translate -A FORWARD -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j DROP -m comment --comment singlecomment
-nft add rule ip filter FORWARD ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter drop comment \"singlecomment\"
+nft 'add rule ip filter FORWARD ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter drop comment "singlecomment"'
diff --git a/extensions/libxt_connbytes.c b/extensions/libxt_connbytes.c
index b57f0fc0..2f110857 100644
--- a/extensions/libxt_connbytes.c
+++ b/extensions/libxt_connbytes.c
@@ -41,10 +41,6 @@ static void connbytes_parse(struct xt_option_call *cb)
if (cb->nvals == 2)
sinfo->count.to = cb->val.u64_range[1];
- if (sinfo->count.to < sinfo->count.from)
- xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
- (unsigned long long)sinfo->count.from,
- (unsigned long long)sinfo->count.to);
if (cb->invert) {
i = sinfo->count.from;
sinfo->count.from = sinfo->count.to;
diff --git a/extensions/libxt_connbytes.t b/extensions/libxt_connbytes.t
index 6b24e266..60209c69 100644
--- a/extensions/libxt_connbytes.t
+++ b/extensions/libxt_connbytes.t
@@ -10,6 +10,12 @@
-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir both;=;OK
-m connbytes --connbytes -1:0 --connbytes-mode packets --connbytes-dir original;;FAIL
-m connbytes --connbytes 0:-1 --connbytes-mode packets --connbytes-dir original;;FAIL
+-m connbytes --connbytes : --connbytes-mode packets --connbytes-dir original;-m connbytes --connbytes 0 --connbytes-mode packets --connbytes-dir original;OK
+-m connbytes --connbytes :1000 --connbytes-mode packets --connbytes-dir original;-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir original;OK
+-m connbytes --connbytes 1000 --connbytes-mode packets --connbytes-dir original;=;OK
+-m connbytes --connbytes 1000: --connbytes-mode packets --connbytes-dir original;-m connbytes --connbytes 1000 --connbytes-mode packets --connbytes-dir original;OK
+-m connbytes --connbytes 1000:1000 --connbytes-mode packets --connbytes-dir original;=;OK
+-m connbytes --connbytes 1000:0 --connbytes-mode packets --connbytes-dir original;;FAIL
# ERROR: cannot find: iptables -I INPUT -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both
# -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both;=;OK
-m connbytes --connbytes 0:18446744073709551616 --connbytes-mode avgpkt --connbytes-dir both;;FAIL
diff --git a/extensions/libxt_connbytes.txlate b/extensions/libxt_connbytes.txlate
index f78958d2..a6af1b87 100644
--- a/extensions/libxt_connbytes.txlate
+++ b/extensions/libxt_connbytes.txlate
@@ -1,14 +1,14 @@
iptables-translate -A OUTPUT -m connbytes --connbytes 200 --connbytes-dir original --connbytes-mode packets
-nft add rule ip filter OUTPUT ct original packets ge 200 counter
+nft 'add rule ip filter OUTPUT ct original packets ge 200 counter'
iptables-translate -A OUTPUT -m connbytes ! --connbytes 200 --connbytes-dir reply --connbytes-mode packets
-nft add rule ip filter OUTPUT ct reply packets lt 200 counter
+nft 'add rule ip filter OUTPUT ct reply packets lt 200 counter'
iptables-translate -A OUTPUT -m connbytes --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes
-nft add rule ip filter OUTPUT ct bytes 200-600 counter
+nft 'add rule ip filter OUTPUT ct bytes 200-600 counter'
iptables-translate -A OUTPUT -m connbytes ! --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes
-nft add rule ip filter OUTPUT ct bytes != 200-600 counter
+nft 'add rule ip filter OUTPUT ct bytes != 200-600 counter'
iptables-translate -A OUTPUT -m connbytes --connbytes 200:200 --connbytes-dir both --connbytes-mode avgpkt
-nft add rule ip filter OUTPUT ct avgpkt 200 counter
+nft 'add rule ip filter OUTPUT ct avgpkt 200 counter'
diff --git a/extensions/libxt_connlabel.man b/extensions/libxt_connlabel.man
index bdaa51e8..7ce18cf5 100644
--- a/extensions/libxt_connlabel.man
+++ b/extensions/libxt_connlabel.man
@@ -23,11 +23,11 @@ Label translation is done via the \fB/etc/xtables/connlabel.conf\fP configuratio
Example:
.IP
.nf
-0 eth0-in
-1 eth0-out
-2 ppp-in
-3 ppp-out
-4 bulk-traffic
+0 eth0\-in
+1 eth0\-out
+2 ppp\-in
+3 ppp\-out
+4 bulk\-traffic
5 interactive
.fi
.PP
diff --git a/extensions/libxt_connlabel.txlate b/extensions/libxt_connlabel.txlate
index 12e4ac03..cba01d2d 100644
--- a/extensions/libxt_connlabel.txlate
+++ b/extensions/libxt_connlabel.txlate
@@ -1,5 +1,5 @@
iptables-translate -A INPUT -m connlabel --label 40
-nft add rule ip filter INPUT ct label 40 counter
+nft 'add rule ip filter INPUT ct label 40 counter'
iptables-translate -A INPUT -m connlabel ! --label 40 --set
-nft add rule ip filter INPUT ct label set 40 ct label and 40 != 40 counter
+nft 'add rule ip filter INPUT ct label set 40 ct label and 40 != 40 counter'
diff --git a/extensions/libxt_connlimit.c b/extensions/libxt_connlimit.c
index a569f86a..118faea5 100644
--- a/extensions/libxt_connlimit.c
+++ b/extensions/libxt_connlimit.c
@@ -2,6 +2,8 @@
#include <netdb.h>
#include <string.h>
#include <xtables.h>
+#include <arpa/inet.h>
+
#include <linux/netfilter/xt_connlimit.h>
enum {
@@ -183,6 +185,51 @@ static void connlimit_save6(const void *ip, const struct xt_entry_match *match)
}
}
+static int connlimit_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_connlimit_info *info = (const void *)params->match->data;
+ static uint32_t connlimit_id;
+ char netmask[128] = {};
+ char addr[64] = {};
+ uint32_t mask;
+
+ switch (xt_xlate_get_family(xl)) {
+ case AF_INET:
+ mask = count_bits4(info->v4_mask);
+ if (mask != 32) {
+ struct in_addr *in = (struct in_addr *)&info->v4_mask;
+
+ inet_ntop(AF_INET, in, addr, sizeof(addr));
+ snprintf(netmask, sizeof(netmask), "and %s ", addr);
+ }
+ break;
+ case AF_INET6:
+ mask = count_bits6(info->v6_mask);
+ if (mask != 128) {
+ struct in6_addr *in6 = (struct in6_addr *)&info->v6_mask;
+
+ inet_ntop(AF_INET6, in6, addr, sizeof(addr));
+ snprintf(netmask, sizeof(netmask), "and %s ", addr);
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ xt_xlate_set_add(xl, "connlimit%u { type ipv4_addr; flags dynamic; }",
+ connlimit_id);
+ xt_xlate_rule_add(xl, "add @connlimit%u { %s %s %sct count %s%u }",
+ connlimit_id++,
+ xt_xlate_get_family(xl) == AF_INET ? "ip" : "ip6",
+ info->flags & XT_CONNLIMIT_DADDR ? "daddr" : "saddr",
+ netmask,
+ info->flags & XT_CONNLIMIT_INVERT ? "" : "over ",
+ info->limit);
+
+ return 1;
+}
+
static struct xtables_match connlimit_mt_reg[] = {
{
.name = "connlimit",
@@ -228,6 +275,7 @@ static struct xtables_match connlimit_mt_reg[] = {
.print = connlimit_print4,
.save = connlimit_save4,
.x6_options = connlimit_opts,
+ .xlate = connlimit_xlate,
},
{
.name = "connlimit",
@@ -243,6 +291,7 @@ static struct xtables_match connlimit_mt_reg[] = {
.print = connlimit_print6,
.save = connlimit_save6,
.x6_options = connlimit_opts,
+ .xlate = connlimit_xlate,
},
};
diff --git a/extensions/libxt_connlimit.man b/extensions/libxt_connlimit.man
index ad9f40fa..aa7df2b2 100644
--- a/extensions/libxt_connlimit.man
+++ b/extensions/libxt_connlimit.man
@@ -20,23 +20,28 @@ Apply the limit onto the source group. This is the default if
Apply the limit onto the destination group.
.PP
Examples:
-.TP
-# allow 2 telnet connections per client host
+.IP \(bu 4
+allow 2 telnet connections per client host:
+.br
iptables \-A INPUT \-p tcp \-\-syn \-\-dport 23 \-m connlimit \-\-connlimit\-above 2 \-j REJECT
-.TP
-# you can also match the other way around:
+.IP \(bu 4
+you can also match the other way around:
+.br
iptables \-A INPUT \-p tcp \-\-syn \-\-dport 23 \-m connlimit \-\-connlimit\-upto 2 \-j ACCEPT
-.TP
-# limit the number of parallel HTTP requests to 16 per class C sized \
-source network (24 bit netmask)
+.IP \(bu 4
+limit the number of parallel HTTP requests to 16 per class C sized \
+source network (24 bit netmask):
+.br
iptables \-p tcp \-\-syn \-\-dport 80 \-m connlimit \-\-connlimit\-above 16
\-\-connlimit\-mask 24 \-j REJECT
-.TP
-# limit the number of parallel HTTP requests to 16 for the link local network
-(ipv6)
+.IP \(bu 4
+limit the number of parallel HTTP requests to 16 for the link local network
+(IPv6):
+.br
ip6tables \-p tcp \-\-syn \-\-dport 80 \-s fe80::/64 \-m connlimit \-\-connlimit\-above
16 \-\-connlimit\-mask 64 \-j REJECT
-.TP
-# Limit the number of connections to a particular host:
+.IP \(bu 4
+Limit the number of connections to a particular host:
+.br
ip6tables \-p tcp \-\-syn \-\-dport 49152:65535 \-d 2001:db8::1 \-m connlimit
-\-\-connlimit-above 100 \-j REJECT
+\-\-connlimit\-above 100 \-j REJECT
diff --git a/extensions/libxt_connlimit.t b/extensions/libxt_connlimit.t
index c7ea61e9..366cea74 100644
--- a/extensions/libxt_connlimit.t
+++ b/extensions/libxt_connlimit.t
@@ -1,11 +1,11 @@
:INPUT,FORWARD,OUTPUT
--m connlimit --connlimit-upto 0;=;OK
--m connlimit --connlimit-upto 4294967295;=;OK
--m connlimit --connlimit-upto 4294967296;;FAIL
+-m connlimit --connlimit-upto 0;-m connlimit --connlimit-upto 0 --connlimit-mask 32 --connlimit-saddr;OK
+-m connlimit --connlimit-upto 4294967295 --connlimit-mask 32 --connlimit-saddr;=;OK
+-m connlimit --connlimit-upto 4294967296 --connlimit-mask 32 --connlimit-saddr;;FAIL
-m connlimit --connlimit-upto -1;;FAIL
--m connlimit --connlimit-above 0;=;OK
--m connlimit --connlimit-above 4294967295;=;OK
--m connlimit --connlimit-above 4294967296;;FAIL
+-m connlimit --connlimit-above 0;-m connlimit --connlimit-above 0 --connlimit-mask 32 --connlimit-saddr;OK
+-m connlimit --connlimit-above 4294967295 --connlimit-mask 32 --connlimit-saddr;=;OK
+-m connlimit --connlimit-above 4294967296 --connlimit-mask 32 --connlimit-saddr;;FAIL
-m connlimit --connlimit-above -1;;FAIL
-m connlimit --connlimit-upto 1 --conlimit-above 1;;FAIL
-m connlimit --connlimit-above 10 --connlimit-saddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;OK
diff --git a/extensions/libxt_connlimit.txlate b/extensions/libxt_connlimit.txlate
new file mode 100644
index 00000000..3108a529
--- /dev/null
+++ b/extensions/libxt_connlimit.txlate
@@ -0,0 +1,15 @@
+iptables-translate -A INPUT -m connlimit --connlimit-above 2
+nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }'
+nft 'add rule ip filter INPUT add @connlimit0 { ip saddr ct count over 2 } counter'
+
+iptables-translate -A INPUT -m connlimit --connlimit-upto 2
+nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }'
+nft 'add rule ip filter INPUT add @connlimit0 { ip saddr ct count 2 } counter'
+
+iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-mask 24
+nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }'
+nft 'add rule ip filter INPUT add @connlimit0 { ip saddr and 255.255.255.0 ct count 2 } counter'
+
+iptables-translate -A INPUT -m connlimit --connlimit-upto 2 --connlimit-daddr
+nft 'add set ip filter connlimit0 { type ipv4_addr; flags dynamic; }'
+nft 'add rule ip filter INPUT add @connlimit0 { ip daddr ct count 2 } counter'
diff --git a/extensions/libxt_connmark.t b/extensions/libxt_connmark.t
index 4dd7d9af..353970a8 100644
--- a/extensions/libxt_connmark.t
+++ b/extensions/libxt_connmark.t
@@ -2,8 +2,8 @@
*mangle
-m connmark --mark 0xffffffff;=;OK
-m connmark --mark 0xffffffff/0xffffffff;-m connmark --mark 0xffffffff;OK
--m connmark --mark 0xffffffff/0;=;OK
--m connmark --mark 0/0xffffffff;-m connmark --mark 0;OK
+-m connmark --mark 0xffffffff/0x0;=;OK
+-m connmark --mark 0/0xffffffff;-m connmark --mark 0x0;OK
-m connmark --mark -1;;FAIL
-m connmark --mark 0xfffffffff;;FAIL
-m connmark;;FAIL
diff --git a/extensions/libxt_connmark.txlate b/extensions/libxt_connmark.txlate
index 89423259..e7bfd721 100644
--- a/extensions/libxt_connmark.txlate
+++ b/extensions/libxt_connmark.txlate
@@ -1,14 +1,14 @@
iptables-translate -A INPUT -m connmark --mark 2 -j ACCEPT
-nft add rule ip filter INPUT ct mark 0x2 counter accept
+nft 'add rule ip filter INPUT ct mark 0x2 counter accept'
iptables-translate -A INPUT -m connmark ! --mark 2 -j ACCEPT
-nft add rule ip filter INPUT ct mark != 0x2 counter accept
+nft 'add rule ip filter INPUT ct mark != 0x2 counter accept'
iptables-translate -A INPUT -m connmark --mark 10/10 -j ACCEPT
-nft add rule ip filter INPUT ct mark and 0xa == 0xa counter accept
+nft 'add rule ip filter INPUT ct mark and 0xa == 0xa counter accept'
iptables-translate -A INPUT -m connmark ! --mark 10/10 -j ACCEPT
-nft add rule ip filter INPUT ct mark and 0xa != 0xa counter accept
+nft 'add rule ip filter INPUT ct mark and 0xa != 0xa counter accept'
iptables-translate -t mangle -A PREROUTING -p tcp --dport 40 -m connmark --mark 0x40
-nft add rule ip mangle PREROUTING tcp dport 40 ct mark 0x40 counter
+nft 'add rule ip mangle PREROUTING tcp dport 40 ct mark 0x40 counter'
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 7734509c..ffbc7467 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -346,14 +346,13 @@ static void conntrack_parse(struct xt_option_call *cb)
sinfo->invflags |= XT_CONNTRACK_STATE;
break;
case O_CTPROTO:
+ if (cb->val.protocol == 0)
+ xtables_error(PARAMETER_PROBLEM, cb->invert ?
+ "condition would always match protocol" :
+ "rule would never match protocol");
sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = cb->val.protocol;
if (cb->invert)
sinfo->invflags |= XT_CONNTRACK_PROTO;
- if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0
- && (sinfo->invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
-
sinfo->flags |= XT_CONNTRACK_PROTO;
break;
case O_CTORIGSRC:
@@ -411,11 +410,11 @@ static void conntrack_mt_parse(struct xt_option_call *cb, uint8_t rev)
info->invert_flags |= XT_CONNTRACK_STATE;
break;
case O_CTPROTO:
+ if (cb->val.protocol == 0)
+ xtables_error(PARAMETER_PROBLEM, cb->invert ?
+ "conntrack: condition would always match protocol" :
+ "conntrack: rule would never match protocol");
info->l4proto = cb->val.protocol;
- if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM, "conntrack: rule would "
- "never match protocol");
-
info->match_flags |= XT_CONNTRACK_PROTO;
if (cb->invert)
info->invert_flags |= XT_CONNTRACK_PROTO;
@@ -778,7 +777,7 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric,
static void
conntrack_dump_ports(const char *prefix, const char *opt,
- u_int16_t port_low, u_int16_t port_high)
+ uint16_t port_low, uint16_t port_high)
{
if (port_high == 0 || port_low == port_high)
printf(" %s%s %u", prefix, opt, port_low);
@@ -1148,10 +1147,13 @@ static void state_save(const void *ip, const struct xt_entry_match *match)
state_print_state(sinfo->statemask);
}
-static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask)
+static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask, int inverted)
{
const char *sep = "";
+ if (inverted)
+ xt_xlate_add(xl, "! ");
+
if (statemask & XT_CONNTRACK_STATE_INVALID) {
xt_xlate_add(xl, "%s%s", sep, "invalid");
sep = ",";
@@ -1180,17 +1182,19 @@ static int state_xlate(struct xt_xlate *xl,
const struct xt_conntrack_mtinfo3 *sinfo =
(const void *)params->match->data;
- xt_xlate_add(xl, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
- xt_xlate_add(xl, " ");
+ xt_xlate_add(xl, "ct state ");
+ state_xlate_print(xl, sinfo->state_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATE);
return 1;
}
-static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask)
+static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask, int inverted)
{
const char *sep = "";
+ if (inverted)
+ xt_xlate_add(xl, "! ");
+
if (statusmask & IPS_EXPECTED) {
xt_xlate_add(xl, "%s%s", sep, "expected");
sep = ",";
@@ -1256,19 +1260,17 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
sinfo->state_mask & XT_CONNTRACK_STATE_SNAT ? "snat" : "dnat");
space = " ";
} else {
- xt_xlate_add(xl, "%sct state %s", space,
- sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
+ xt_xlate_add(xl, "%sct state ", space);
+ state_xlate_print(xl, sinfo->state_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATE);
space = " ";
}
}
if (sinfo->match_flags & XT_CONNTRACK_STATUS) {
- xt_xlate_add(xl, "%sct status %s", space,
- sinfo->invert_flags & XT_CONNTRACK_STATUS ?
- "!= " : "");
- status_xlate_print(xl, sinfo->status_mask);
+ xt_xlate_add(xl, "%sct status ", space);
+ status_xlate_print(xl, sinfo->status_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATUS);
space = " ";
}
@@ -1285,9 +1287,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC) {
- if (&sinfo->origsrc_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct original saddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_ORIGSRC ?
"!= " : "");
@@ -1297,9 +1296,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_ORIGDST) {
- if (&sinfo->origdst_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct original daddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_ORIGDST ?
"!= " : "");
@@ -1309,9 +1305,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_REPLSRC) {
- if (&sinfo->replsrc_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct reply saddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_REPLSRC ?
"!= " : "");
@@ -1321,9 +1314,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_REPLDST) {
- if (&sinfo->repldst_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct reply daddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_REPLDST ?
"!= " : "");
diff --git a/extensions/libxt_conntrack.t b/extensions/libxt_conntrack.t
index db531475..5e27ddce 100644
--- a/extensions/libxt_conntrack.t
+++ b/extensions/libxt_conntrack.t
@@ -17,6 +17,8 @@
-m conntrack --ctexpire 0:4294967295;=;OK
-m conntrack --ctexpire 42949672956;;FAIL
-m conntrack --ctexpire -1;;FAIL
+-m conntrack --ctexpire 3:3;-m conntrack --ctexpire 3;OK
+-m conntrack --ctexpire 4:3;;FAIL
-m conntrack --ctdir ORIGINAL;=;OK
-m conntrack --ctdir REPLY;=;OK
-m conntrack --ctstatus NONE;=;OK
@@ -25,3 +27,29 @@
-m conntrack --ctstatus EXPECTED;=;OK
-m conntrack --ctstatus SEEN_REPLY;=;OK
-m conntrack;;FAIL
+-m conntrack --ctproto 0;;FAIL
+-m conntrack ! --ctproto 0;;FAIL
+-m conntrack --ctorigsrcport :;-m conntrack --ctorigsrcport 0:65535;OK
+-m conntrack --ctorigsrcport :4;-m conntrack --ctorigsrcport 0:4;OK
+-m conntrack --ctorigsrcport 4:;-m conntrack --ctorigsrcport 4:65535;OK
+-m conntrack --ctorigsrcport 3:4;=;OK
+-m conntrack --ctorigsrcport 4:4;-m conntrack --ctorigsrcport 4;OK
+-m conntrack --ctorigsrcport 4:3;;FAIL
+-m conntrack --ctreplsrcport :;-m conntrack --ctreplsrcport 0:65535;OK
+-m conntrack --ctreplsrcport :4;-m conntrack --ctreplsrcport 0:4;OK
+-m conntrack --ctreplsrcport 4:;-m conntrack --ctreplsrcport 4:65535;OK
+-m conntrack --ctreplsrcport 3:4;=;OK
+-m conntrack --ctreplsrcport 4:4;-m conntrack --ctreplsrcport 4;OK
+-m conntrack --ctreplsrcport 4:3;;FAIL
+-m conntrack --ctorigdstport :;-m conntrack --ctorigdstport 0:65535;OK
+-m conntrack --ctorigdstport :4;-m conntrack --ctorigdstport 0:4;OK
+-m conntrack --ctorigdstport 4:;-m conntrack --ctorigdstport 4:65535;OK
+-m conntrack --ctorigdstport 3:4;=;OK
+-m conntrack --ctorigdstport 4:4;-m conntrack --ctorigdstport 4;OK
+-m conntrack --ctorigdstport 4:3;;FAIL
+-m conntrack --ctrepldstport :;-m conntrack --ctrepldstport 0:65535;OK
+-m conntrack --ctrepldstport :4;-m conntrack --ctrepldstport 0:4;OK
+-m conntrack --ctrepldstport 4:;-m conntrack --ctrepldstport 4:65535;OK
+-m conntrack --ctrepldstport 3:4;=;OK
+-m conntrack --ctrepldstport 4:4;-m conntrack --ctrepldstport 4;OK
+-m conntrack --ctrepldstport 4:3;;FAIL
diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate
index d374f8a0..0f44a957 100644
--- a/extensions/libxt_conntrack.txlate
+++ b/extensions/libxt_conntrack.txlate
@@ -1,51 +1,60 @@
iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCEPT
-nft add rule ip filter INPUT ct state new,related counter accept
+nft 'add rule ip filter INPUT ct state new,related counter accept'
ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT
-nft add rule ip6 filter INPUT ct state != new,related counter accept
+nft 'add rule ip6 filter INPUT ct state ! new,related counter accept'
+
+ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW -j ACCEPT
+nft 'add rule ip6 filter INPUT ct state ! new counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT
-nft add rule ip filter INPUT ct original protocol 17 counter accept
+nft 'add rule ip filter INPUT ct original protocol 17 counter accept'
iptables-translate -t filter -A INPUT -m conntrack ! --ctproto UDP -j ACCEPT
-nft add rule ip filter INPUT ct original protocol != 17 counter accept
+nft 'add rule ip filter INPUT ct original protocol != 17 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.2.131 -j ACCEPT
-nft add rule ip filter INPUT ct original saddr 10.100.2.131 counter accept
+nft 'add rule ip filter INPUT ct original saddr 10.100.2.131 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.0.0/255.255.0.0 -j ACCEPT
-nft add rule ip filter INPUT ct original saddr 10.100.0.0/16 counter accept
+nft 'add rule ip filter INPUT ct original saddr 10.100.0.0/16 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctorigdst 10.100.2.131 -j ACCEPT
-nft add rule ip filter INPUT ct original daddr 10.100.2.131 counter accept
+nft 'add rule ip filter INPUT ct original daddr 10.100.2.131 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctreplsrc 10.100.2.131 -j ACCEPT
-nft add rule ip filter INPUT ct reply saddr 10.100.2.131 counter accept
+nft 'add rule ip filter INPUT ct reply saddr 10.100.2.131 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctrepldst 10.100.2.131 -j ACCEPT
-nft add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept
+nft 'add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctproto tcp --ctorigsrcport 443:444 -j ACCEPT
-nft add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept
+nft 'add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctstatus EXPECTED -j ACCEPT
-nft add rule ip filter INPUT ct status expected counter accept
+nft 'add rule ip filter INPUT ct status expected counter accept'
iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED -j ACCEPT
-nft add rule ip filter INPUT ct status != confirmed counter accept
+nft 'add rule ip filter INPUT ct status ! confirmed counter accept'
+
+iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED,ASSURED -j ACCEPT
+nft 'add rule ip filter INPUT ct status ! assured,confirmed counter accept'
+
+iptables-translate -t filter -A INPUT -m conntrack --ctstatus CONFIRMED,ASSURED -j ACCEPT
+nft 'add rule ip filter INPUT ct status assured,confirmed counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctexpire 3 -j ACCEPT
-nft add rule ip filter INPUT ct expiration 3 counter accept
+nft 'add rule ip filter INPUT ct expiration 3 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctdir ORIGINAL -j ACCEPT
-nft add rule ip filter INPUT ct direction original counter accept
+nft 'add rule ip filter INPUT ct direction original counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.0.1 --ctorigdst 192.168.0.1 --ctreplsrc 192.168.0.1 --ctrepldst 192.168.0.1 --ctorigsrcport 12 --ctorigdstport 14 --ctreplsrcport 16 --ctrepldstport 18 --ctexpire 10 --ctstatus SEEN_REPLY --ctdir ORIGINAL -j ACCEPT
-nft add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept
+nft 'add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctstate SNAT -j ACCEPT
-nft add rule ip filter INPUT ct status snat counter accept
+nft 'add rule ip filter INPUT ct status snat counter accept'
iptables-translate -t filter -A INPUT -m conntrack --ctstate DNAT -j ACCEPT
-nft add rule ip filter INPUT ct status dnat counter accept
+nft 'add rule ip filter INPUT ct status dnat counter accept'
diff --git a/extensions/libxt_cpu.man b/extensions/libxt_cpu.man
index d9ea5c2f..158d50cb 100644
--- a/extensions/libxt_cpu.man
+++ b/extensions/libxt_cpu.man
@@ -1,15 +1,15 @@
.TP
[\fB!\fP] \fB\-\-cpu\fP \fInumber\fP
-Match cpu handling this packet. cpus are numbered from 0 to NR_CPUS-1
+Match cpu handling this packet. cpus are numbered from 0 to NR_CPUS\-1
Can be used in combination with RPS (Remote Packet Steering) or
multiqueue NICs to spread network traffic on different queues.
.PP
Example:
.PP
iptables \-t nat \-A PREROUTING \-p tcp \-\-dport 80 \-m cpu \-\-cpu 0
-\-j REDIRECT \-\-to\-port 8080
+\-j REDIRECT \-\-to\-ports 8080
.PP
iptables \-t nat \-A PREROUTING \-p tcp \-\-dport 80 \-m cpu \-\-cpu 1
-\-j REDIRECT \-\-to\-port 8081
+\-j REDIRECT \-\-to\-ports 8081
.PP
Available since Linux 2.6.36.
diff --git a/extensions/libxt_cpu.txlate b/extensions/libxt_cpu.txlate
index c59b0e02..937c939e 100644
--- a/extensions/libxt_cpu.txlate
+++ b/extensions/libxt_cpu.txlate
@@ -1,5 +1,5 @@
iptables-translate -A INPUT -p tcp --dport 80 -m cpu --cpu 0 -j ACCEPT
-nft add rule ip filter INPUT tcp dport 80 cpu 0 counter accept
+nft 'add rule ip filter INPUT tcp dport 80 cpu 0 counter accept'
iptables-translate -A INPUT -p tcp --dport 80 -m cpu ! --cpu 1 -j ACCEPT
-nft add rule ip filter INPUT tcp dport 80 cpu != 1 counter accept
+nft 'add rule ip filter INPUT tcp dport 80 cpu != 1 counter accept'
diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c
index 5e67c264..bfceced3 100644
--- a/extensions/libxt_dccp.c
+++ b/extensions/libxt_dccp.c
@@ -76,13 +76,16 @@ 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)
{
uint16_t typemask = 0;
char *ptr, *buffer;
- buffer = strdup(typestring);
+ buffer = xtables_strdup(typestring);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
unsigned int i;
@@ -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, "{");
@@ -332,37 +343,33 @@ static int dccp_xlate(struct xt_xlate *xl,
{
const struct xt_dccp_info *einfo =
(const struct xt_dccp_info *)params->match->data;
- 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]);
- space = " ";
+ xt_xlate_add(xl, "-%u", einfo->spts[1]);
}
if (einfo->flags & XT_DCCP_DEST_PORTS) {
+ xt_xlate_add(xl, "dccp dport%s %u",
+ 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]);
}
- if (einfo->flags & XT_DCCP_TYPE)
+ if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) {
+ xt_xlate_add(xl, "dccp type%s ",
+ einfo->invflags & XT_DCCP_TYPE ? " !=" : "");
ret = dccp_type_xlate(einfo, xl);
+ }
+ /* FIXME: no dccp option support in nftables yet */
if (einfo->flags & XT_DCCP_OPTION)
ret = 0;
diff --git a/extensions/libxt_dccp.t b/extensions/libxt_dccp.t
index f60b480f..3655ab6f 100644
--- a/extensions/libxt_dccp.t
+++ b/extensions/libxt_dccp.t
@@ -6,6 +6,16 @@
-p dccp -m dccp --sport 1:1023;=;OK
-p dccp -m dccp --sport 1024:65535;=;OK
-p dccp -m dccp --sport 1024:;-p dccp -m dccp --sport 1024:65535;OK
+-p dccp -m dccp --sport :;-p dccp -m dccp --sport 0:65535;OK
+-p dccp -m dccp --sport :4;-p dccp -m dccp --sport 0:4;OK
+-p dccp -m dccp --sport 4:;-p dccp -m dccp --sport 4:65535;OK
+-p dccp -m dccp --sport 4:4;-p dccp -m dccp --sport 4;OK
+-p dccp -m dccp --sport 4:3;;FAIL
+-p dccp -m dccp --dport :;-p dccp -m dccp --dport 0:65535;OK
+-p dccp -m dccp --dport :4;-p dccp -m dccp --dport 0:4;OK
+-p dccp -m dccp --dport 4:;-p dccp -m dccp --dport 4:65535;OK
+-p dccp -m dccp --dport 4:4;-p dccp -m dccp --dport 4;OK
+-p dccp -m dccp --dport 4:3;;FAIL
-p dccp -m dccp ! --sport 1;=;OK
-p dccp -m dccp ! --sport 65535;=;OK
-p dccp -m dccp ! --dport 1;=;OK
diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate
index b47dc65f..a4da1a79 100644
--- a/extensions/libxt_dccp.txlate
+++ b/extensions/libxt_dccp.txlate
@@ -1,14 +1,20 @@
iptables-translate -A INPUT -p dccp -m dccp --sport 100
-nft add rule ip filter INPUT dccp sport 100 counter
+nft 'add rule ip filter INPUT dccp sport 100 counter'
iptables-translate -A INPUT -p dccp -m dccp --dport 100:200
-nft add rule ip filter INPUT dccp dport 100-200 counter
+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
+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_devgroup.c b/extensions/libxt_devgroup.c
index a88211c5..f60526ff 100644
--- a/extensions/libxt_devgroup.c
+++ b/extensions/libxt_devgroup.c
@@ -129,7 +129,6 @@ static void devgroup_show_xlate(const struct xt_devgroup_info *info,
struct xt_xlate *xl, int numeric)
{
enum xt_op op = XT_OP_EQ;
- char *space = "";
if (info->flags & XT_DEVGROUP_MATCH_SRC) {
if (info->flags & XT_DEVGROUP_INVERT_SRC)
@@ -137,13 +136,12 @@ static void devgroup_show_xlate(const struct xt_devgroup_info *info,
xt_xlate_add(xl, "iifgroup ");
print_devgroup_xlate(info->src_group, op,
info->src_mask, xl, numeric);
- space = " ";
}
if (info->flags & XT_DEVGROUP_MATCH_DST) {
if (info->flags & XT_DEVGROUP_INVERT_DST)
op = XT_OP_NEQ;
- xt_xlate_add(xl, "%soifgroup ", space);
+ xt_xlate_add(xl, "oifgroup ");
print_devgroup_xlate(info->dst_group, op,
info->dst_mask, xl, numeric);
}
diff --git a/extensions/libxt_devgroup.man b/extensions/libxt_devgroup.man
index 4a66c9fe..480ee351 100644
--- a/extensions/libxt_devgroup.man
+++ b/extensions/libxt_devgroup.man
@@ -1,4 +1,4 @@
-Match device group of a packets incoming/outgoing interface.
+Match device group of a packet's incoming/outgoing interface.
.TP
[\fB!\fP] \fB\-\-src\-group\fP \fIname\fP
Match device group of incoming device
diff --git a/extensions/libxt_devgroup.txlate b/extensions/libxt_devgroup.txlate
index aeb597bd..dea47a99 100644
--- a/extensions/libxt_devgroup.txlate
+++ b/extensions/libxt_devgroup.txlate
@@ -1,17 +1,17 @@
iptables-translate -A FORWARD -m devgroup --src-group 0x2 -j ACCEPT
-nft add rule ip filter FORWARD iifgroup 0x2 counter accept
+nft 'add rule ip filter FORWARD iifgroup 0x2 counter accept'
iptables-translate -A FORWARD -m devgroup --dst-group 0xc/0xc -j ACCEPT
-nft add rule ip filter FORWARD oifgroup and 0xc == 0xc counter accept
+nft 'add rule ip filter FORWARD oifgroup and 0xc == 0xc counter accept'
iptables-translate -t mangle -A PREROUTING -p tcp --dport 46000 -m devgroup --src-group 23 -j ACCEPT
-nft add rule ip mangle PREROUTING tcp dport 46000 iifgroup 0x17 counter accept
+nft 'add rule ip mangle PREROUTING tcp dport 46000 iifgroup 0x17 counter accept'
iptables-translate -A FORWARD -m devgroup ! --dst-group 0xc/0xc -j ACCEPT
-nft add rule ip filter FORWARD oifgroup and 0xc != 0xc counter accept
+nft 'add rule ip filter FORWARD oifgroup and 0xc != 0xc counter accept'
iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 -j ACCEPT
-nft add rule ip filter FORWARD iifgroup != 0x2 counter accept
+nft 'add rule ip filter FORWARD iifgroup != 0x2 counter accept'
iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 --dst-group 0xc/0xc -j ACCEPT
-nft add rule ip filter FORWARD iifgroup != 0x2 oifgroup and 0xc != 0xc counter accept
+nft 'add rule ip filter FORWARD iifgroup != 0x2 oifgroup and 0xc != 0xc counter accept'
diff --git a/extensions/libxt_dscp.man b/extensions/libxt_dscp.man
index 63a17dac..ff4523fd 100644
--- a/extensions/libxt_dscp.man
+++ b/extensions/libxt_dscp.man
@@ -2,7 +2,7 @@ This module matches the 6 bit DSCP field within the TOS field in the
IP header. DSCP has superseded TOS within the IETF.
.TP
[\fB!\fP] \fB\-\-dscp\fP \fIvalue\fP
-Match against a numeric (decimal or hex) value [0-63].
+Match against a numeric (decimal or hex) value in the range 0\(en63.
.TP
[\fB!\fP] \fB\-\-dscp\-class\fP \fIclass\fP
Match the DiffServ class. This value may be any of the
diff --git a/extensions/libxt_dscp.t b/extensions/libxt_dscp.t
index 38d7f04e..e0101906 100644
--- a/extensions/libxt_dscp.t
+++ b/extensions/libxt_dscp.t
@@ -1,5 +1,5 @@
:INPUT,FORWARD,OUTPUT
--m dscp --dscp 0;=;OK
+-m dscp --dscp 0x00;=;OK
-m dscp --dscp 0x3f;=;OK
-m dscp --dscp -1;;FAIL
-m dscp --dscp 0x40;;FAIL
diff --git a/extensions/libxt_dscp.txlate b/extensions/libxt_dscp.txlate
index 2cccc3b4..ca2ec724 100644
--- a/extensions/libxt_dscp.txlate
+++ b/extensions/libxt_dscp.txlate
@@ -1,5 +1,5 @@
iptables-translate -t filter -A INPUT -m dscp --dscp 0x32 -j ACCEPT
-nft add rule ip filter INPUT ip dscp 0x32 counter accept
+nft 'add rule ip filter INPUT ip dscp 0x32 counter accept'
ip6tables-translate -t filter -A INPUT -m dscp ! --dscp 0x32 -j ACCEPT
-nft add rule ip6 filter INPUT ip6 dscp != 0x32 counter accept
+nft 'add rule ip6 filter INPUT ip6 dscp != 0x32 counter accept'
diff --git a/extensions/libxt_ecn.c b/extensions/libxt_ecn.c
index ad3c7a03..83a4acfa 100644
--- a/extensions/libxt_ecn.c
+++ b/extensions/libxt_ecn.c
@@ -156,6 +156,8 @@ static int ecn_xlate(struct xt_xlate *xl,
case 3:
xt_xlate_add(xl, "ce");
break;
+ default:
+ return 0;
}
}
return 1;
diff --git a/extensions/libxt_ecn.txlate b/extensions/libxt_ecn.txlate
index f012f128..8488f8ce 100644
--- a/extensions/libxt_ecn.txlate
+++ b/extensions/libxt_ecn.txlate
@@ -1,29 +1,29 @@
iptables-translate -A INPUT -m ecn --ecn-ip-ect 0
-nft add rule ip filter INPUT ip ecn not-ect counter
+nft 'add rule ip filter INPUT ip ecn not-ect counter'
iptables-translate -A INPUT -m ecn --ecn-ip-ect 1
-nft add rule ip filter INPUT ip ecn ect1 counter
+nft 'add rule ip filter INPUT ip ecn ect1 counter'
iptables-translate -A INPUT -m ecn --ecn-ip-ect 2
-nft add rule ip filter INPUT ip ecn ect0 counter
+nft 'add rule ip filter INPUT ip ecn ect0 counter'
iptables-translate -A INPUT -m ecn --ecn-ip-ect 3
-nft add rule ip filter INPUT ip ecn ce counter
+nft 'add rule ip filter INPUT ip ecn ce counter'
iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 0
-nft add rule ip filter INPUT ip ecn != not-ect counter
+nft 'add rule ip filter INPUT ip ecn != not-ect counter'
iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 1
-nft add rule ip filter INPUT ip ecn != ect1 counter
+nft 'add rule ip filter INPUT ip ecn != ect1 counter'
iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 2
-nft add rule ip filter INPUT ip ecn != ect0 counter
+nft 'add rule ip filter INPUT ip ecn != ect0 counter'
iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 3
-nft add rule ip filter INPUT ip ecn != ce counter
+nft 'add rule ip filter INPUT ip ecn != ce counter'
iptables-translate -A INPUT -m ecn ! --ecn-tcp-ece
-nft add rule ip filter INPUT tcp flags != ecn counter
+nft 'add rule ip filter INPUT tcp flags != ecn counter'
iptables-translate -A INPUT -m ecn --ecn-tcp-cwr
-nft add rule ip filter INPUT tcp flags cwr counter
+nft 'add rule ip filter INPUT tcp flags cwr counter'
diff --git a/extensions/libxt_esp.c b/extensions/libxt_esp.c
index 2c7ff942..8e9766d7 100644
--- a/extensions/libxt_esp.c
+++ b/extensions/libxt_esp.c
@@ -39,13 +39,18 @@ static void esp_parse(struct xt_option_call *cb)
espinfo->invflags |= XT_ESP_INV_SPI;
}
+static bool skip_spis_match(uint32_t min, uint32_t max, bool inv)
+{
+ return min == 0 && max == UINT32_MAX && !inv;
+}
+
static void
print_spis(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFFFFFFFF || invert) {
+ if (!skip_spis_match(min, max, invert)) {
if (min == max)
printf(" %s:%s%u", name, inv, min);
else
@@ -69,11 +74,10 @@ esp_print(const void *ip, const struct xt_entry_match *match, int numeric)
static void esp_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_esp *espinfo = (struct xt_esp *)match->data;
+ bool inv_spi = espinfo->invflags & XT_ESP_INV_SPI;
- if (!(espinfo->spis[0] == 0
- && espinfo->spis[1] == 0xFFFFFFFF)) {
- printf("%s --espspi ",
- (espinfo->invflags & XT_ESP_INV_SPI) ? " !" : "");
+ if (!skip_spis_match(espinfo->spis[0], espinfo->spis[1], inv_spi)) {
+ printf("%s --espspi ", inv_spi ? " !" : "");
if (espinfo->spis[0]
!= espinfo->spis[1])
printf("%u:%u",
@@ -90,15 +94,21 @@ static int esp_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct xt_esp *espinfo = (struct xt_esp *)params->match->data;
+ bool inv_spi = espinfo->invflags & XT_ESP_INV_SPI;
- if (!(espinfo->spis[0] == 0 && espinfo->spis[1] == 0xFFFFFFFF)) {
- xt_xlate_add(xl, "esp spi%s",
- (espinfo->invflags & XT_ESP_INV_SPI) ? " !=" : "");
+ if (!skip_spis_match(espinfo->spis[0], espinfo->spis[1], inv_spi)) {
+ xt_xlate_add(xl, "esp spi%s", inv_spi ? " !=" : "");
if (espinfo->spis[0] != espinfo->spis[1])
xt_xlate_add(xl, " %u-%u", espinfo->spis[0],
espinfo->spis[1]);
else
xt_xlate_add(xl, " %u", espinfo->spis[0]);
+ } else if (afinfo->family == NFPROTO_IPV4) {
+ xt_xlate_add(xl, "meta l4proto esp");
+ } else if (afinfo->family == NFPROTO_IPV6) {
+ xt_xlate_add(xl, "exthdr esp exists");
+ } else {
+ return 0;
}
return 1;
diff --git a/extensions/libxt_esp.t b/extensions/libxt_esp.t
index 92c5779f..ece131c9 100644
--- a/extensions/libxt_esp.t
+++ b/extensions/libxt_esp.t
@@ -4,5 +4,12 @@
-p esp -m esp --espspi 0:4294967295;-p esp -m esp;OK
-p esp -m esp ! --espspi 0:4294967294;=;OK
-p esp -m esp --espspi -1;;FAIL
+-p esp -m esp --espspi :;-p esp -m esp;OK
+-p esp -m esp ! --espspi :;-p esp -m esp ! --espspi 0:4294967295;OK
+-p esp -m esp --espspi :4;-p esp -m esp --espspi 0:4;OK
+-p esp -m esp --espspi 4:;-p esp -m esp --espspi 4:4294967295;OK
+-p esp -m esp --espspi 3:4;=;OK
+-p esp -m esp --espspi 4:4;-p esp -m esp --espspi 4;OK
+-p esp -m esp --espspi 4:3;;FAIL
-p esp -m esp;=;OK
-m esp;;FAIL
diff --git a/extensions/libxt_esp.txlate b/extensions/libxt_esp.txlate
index 5e2f18fa..5e8fb241 100644
--- a/extensions/libxt_esp.txlate
+++ b/extensions/libxt_esp.txlate
@@ -1,11 +1,23 @@
iptables-translate -A FORWARD -p esp -j ACCEPT
-nft add rule ip filter FORWARD ip protocol esp counter accept
+nft 'add rule ip filter FORWARD ip protocol esp counter accept'
iptables-translate -A INPUT --in-interface wan --protocol esp -j ACCEPT
-nft add rule ip filter INPUT iifname "wan" ip protocol esp counter accept
+nft 'add rule ip filter INPUT iifname "wan" ip protocol esp counter accept'
iptables-translate -A INPUT -p 50 -m esp --espspi 500 -j DROP
-nft add rule ip filter INPUT esp spi 500 counter drop
+nft 'add rule ip filter INPUT esp spi 500 counter drop'
iptables-translate -A INPUT -p 50 -m esp --espspi 500:600 -j DROP
-nft add rule ip filter INPUT esp spi 500-600 counter drop
+nft 'add rule ip filter INPUT esp spi 500-600 counter drop'
+
+iptables-translate -A INPUT -p 50 -m esp --espspi 0:4294967295 -j DROP
+nft 'add rule ip filter INPUT meta l4proto esp counter drop'
+
+iptables-translate -A INPUT -p 50 -m esp ! --espspi 0:4294967295 -j DROP
+nft 'add rule ip filter INPUT esp spi != 0-4294967295 counter drop'
+
+ip6tables-translate -A INPUT -p 50 -m esp --espspi 0:4294967295 -j DROP
+nft 'add rule ip6 filter INPUT exthdr esp exists counter drop'
+
+ip6tables-translate -A INPUT -p 50 -m esp ! --espspi 0:4294967295 -j DROP
+nft 'add rule ip6 filter INPUT esp spi != 0-4294967295 counter drop'
diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c
index 7f1d2a40..24e784ab 100644
--- a/extensions/libxt_hashlimit.c
+++ b/extensions/libxt_hashlimit.c
@@ -356,12 +356,12 @@ static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata *
tmp = (uint64_t) r * factor;
if (tmp > max)
xtables_error(PARAMETER_PROBLEM,
- "Rate value too large \"%"PRIu64"\" (max %"PRIu64")\n",
- tmp, max);
+ "Rate value too large \"%"PRIu64"\" (max %"PRIu64")",
+ tmp, max);
tmp = bytes_to_cost(tmp);
if (tmp == 0)
- xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
+ xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"", rate);
ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
@@ -407,7 +407,7 @@ int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int r
* The rate maps to infinity. (1/day is the minimum they can
* specify, so we are ok at that end).
*/
- xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
+ xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"", rate);
if(revision == 1)
*((uint32_t*)val) = tmp;
@@ -508,10 +508,7 @@ static void hashlimit_mt6_init(struct xt_entry_match *match)
static int parse_mode(uint32_t *mode, const char *option_arg)
{
char *tok;
- char *arg = strdup(option_arg);
-
- if (!arg)
- return -1;
+ char *arg = xtables_strdup(option_arg);
for (tok = strtok(arg, ",|");
tok;
@@ -1273,7 +1270,7 @@ static void hashlimit_print_subnet_xlate(struct xt_xlate *xl,
}
}
- xt_xlate_add(xl, fmt, acm);
+ xt_xlate_add_nospc(xl, fmt, acm);
if (nblocks > 0)
xt_xlate_add(xl, "%c", sep);
}
diff --git a/extensions/libxt_hashlimit.man b/extensions/libxt_hashlimit.man
index 8a35d564..b95a52d2 100644
--- a/extensions/libxt_hashlimit.man
+++ b/extensions/libxt_hashlimit.man
@@ -20,7 +20,7 @@ Maximum initial number of packets to match: this number gets recharged by one
every time the limit specified above is not reached, up to this number; the
default is 5. When byte-based rate matching is requested, this option specifies
the amount of bytes that can exceed the given rate. This option should be used
-with caution -- if the entry expires, the burst value is reset too.
+with caution \(em if the entry expires, the burst value is reset too.
.TP
\fB\-\-hashlimit\-mode\fP {\fBsrcip\fP|\fBsrcport\fP|\fBdstip\fP|\fBdstport\fP}\fB,\fP...
A comma-separated list of objects to take into consideration. If no
@@ -77,8 +77,8 @@ in 10.0.0.0/8" =>
.TP
matching bytes per second
"flows exceeding 512kbyte/s" =>
-\-\-hashlimit-mode srcip,dstip,srcport,dstport \-\-hashlimit\-above 512kb/s
+\-\-hashlimit\-mode srcip,dstip,srcport,dstport \-\-hashlimit\-above 512kb/s
.TP
matching bytes per second
"hosts that exceed 512kbyte/s, but permit up to 1Megabytes without matching"
-\-\-hashlimit-mode dstip \-\-hashlimit\-above 512kb/s \-\-hashlimit-burst 1mb
+\-\-hashlimit\-mode dstip \-\-hashlimit\-above 512kb/s \-\-hashlimit\-burst 1mb
diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t
index ccd0d1e6..206d9293 100644
--- a/extensions/libxt_hashlimit.t
+++ b/extensions/libxt_hashlimit.t
@@ -3,14 +3,12 @@
-m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
--m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-above 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
--m hashlimit --hashlimit-upto 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
diff --git a/extensions/libxt_hashlimit.txlate b/extensions/libxt_hashlimit.txlate
index 6c8d07f1..306ee783 100644
--- a/extensions/libxt_hashlimit.txlate
+++ b/extensions/libxt_hashlimit.txlate
@@ -1,5 +1,5 @@
iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-above 20kb/s --hashlimit-burst 1mb --hashlimit-mode dstip --hashlimit-name https --hashlimit-dstmask 24 -m state --state NEW -j DROP
-nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes} ct state new counter drop
+nft 'add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes } ct state new counter drop'
iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-upto 300 --hashlimit-burst 15 --hashlimit-mode srcip,dstip --hashlimit-name https --hashlimit-htable-expire 300000 -m state --state NEW -j DROP
-nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets} ct state new counter drop
+nft 'add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets } ct state new counter drop'
diff --git a/extensions/libxt_helper.c b/extensions/libxt_helper.c
index 2afbf996..0f72eec6 100644
--- a/extensions/libxt_helper.c
+++ b/extensions/libxt_helper.c
@@ -50,12 +50,8 @@ static int helper_xlate(struct xt_xlate *xl,
{
const struct xt_helper_info *info = (const void *)params->match->data;
- if (params->escape_quotes)
- xt_xlate_add(xl, "ct helper%s \\\"%s\\\"",
- info->invert ? " !=" : "", info->name);
- else
- xt_xlate_add(xl, "ct helper%s \"%s\"",
- info->invert ? " !=" : "", info->name);
+ xt_xlate_add(xl, "ct helper%s \"%s\"",
+ info->invert ? " !=" : "", info->name);
return 1;
}
diff --git a/extensions/libxt_helper.man b/extensions/libxt_helper.man
index 772b1350..fb8a206c 100644
--- a/extensions/libxt_helper.man
+++ b/extensions/libxt_helper.man
@@ -1,11 +1,11 @@
-This module matches packets related to a specific conntrack-helper.
+This module matches packets related to a specific conntrack helper.
.TP
[\fB!\fP] \fB\-\-helper\fP \fIstring\fP
-Matches packets related to the specified conntrack-helper.
+Matches packets related to the specified conntrack helper.
.RS
.PP
-string can be "ftp" for packets related to a ftp-session on default port.
-For other ports append \-portnr to the value, ie. "ftp\-2121".
+string can be "ftp" for packets related to an FTP session on default port.
+For other ports, append \-\-portnr to the value, ie. "ftp\-2121".
.PP
-Same rules apply for other conntrack-helpers.
+Same rules apply for other conntrack helpers.
.RE
diff --git a/extensions/libxt_helper.txlate b/extensions/libxt_helper.txlate
index 8259aba3..2d94f740 100644
--- a/extensions/libxt_helper.txlate
+++ b/extensions/libxt_helper.txlate
@@ -1,5 +1,5 @@
iptables-translate -A FORWARD -m helper --helper sip
-nft add rule ip filter FORWARD ct helper \"sip\" counter
+nft 'add rule ip filter FORWARD ct helper "sip" counter'
iptables-translate -A FORWARD -m helper ! --helper ftp
-nft add rule ip filter FORWARD ct helper != \"ftp\" counter
+nft 'add rule ip filter FORWARD ct helper != "ftp" counter'
diff --git a/extensions/libxt_icmp.h b/extensions/libxt_icmp.h
index 5820206e..7a45b4bd 100644
--- a/extensions/libxt_icmp.h
+++ b/extensions/libxt_icmp.h
@@ -1,25 +1,256 @@
-struct xt_icmp_names {
+static const struct xt_icmp_names {
const char *name;
uint8_t type;
uint8_t code_min, code_max;
+} icmp_codes[] = {
+ { "any", 0xFF, 0, 0xFF },
+ { "echo-reply", 0, 0, 0xFF },
+ /* Alias */ { "pong", 0, 0, 0xFF },
+
+ { "destination-unreachable", 3, 0, 0xFF },
+ { "network-unreachable", 3, 0, 0 },
+ { "host-unreachable", 3, 1, 1 },
+ { "protocol-unreachable", 3, 2, 2 },
+ { "port-unreachable", 3, 3, 3 },
+ { "fragmentation-needed", 3, 4, 4 },
+ { "source-route-failed", 3, 5, 5 },
+ { "network-unknown", 3, 6, 6 },
+ { "host-unknown", 3, 7, 7 },
+ { "network-prohibited", 3, 9, 9 },
+ { "host-prohibited", 3, 10, 10 },
+ { "TOS-network-unreachable", 3, 11, 11 },
+ { "TOS-host-unreachable", 3, 12, 12 },
+ { "communication-prohibited", 3, 13, 13 },
+ { "host-precedence-violation", 3, 14, 14 },
+ { "precedence-cutoff", 3, 15, 15 },
+
+ { "source-quench", 4, 0, 0xFF },
+
+ { "redirect", 5, 0, 0xFF },
+ { "network-redirect", 5, 0, 0 },
+ { "host-redirect", 5, 1, 1 },
+ { "TOS-network-redirect", 5, 2, 2 },
+ { "TOS-host-redirect", 5, 3, 3 },
+
+ { "echo-request", 8, 0, 0xFF },
+ /* Alias */ { "ping", 8, 0, 0xFF },
+
+ { "router-advertisement", 9, 0, 0xFF },
+
+ { "router-solicitation", 10, 0, 0xFF },
+
+ { "time-exceeded", 11, 0, 0xFF },
+ /* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
+ { "ttl-zero-during-transit", 11, 0, 0 },
+ { "ttl-zero-during-reassembly", 11, 1, 1 },
+
+ { "parameter-problem", 12, 0, 0xFF },
+ { "ip-header-bad", 12, 0, 0 },
+ { "required-option-missing", 12, 1, 1 },
+
+ { "timestamp-request", 13, 0, 0xFF },
+
+ { "timestamp-reply", 14, 0, 0xFF },
+
+ { "address-mask-request", 17, 0, 0xFF },
+
+ { "address-mask-reply", 18, 0, 0xFF }
+}, icmpv6_codes[] = {
+ { "destination-unreachable", 1, 0, 0xFF },
+ { "no-route", 1, 0, 0 },
+ { "communication-prohibited", 1, 1, 1 },
+ { "beyond-scope", 1, 2, 2 },
+ { "address-unreachable", 1, 3, 3 },
+ { "port-unreachable", 1, 4, 4 },
+ { "failed-policy", 1, 5, 5 },
+ { "reject-route", 1, 6, 6 },
+
+ { "packet-too-big", 2, 0, 0xFF },
+
+ { "time-exceeded", 3, 0, 0xFF },
+ /* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
+ { "ttl-zero-during-transit", 3, 0, 0 },
+ { "ttl-zero-during-reassembly", 3, 1, 1 },
+
+ { "parameter-problem", 4, 0, 0xFF },
+ { "bad-header", 4, 0, 0 },
+ { "unknown-header-type", 4, 1, 1 },
+ { "unknown-option", 4, 2, 2 },
+
+ { "echo-request", 128, 0, 0xFF },
+ /* Alias */ { "ping", 128, 0, 0xFF },
+
+ { "echo-reply", 129, 0, 0xFF },
+ /* Alias */ { "pong", 129, 0, 0xFF },
+
+ { "mld-listener-query", 130, 0, 0xFF },
+
+ { "mld-listener-report", 131, 0, 0xFF },
+
+ { "mld-listener-done", 132, 0, 0xFF },
+ /* Alias */ { "mld-listener-reduction", 132, 0, 0xFF },
+
+ { "router-solicitation", 133, 0, 0xFF },
+
+ { "router-advertisement", 134, 0, 0xFF },
+
+ { "neighbour-solicitation", 135, 0, 0xFF },
+ /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
+
+ { "neighbour-advertisement", 136, 0, 0xFF },
+ /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
+
+ { "redirect", 137, 0, 0xFF },
+}, igmp_types[] = {
+ { "membership-query", 0x11 },
+ { "membership-report-v1", 0x12 },
+ { "membership-report-v2", 0x16 },
+ { "leave-group", 0x17 },
+ { "membership-report-v3", 0x22 },
};
-static void xt_print_icmp_types(const struct xt_icmp_names *icmp_codes,
+static inline char *parse_range(const char *str, unsigned int res[])
+{
+ char *next;
+
+ if (!xtables_strtoui(str, &next, &res[0], 0, 255))
+ return NULL;
+
+ res[1] = res[0];
+ if (*next == ':') {
+ str = next + 1;
+ if (!xtables_strtoui(str, &next, &res[1], 0, 255))
+ return NULL;
+ }
+
+ return next;
+}
+
+static void
+__parse_icmp(const struct xt_icmp_names codes[], size_t n_codes,
+ const char *codes_name, const char *fmtstring,
+ uint8_t type[], uint8_t code[])
+{
+ unsigned int match = n_codes;
+ unsigned int i, number[2];
+
+ for (i = 0; i < n_codes; i++) {
+ if (strncasecmp(codes[i].name, fmtstring, strlen(fmtstring)))
+ continue;
+ if (match != n_codes)
+ xtables_error(PARAMETER_PROBLEM,
+ "Ambiguous %s type `%s': `%s' or `%s'?",
+ codes_name, fmtstring, codes[match].name,
+ codes[i].name);
+ match = i;
+ }
+
+ if (match < n_codes) {
+ type[0] = type[1] = codes[match].type;
+ if (code) {
+ code[0] = codes[match].code_min;
+ code[1] = codes[match].code_max;
+ }
+ } else {
+ char *next = parse_range(fmtstring, number);
+ if (!next)
+ xtables_error(PARAMETER_PROBLEM, "Unknown %s type `%s'",
+ codes_name, fmtstring);
+ type[0] = (uint8_t) number[0];
+ type[1] = (uint8_t) number[1];
+ switch (*next) {
+ case 0:
+ if (code) {
+ code[0] = 0;
+ code[1] = 255;
+ }
+ return;
+ case '/':
+ if (!code)
+ break;
+
+ next = parse_range(next + 1, number);
+ if (!next)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unknown %s code `%s'",
+ codes_name, fmtstring);
+ code[0] = (uint8_t) number[0];
+ code[1] = (uint8_t) number[1];
+ if (!*next)
+ break;
+ /* fallthrough */
+ default:
+ xtables_error(PARAMETER_PROBLEM,
+ "unknown character %c", *next);
+ }
+ }
+}
+
+static inline void
+__ipt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes,
+ const char *codes_name, const char *fmtstr,
+ uint8_t *type, uint8_t code[])
+{
+ uint8_t types[2];
+
+ __parse_icmp(codes, n_codes, codes_name, fmtstr, types, code);
+ if (types[1] != types[0])
+ xtables_error(PARAMETER_PROBLEM,
+ "%s type range not supported", codes_name);
+ *type = types[0];
+}
+
+static inline void
+ipt_parse_icmp(const char *str, uint8_t *type, uint8_t code[])
+{
+ __ipt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes),
+ "ICMP", str, type, code);
+}
+
+static inline void
+ipt_parse_icmpv6(const char *str, uint8_t *type, uint8_t code[])
+{
+ __ipt_parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
+ "ICMPv6", str, type, code);
+}
+
+static inline void
+ebt_parse_icmp(const char *str, uint8_t type[], uint8_t code[])
+{
+ __parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes),
+ "ICMP", str, type, code);
+}
+
+static inline void
+ebt_parse_icmpv6(const char *str, uint8_t type[], uint8_t code[])
+{
+ __parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
+ "ICMPv6", str, type, code);
+}
+
+static inline void
+ebt_parse_igmp(const char *str, uint8_t type[])
+{
+ __parse_icmp(igmp_types, ARRAY_SIZE(igmp_types),
+ "IGMP", str, type, NULL);
+}
+
+static void xt_print_icmp_types(const struct xt_icmp_names *_icmp_codes,
unsigned int n_codes)
{
unsigned int i;
for (i = 0; i < n_codes; ++i) {
- if (i && icmp_codes[i].type == icmp_codes[i-1].type) {
- if (icmp_codes[i].code_min == icmp_codes[i-1].code_min
- && (icmp_codes[i].code_max
- == icmp_codes[i-1].code_max))
- printf(" (%s)", icmp_codes[i].name);
+ if (i && _icmp_codes[i].type == _icmp_codes[i-1].type) {
+ if (_icmp_codes[i].code_min == _icmp_codes[i-1].code_min
+ && (_icmp_codes[i].code_max
+ == _icmp_codes[i-1].code_max))
+ printf(" (%s)", _icmp_codes[i].name);
else
- printf("\n %s", icmp_codes[i].name);
+ printf("\n %s", _icmp_codes[i].name);
}
else
- printf("\n%s", icmp_codes[i].name);
+ printf("\n%s", _icmp_codes[i].name);
}
printf("\n");
}
diff --git a/extensions/libxt_ipcomp.c b/extensions/libxt_ipcomp.c
index b5c43128..961c17e5 100644
--- a/extensions/libxt_ipcomp.c
+++ b/extensions/libxt_ipcomp.c
@@ -76,11 +76,12 @@ static void comp_print(const void *ip, const struct xt_entry_match *match,
static void comp_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_ipcomp *compinfo = (struct xt_ipcomp *)match->data;
+ bool inv_spi = compinfo->invflags & XT_IPCOMP_INV_SPI;
if (!(compinfo->spis[0] == 0
- && compinfo->spis[1] == 0xFFFFFFFF)) {
- printf("%s --ipcompspi ",
- (compinfo->invflags & XT_IPCOMP_INV_SPI) ? " !" : "");
+ && compinfo->spis[1] == UINT32_MAX
+ && !inv_spi)) {
+ printf("%s --ipcompspi ", inv_spi ? " !" : "");
if (compinfo->spis[0]
!= compinfo->spis[1])
printf("%u:%u",
@@ -101,6 +102,8 @@ static int comp_xlate(struct xt_xlate *xl,
const struct xt_ipcomp *compinfo =
(struct xt_ipcomp *)params->match->data;
+ /* ignore compinfo->hdrres like kernel's xt_ipcomp.c does */
+
xt_xlate_add(xl, "comp cpi %s",
compinfo->invflags & XT_IPCOMP_INV_SPI ? "!= " : "");
if (compinfo->spis[0] != compinfo->spis[1])
diff --git a/extensions/libxt_ipcomp.c.man b/extensions/libxt_ipcomp.c.man
index f3b17d21..824f5b3d 100644
--- a/extensions/libxt_ipcomp.c.man
+++ b/extensions/libxt_ipcomp.c.man
@@ -2,6 +2,3 @@ This module matches the parameters in IPcomp header of IPsec packets.
.TP
[\fB!\fP] \fB\-\-ipcompspi\fP \fIspi\fP[\fB:\fP\fIspi\fP]
Matches IPcomp header CPI value.
-.TP
-\fB\-\-compres\fP
-Matches if the reserved field is filled with zero.
diff --git a/extensions/libxt_ipcomp.t b/extensions/libxt_ipcomp.t
index 8546ba9c..e25695c6 100644
--- a/extensions/libxt_ipcomp.t
+++ b/extensions/libxt_ipcomp.t
@@ -1,3 +1,10 @@
:INPUT,OUTPUT
-p ipcomp -m ipcomp --ipcompspi 18 -j DROP;=;OK
-p ipcomp -m ipcomp ! --ipcompspi 18 -j ACCEPT;=;OK
+-p ipcomp -m ipcomp --ipcompspi :;-p ipcomp -m ipcomp;OK
+-p ipcomp -m ipcomp ! --ipcompspi :;-p ipcomp -m ipcomp ! --ipcompspi 0:4294967295;OK
+-p ipcomp -m ipcomp --ipcompspi :4;-p ipcomp -m ipcomp --ipcompspi 0:4;OK
+-p ipcomp -m ipcomp --ipcompspi 4:;-p ipcomp -m ipcomp --ipcompspi 4:4294967295;OK
+-p ipcomp -m ipcomp --ipcompspi 3:4;=;OK
+-p ipcomp -m ipcomp --ipcompspi 4:4;-p ipcomp -m ipcomp --ipcompspi 4;OK
+-p ipcomp -m ipcomp --ipcompspi 4:3;;FAIL
diff --git a/extensions/libxt_ipcomp.txlate b/extensions/libxt_ipcomp.txlate
index f9efe53c..877cccbb 100644
--- a/extensions/libxt_ipcomp.txlate
+++ b/extensions/libxt_ipcomp.txlate
@@ -1,5 +1,5 @@
iptables-translate -t filter -A INPUT -m ipcomp --ipcompspi 0x12 -j ACCEPT
-nft add rule ip filter INPUT comp cpi 18 counter accept
+nft 'add rule ip filter INPUT comp cpi 18 counter accept'
iptables-translate -t filter -A INPUT -m ipcomp ! --ipcompspi 0x12 -j ACCEPT
-nft add rule ip filter INPUT comp cpi != 18 counter accept
+nft 'add rule ip filter INPUT comp cpi != 18 counter accept'
diff --git a/extensions/libxt_iprange.c b/extensions/libxt_iprange.c
index 8be24814..0df709d5 100644
--- a/extensions/libxt_iprange.c
+++ b/extensions/libxt_iprange.c
@@ -73,11 +73,9 @@ iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range,
static void iprange_parse_range(const char *oarg, union nf_inet_addr *range,
uint8_t family, const char *optname)
{
- char *arg = strdup(oarg);
+ char *arg = xtables_strdup(oarg);
char *dash;
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
dash = strchr(arg, '-');
if (dash == NULL) {
iprange_parse_spec(arg, arg, range, family, optname);
@@ -319,16 +317,14 @@ static int iprange_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct ipt_iprange_info *info = (const void *)params->match->data;
- char *space = "";
if (info->flags & IPRANGE_SRC) {
xt_xlate_add(xl, "ip saddr%s",
info->flags & IPRANGE_SRC_INV ? " !=" : "");
print_iprange_xlate(&info->src, xl);
- space = " ";
}
if (info->flags & IPRANGE_DST) {
- xt_xlate_add(xl, "%sip daddr%s", space,
+ xt_xlate_add(xl, "ip daddr%s",
info->flags & IPRANGE_DST_INV ? " !=" : "");
print_iprange_xlate(&info->dst, xl);
}
@@ -341,7 +337,6 @@ static int iprange_mt4_xlate(struct xt_xlate *xl,
{
const struct xt_iprange_mtinfo *info =
(const void *)params->match->data;
- char *space = "";
if (info->flags & IPRANGE_SRC) {
xt_xlate_add(xl, "ip saddr%s %s",
@@ -349,10 +344,9 @@ static int iprange_mt4_xlate(struct xt_xlate *xl,
xtables_ipaddr_to_numeric(&info->src_min.in));
xt_xlate_add(xl, "-%s",
xtables_ipaddr_to_numeric(&info->src_max.in));
- space = " ";
}
if (info->flags & IPRANGE_DST) {
- xt_xlate_add(xl, "%sip daddr%s %s", space,
+ xt_xlate_add(xl, "ip daddr%s %s",
info->flags & IPRANGE_DST_INV ? " !=" : "",
xtables_ipaddr_to_numeric(&info->dst_min.in));
xt_xlate_add(xl, "-%s",
@@ -367,7 +361,6 @@ static int iprange_mt6_xlate(struct xt_xlate *xl,
{
const struct xt_iprange_mtinfo *info =
(const void *)params->match->data;
- char *space = "";
if (info->flags & IPRANGE_SRC) {
xt_xlate_add(xl, "ip6 saddr%s %s",
@@ -375,10 +368,9 @@ static int iprange_mt6_xlate(struct xt_xlate *xl,
xtables_ip6addr_to_numeric(&info->src_min.in6));
xt_xlate_add(xl, "-%s",
xtables_ip6addr_to_numeric(&info->src_max.in6));
- space = " ";
}
if (info->flags & IPRANGE_DST) {
- xt_xlate_add(xl, "%sip6 daddr%s %s", space,
+ xt_xlate_add(xl, "ip6 daddr%s %s",
info->flags & IPRANGE_DST_INV ? " !=" : "",
xtables_ip6addr_to_numeric(&info->dst_min.in6));
xt_xlate_add(xl, "-%s",
diff --git a/extensions/libxt_iprange.txlate b/extensions/libxt_iprange.txlate
index 999f4b72..80369650 100644
--- a/extensions/libxt_iprange.txlate
+++ b/extensions/libxt_iprange.txlate
@@ -1,14 +1,14 @@
iptables-translate -A INPUT -m iprange --src-range 192.168.25.149-192.168.25.151 -j ACCEPT
-nft add rule ip filter INPUT ip saddr 192.168.25.149-192.168.25.151 counter accept
+nft 'add rule ip filter INPUT ip saddr 192.168.25.149-192.168.25.151 counter accept'
iptables-translate -A INPUT -m iprange --dst-range 192.168.25.149-192.168.25.151 -j ACCEPT
-nft add rule ip filter INPUT ip daddr 192.168.25.149-192.168.25.151 counter accept
+nft 'add rule ip filter INPUT ip daddr 192.168.25.149-192.168.25.151 counter accept'
iptables-translate -A INPUT -m iprange --dst-range 3.3.3.3-6.6.6.6 --src-range 4.4.4.4-7.7.7.7 -j ACCEPT
-nft add rule ip filter INPUT ip saddr 4.4.4.4-7.7.7.7 ip daddr 3.3.3.3-6.6.6.6 counter accept
+nft 'add rule ip filter INPUT ip saddr 4.4.4.4-7.7.7.7 ip daddr 3.3.3.3-6.6.6.6 counter accept'
ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 -j ACCEPT
-nft add rule ip6 filter INPUT ip6 daddr != ::2d01-::2d03 counter accept
+nft 'add rule ip6 filter INPUT ip6 daddr != ::2d01-::2d03 counter accept'
ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 --src-range ::2d01-::2d03 -j ACCEPT
-nft add rule ip6 filter INPUT ip6 saddr ::2d01-::2d03 ip6 daddr != ::2d01-::2d03 counter accept
+nft 'add rule ip6 filter INPUT ip6 saddr ::2d01-::2d03 ip6 daddr != ::2d01-::2d03 counter accept'
diff --git a/extensions/libxt_length.t b/extensions/libxt_length.t
index 0b6624ee..bae313b4 100644
--- a/extensions/libxt_length.t
+++ b/extensions/libxt_length.t
@@ -2,9 +2,12 @@
-m length --length 1;=;OK
-m length --length :2;-m length --length 0:2;OK
-m length --length 0:3;=;OK
--m length --length 4:;=;OK
+-m length --length 4:;-m length --length 4:65535;OK
+-m length --length :;-m length --length 0:65535;OK
-m length --length 0:65535;=;OK
-m length ! --length 0:65535;=;OK
-m length --length 0:65536;;FAIL
-m length --length -1:65535;;FAIL
+-m length --length 4:4;-m length --length 4;OK
+-m length --length 4:3;;FAIL
-m length;;FAIL
diff --git a/extensions/libxt_length.txlate b/extensions/libxt_length.txlate
index e777c265..38f835dc 100644
--- a/extensions/libxt_length.txlate
+++ b/extensions/libxt_length.txlate
@@ -1,11 +1,11 @@
iptables-translate -A INPUT -p icmp -m length --length 86:0xffff -j DROP
-nft add rule ip filter INPUT ip protocol icmp meta length 86-65535 counter drop
+nft 'add rule ip filter INPUT ip protocol icmp meta length 86-65535 counter drop'
iptables-translate -A INPUT -p udp -m length --length :400
-nft add rule ip filter INPUT ip protocol udp meta length 0-400 counter
+nft 'add rule ip filter INPUT ip protocol udp meta length 0-400 counter'
iptables-translate -A INPUT -p udp -m length --length 40
-nft add rule ip filter INPUT ip protocol udp meta length 40 counter
+nft 'add rule ip filter INPUT ip protocol udp meta length 40 counter'
iptables-translate -A INPUT -p udp -m length ! --length 40
-nft add rule ip filter INPUT ip protocol udp meta length != 40 counter
+nft 'add rule ip filter INPUT ip protocol udp meta length != 40 counter'
diff --git a/extensions/libxt_limit.c b/extensions/libxt_limit.c
index 1b324657..63f3289d 100644
--- a/extensions/libxt_limit.c
+++ b/extensions/libxt_limit.c
@@ -7,7 +7,6 @@
#define _DEFAULT_SOURCE 1
#define _ISOC99_SOURCE 1
#include <errno.h>
-#include <getopt.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
@@ -77,7 +76,7 @@ int parse_rate(const char *rate, uint32_t *val)
* The rate maps to infinity. (1/day is the minimum they can
* specify, so we are ok at that end).
*/
- xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
+ xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"", rate);
return 1;
}
@@ -93,7 +92,7 @@ static void limit_init(struct xt_entry_match *m)
/* FIXME: handle overflow:
if (r->avg*r->burst/r->burst != r->avg)
xtables_error(PARAMETER_PROBLEM,
- "Sorry: burst too large for that avg rate.\n");
+ "Sorry: burst too large for that avg rate.");
*/
static void limit_parse(struct xt_option_call *cb)
@@ -202,44 +201,6 @@ static int limit_xlate_eb(struct xt_xlate *xl,
return 1;
}
-#define FLAG_LIMIT 0x01
-#define FLAG_LIMIT_BURST 0x02
-#define ARG_LIMIT '1'
-#define ARG_LIMIT_BURST '2'
-
-static int brlimit_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_match **match)
-{
- struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data;
- uintmax_t num;
-
- switch (c) {
- case ARG_LIMIT:
- EBT_CHECK_OPTION(flags, FLAG_LIMIT);
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "Unexpected `!' after --limit");
- if (!parse_rate(optarg, &r->avg))
- xtables_error(PARAMETER_PROBLEM,
- "bad rate `%s'", optarg);
- break;
- case ARG_LIMIT_BURST:
- EBT_CHECK_OPTION(flags, FLAG_LIMIT_BURST);
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "Unexpected `!' after --limit-burst");
- if (!xtables_strtoul(optarg, NULL, &num, 0, 10000))
- xtables_error(PARAMETER_PROBLEM,
- "bad --limit-burst `%s'", optarg);
- r->burst = num;
- break;
- default:
- return 0;
- }
-
- return 1;
-}
-
static void brlimit_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
@@ -250,13 +211,6 @@ static void brlimit_print(const void *ip, const struct xt_entry_match *match,
printf(" --limit-burst %u ", r->burst);
}
-static const struct option brlimit_opts[] =
-{
- { .name = "limit", .has_arg = true, .val = ARG_LIMIT },
- { .name = "limit-burst",.has_arg = true, .val = ARG_LIMIT_BURST },
- XT_GETOPT_TABLEEND,
-};
-
static struct xtables_match limit_match[] = {
{
.family = NFPROTO_UNSPEC,
@@ -280,9 +234,9 @@ static struct xtables_match limit_match[] = {
.userspacesize = offsetof(struct xt_rateinfo, prev),
.help = limit_help,
.init = limit_init,
- .parse = brlimit_parse,
+ .x6_parse = limit_parse,
.print = brlimit_print,
- .extra_opts = brlimit_opts,
+ .x6_options = limit_opts,
.xlate = limit_xlate_eb,
},
};
diff --git a/extensions/libxt_limit.man b/extensions/libxt_limit.man
index 6fb94ccf..b477dd94 100644
--- a/extensions/libxt_limit.man
+++ b/extensions/libxt_limit.man
@@ -4,7 +4,7 @@ It can be used in combination with the
.B LOG
target to give limited logging, for example.
.PP
-xt_limit has no negation support - you will have to use \-m hashlimit !
+xt_limit has no negation support \(em you will have to use \-m hashlimit !
\-\-hashlimit \fIrate\fP in this case whilst omitting \-\-hashlimit\-mode.
.TP
\fB\-\-limit\fP \fIrate\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP]
diff --git a/extensions/libxt_limit.txlate b/extensions/libxt_limit.txlate
index df9ed2d5..fa8e1bc0 100644
--- a/extensions/libxt_limit.txlate
+++ b/extensions/libxt_limit.txlate
@@ -1,8 +1,8 @@
iptables-translate -A INPUT -m limit --limit 3/m --limit-burst 3
-nft add rule ip filter INPUT limit rate 3/minute burst 3 packets counter
+nft 'add rule ip filter INPUT limit rate 3/minute burst 3 packets counter'
iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 5
-nft add rule ip filter INPUT limit rate 10/second burst 5 packets counter
+nft 'add rule ip filter INPUT limit rate 10/second burst 5 packets counter'
iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 0
-nft add rule ip filter INPUT limit rate 10/second counter
+nft 'add rule ip filter INPUT limit rate 10/second counter'
diff --git a/extensions/libxt_mac.c b/extensions/libxt_mac.c
index b6d717bc..55891b2b 100644
--- a/extensions/libxt_mac.c
+++ b/extensions/libxt_mac.c
@@ -37,26 +37,17 @@ 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)
{
const struct xt_mac_info *info = (void *)match->data;
- printf(" MAC");
+ printf(" MAC ");
if (info->invert)
- printf(" !");
+ 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/extensions/libxt_mac.txlate b/extensions/libxt_mac.txlate
index 08696f3d..16800179 100644
--- a/extensions/libxt_mac.txlate
+++ b/extensions/libxt_mac.txlate
@@ -1,5 +1,5 @@
iptables-translate -A INPUT -m mac --mac-source 0a:12:3e:4f:b2:c6 -j DROP
-nft add rule ip filter INPUT ether saddr 0a:12:3e:4f:b2:c6 counter drop
+nft 'add rule ip filter INPUT ether saddr 0a:12:3e:4f:b2:c6 counter drop'
iptables-translate -A INPUT -p tcp --dport 80 -m mac --mac-source 0a:12:3e:4f:b2:c6 -j ACCEPT
-nft add rule ip filter INPUT tcp dport 80 ether saddr 0a:12:3e:4f:b2:c6 counter accept
+nft 'add rule ip filter INPUT tcp dport 80 ether saddr 0a:12:3e:4f:b2:c6 counter accept'
diff --git a/extensions/libxt_mark.t b/extensions/libxt_mark.t
index 7c005379..12c05865 100644
--- a/extensions/libxt_mark.t
+++ b/extensions/libxt_mark.t
@@ -1,7 +1,8 @@
:INPUT,FORWARD,OUTPUT
-m mark --mark 0xfeedcafe/0xfeedcafe;=;OK
--m mark --mark 0;=;OK
+-m mark --mark 0x0;=;OK
-m mark --mark 4294967295;-m mark --mark 0xffffffff;OK
-m mark --mark 4294967296;;FAIL
-m mark --mark -1;;FAIL
-m mark;;FAIL
+-s 1.2.0.0/15 -m mark --mark 0x0/0xff0;=;OK
diff --git a/extensions/libxt_mark.txlate b/extensions/libxt_mark.txlate
index 6bfb5243..6e097091 100644
--- a/extensions/libxt_mark.txlate
+++ b/extensions/libxt_mark.txlate
@@ -1,5 +1,5 @@
iptables-translate -I INPUT -p tcp -m mark ! --mark 0xa/0xa
-nft insert rule ip filter INPUT ip protocol tcp mark and 0xa != 0xa counter
+nft 'insert rule ip filter INPUT ip protocol tcp mark and 0xa != 0xa counter'
iptables-translate -I INPUT -p tcp -m mark ! --mark 0x1
-nft insert rule ip filter INPUT ip protocol tcp mark != 0x1 counter
+nft 'insert rule ip filter INPUT ip protocol tcp mark != 0x1 counter'
diff --git a/extensions/libxt_multiport.c b/extensions/libxt_multiport.c
index 07ad4cfd..813a3555 100644
--- a/extensions/libxt_multiport.c
+++ b/extensions/libxt_multiport.c
@@ -87,8 +87,7 @@ parse_multi_ports(const char *portstring, uint16_t *ports, const char *proto)
char *buffer, *cp, *next;
unsigned int i;
- buffer = strdup(portstring);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+ buffer = xtables_strdup(portstring);
for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
{
@@ -109,8 +108,7 @@ parse_multi_ports_v1(const char *portstring,
char *buffer, *cp, *next, *range;
unsigned int i;
- buffer = strdup(portstring);
- if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+ buffer = xtables_strdup(portstring);
for (i=0; i<XT_MULTI_PORTS; i++)
multiinfo->pflags[i] = 0;
@@ -250,7 +248,7 @@ static void multiport_parse6_v1(struct xt_option_call *cb)
static void multiport_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
- xtables_error(PARAMETER_PROBLEM, "multiport expection an option");
+ xtables_error(PARAMETER_PROBLEM, "no ports specified");
}
static const char *
@@ -467,7 +465,8 @@ static void multiport_save6_v1(const void *ip_void,
}
static int __multiport_xlate(struct xt_xlate *xl,
- const struct xt_xlate_mt_params *params)
+ const struct xt_xlate_mt_params *params,
+ uint8_t proto)
{
const struct xt_multiport *multiinfo
= (const struct xt_multiport *)params->match->data;
@@ -481,14 +480,24 @@ static int __multiport_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, " dport ");
break;
case XT_MULTIPORT_EITHER:
- return 0;
+ xt_xlate_add(xl, " sport . %s dport { ", proto_to_name(proto));
+ for (i = 0; i < multiinfo->count; i++) {
+ if (i != 0)
+ xt_xlate_add(xl, ", ");
+
+ xt_xlate_add(xl, "0-65535 . %u, %u . 0-65535",
+ multiinfo->ports[i], multiinfo->ports[i]);
+ }
+ xt_xlate_add(xl, " }");
+
+ return 1;
}
if (multiinfo->count > 1)
xt_xlate_add(xl, "{ ");
for (i = 0; i < multiinfo->count; i++)
- xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]);
+ xt_xlate_add(xl, "%s%u", i ? ", " : "", multiinfo->ports[i]);
if (multiinfo->count > 1)
xt_xlate_add(xl, "}");
@@ -502,7 +511,7 @@ static int multiport_xlate(struct xt_xlate *xl,
uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate(xl, params);
+ return __multiport_xlate(xl, params, proto);
}
static int multiport_xlate6(struct xt_xlate *xl,
@@ -511,11 +520,12 @@ static int multiport_xlate6(struct xt_xlate *xl,
uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate(xl, params);
+ return __multiport_xlate(xl, params, proto);
}
static int __multiport_xlate_v1(struct xt_xlate *xl,
- const struct xt_xlate_mt_params *params)
+ const struct xt_xlate_mt_params *params,
+ uint8_t proto)
{
const struct xt_multiport_v1 *multiinfo =
(const struct xt_multiport_v1 *)params->match->data;
@@ -529,7 +539,17 @@ static int __multiport_xlate_v1(struct xt_xlate *xl,
xt_xlate_add(xl, " dport ");
break;
case XT_MULTIPORT_EITHER:
- return 0;
+ xt_xlate_add(xl, " sport . %s dport { ", proto_to_name(proto));
+ for (i = 0; i < multiinfo->count; i++) {
+ if (i != 0)
+ xt_xlate_add(xl, ", ");
+
+ xt_xlate_add(xl, "0-65535 . %u, %u . 0-65535",
+ multiinfo->ports[i], multiinfo->ports[i]);
+ }
+ xt_xlate_add(xl, " }");
+
+ return 1;
}
if (multiinfo->invert)
@@ -540,7 +560,7 @@ static int __multiport_xlate_v1(struct xt_xlate *xl,
xt_xlate_add(xl, "{ ");
for (i = 0; i < multiinfo->count; i++) {
- xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]);
+ xt_xlate_add(xl, "%s%u", i ? ", " : "", multiinfo->ports[i]);
if (multiinfo->pflags[i])
xt_xlate_add(xl, "-%u", multiinfo->ports[++i]);
}
@@ -558,7 +578,7 @@ static int multiport_xlate_v1(struct xt_xlate *xl,
uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate_v1(xl, params);
+ return __multiport_xlate_v1(xl, params, proto);
}
static int multiport_xlate6_v1(struct xt_xlate *xl,
@@ -567,7 +587,7 @@ static int multiport_xlate6_v1(struct xt_xlate *xl,
uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
xt_xlate_add(xl, "%s", proto_to_name(proto));
- return __multiport_xlate_v1(xl, params);
+ return __multiport_xlate_v1(xl, params, proto);
}
static struct xtables_match multiport_mt_reg[] = {
diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate
index 752e7148..aa5f006d 100644
--- a/extensions/libxt_multiport.txlate
+++ b/extensions/libxt_multiport.txlate
@@ -1,11 +1,14 @@
iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80,81 -j ACCEPT
-nft add rule ip filter INPUT ip protocol tcp tcp dport { 80,81} counter accept
+nft 'add rule ip filter INPUT ip protocol tcp tcp dport { 80, 81 } counter accept'
iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80:88 -j ACCEPT
-nft add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept
+nft 'add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept'
iptables-translate -t filter -A INPUT -p tcp -m multiport ! --dports 80:88 -j ACCEPT
-nft add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept
+nft 'add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept'
iptables-translate -t filter -A INPUT -p tcp -m multiport --sports 50 -j ACCEPT
-nft add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept
+nft 'add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept'
+
+iptables-translate -t filter -I INPUT -p tcp -m multiport --ports 10
+nft 'insert rule ip filter INPUT ip protocol tcp tcp sport . tcp dport { 0-65535 . 10, 10 . 0-65535 } counter'
diff --git a/extensions/libxt_nfacct.man b/extensions/libxt_nfacct.man
index b755f977..4e05891e 100644
--- a/extensions/libxt_nfacct.man
+++ b/extensions/libxt_nfacct.man
@@ -22,9 +22,9 @@ Then, you can check for the amount of traffic that the rules match:
.IP
nfacct get http\-traffic
.IP
-{ pkts = 00000000000000000156, bytes = 00000000000000151786 } = http-traffic;
+{ pkts = 00000000000000000156, bytes = 00000000000000151786 } = http\-traffic;
.PP
You can obtain
.B nfacct(8)
-from http://www.netfilter.org or, alternatively, from the git.netfilter.org
+from https://www.netfilter.org or, alternatively, from the git.netfilter.org
repository.
diff --git a/extensions/libxt_osf.man b/extensions/libxt_osf.man
index 41103f29..85c1a3b4 100644
--- a/extensions/libxt_osf.man
+++ b/extensions/libxt_osf.man
@@ -8,29 +8,39 @@ Match an operating system genre by using a passive fingerprinting.
\fB\-\-ttl\fP \fIlevel\fP
Do additional TTL checks on the packet to determine the operating system.
\fIlevel\fP can be one of the following values:
-.IP \(bu 4
-0 - True IP address and fingerprint TTL comparison. This generally works for
+.RS
+.TP
+\fB0\fP
+True IP address and fingerprint TTL comparison. This generally works for
LANs.
-.IP \(bu 4
-1 - Check if the IP header's TTL is less than the fingerprint one. Works for
+.TP
+\fB1\fP
+Check if the IP header's TTL is less than the fingerprint one. Works for
globally-routable addresses.
-.IP \(bu 4
-2 - Do not compare the TTL at all.
+.TP
+\fB2\fP
+Do not compare the TTL at all.
+.RE
.TP
\fB\-\-log\fP \fIlevel\fP
Log determined genres into dmesg even if they do not match the desired one.
\fIlevel\fP can be one of the following values:
-.IP \(bu 4
-0 - Log all matched or unknown signatures
-.IP \(bu 4
-1 - Log only the first one
-.IP \(bu 4
-2 - Log all known matched signatures
+.RS
+.TP
+\fB0\fP
+Log all matched or unknown signatures
+.TP
+\fB1\fP
+Log only the first one
+.TP
+\fB2\fP
+Log all known matched signatures
+.RE
.PP
You may find something like this in syslog:
.PP
-Windows [2000:SP3:Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 ->
-11.22.33.44:139 hops=3 Linux [2.5-2.6:] : 1.2.3.4:42624 -> 1.2.3.5:22 hops=4
+Windows [2000:SP3:Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 \->
+11.22.33.44:139 hops=3 Linux [2.5\-2.6:] : 1.2.3.4:42624 \-> 1.2.3.5:22 hops=4
.PP
OS fingerprints are loadable using the \fBnfnl_osf\fP program. To load
fingerprints from a file, use:
@@ -42,4 +52,4 @@ To remove them again,
\fBnfnl_osf \-f /usr/share/xtables/pf.os \-d\fP
.PP
The fingerprint database can be downloaded from
-http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os .
+http://www.openbsd.org/cgi\-bin/cvsweb/src/etc/pf.os .
diff --git a/extensions/libxt_owner.man b/extensions/libxt_owner.man
index e2479865..fd6fe190 100644
--- a/extensions/libxt_owner.man
+++ b/extensions/libxt_owner.man
@@ -16,7 +16,7 @@ Matches if the packet socket's file structure is owned by the given group.
You may also specify a numerical GID, or a GID range.
.TP
\fB\-\-suppl\-groups\fP
-Causes group(s) specified with \fB\-\-gid-owner\fP to be also checked in the
+Causes group(s) specified with \fB\-\-gid\-owner\fP to be also checked in the
supplementary groups of a process.
.TP
[\fB!\fP] \fB\-\-socket\-exists\fP
diff --git a/extensions/libxt_owner.txlate b/extensions/libxt_owner.txlate
index 86fb0585..8fbd68eb 100644
--- a/extensions/libxt_owner.txlate
+++ b/extensions/libxt_owner.txlate
@@ -1,8 +1,8 @@
iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner root -j ACCEPT
-nft add rule ip nat OUTPUT tcp dport 80 skuid 0 counter accept
+nft 'add rule ip nat OUTPUT tcp dport 80 skuid 0 counter accept'
iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --gid-owner 0-10 -j ACCEPT
-nft add rule ip nat OUTPUT tcp dport 80 skgid 0-10 counter accept
+nft 'add rule ip nat OUTPUT tcp dport 80 skgid 0-10 counter accept'
iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner 1000 -j ACCEPT
-nft add rule ip nat OUTPUT tcp dport 80 skuid != 1000 counter accept
+nft 'add rule ip nat OUTPUT tcp dport 80 skuid != 1000 counter accept'
diff --git a/extensions/libxt_pkttype.c b/extensions/libxt_pkttype.c
index bf6f5b96..a76310b0 100644
--- a/extensions/libxt_pkttype.c
+++ b/extensions/libxt_pkttype.c
@@ -30,8 +30,8 @@ static const struct pkttypes supported_types[] = {
{"unicast", PACKET_HOST, 1, "to us"},
{"broadcast", PACKET_BROADCAST, 1, "to all"},
{"multicast", PACKET_MULTICAST, 1, "to group"},
-/*
{"otherhost", PACKET_OTHERHOST, 1, "to someone else"},
+/*
{"outgoing", PACKET_OUTGOING, 1, "outgoing of any type"},
*/
/* aliases */
diff --git a/extensions/libxt_pkttype.txlate b/extensions/libxt_pkttype.txlate
index 6506a380..c69f56f9 100644
--- a/extensions/libxt_pkttype.txlate
+++ b/extensions/libxt_pkttype.txlate
@@ -1,8 +1,8 @@
iptables-translate -A INPUT -m pkttype --pkt-type broadcast -j DROP
-nft add rule ip filter INPUT pkttype broadcast counter drop
+nft 'add rule ip filter INPUT pkttype broadcast counter drop'
iptables-translate -A INPUT -m pkttype ! --pkt-type unicast -j DROP
-nft add rule ip filter INPUT pkttype != unicast counter drop
+nft 'add rule ip filter INPUT pkttype != unicast counter drop'
iptables-translate -A INPUT -m pkttype --pkt-type multicast -j ACCEPT
-nft add rule ip filter INPUT pkttype multicast counter accept
+nft 'add rule ip filter INPUT pkttype multicast counter accept'
diff --git a/extensions/libxt_policy.txlate b/extensions/libxt_policy.txlate
index 66788a76..a960b395 100644
--- a/extensions/libxt_policy.txlate
+++ b/extensions/libxt_policy.txlate
@@ -1,5 +1,5 @@
iptables-translate -A INPUT -m policy --pol ipsec --dir in
-nft add rule ip filter INPUT meta secpath exists counter
+nft 'add rule ip filter INPUT meta secpath exists counter'
iptables-translate -A INPUT -m policy --pol none --dir in
-nft add rule ip filter INPUT meta secpath missing counter
+nft 'add rule ip filter INPUT meta secpath missing counter'
diff --git a/extensions/libxt_quota.txlate b/extensions/libxt_quota.txlate
index 91142141..6edd925d 100644
--- a/extensions/libxt_quota.txlate
+++ b/extensions/libxt_quota.txlate
@@ -1,5 +1,5 @@
iptables-translate -A OUTPUT -m quota --quota 111
-nft add rule ip filter OUTPUT quota 111 bytes counter
+nft 'add rule ip filter OUTPUT quota 111 bytes counter'
iptables-translate -A OUTPUT -m quota ! --quota 111
-nft add rule ip filter OUTPUT quota over 111 bytes counter
+nft 'add rule ip filter OUTPUT quota over 111 bytes counter'
diff --git a/extensions/libxt_rateest.man b/extensions/libxt_rateest.man
index 42a82f32..b1779eb3 100644
--- a/extensions/libxt_rateest.man
+++ b/extensions/libxt_rateest.man
@@ -4,22 +4,26 @@ estimators and matching on the difference between two rate estimators.
.PP
For a better understanding of the available options, these are all possible
combinations:
-.\" * Absolute:
+.TP
+Absolute:
.IP \(bu 4
\fBrateest\fP \fIoperator\fP \fBrateest-bps\fP
.IP \(bu 4
\fBrateest\fP \fIoperator\fP \fBrateest-pps\fP
-.\" * Absolute + Delta:
+.TP
+Absolute + Delta:
.IP \(bu 4
(\fBrateest\fP minus \fBrateest-bps1\fP) \fIoperator\fP \fBrateest-bps2\fP
.IP \(bu 4
(\fBrateest\fP minus \fBrateest-pps1\fP) \fIoperator\fP \fBrateest-pps2\fP
-.\" * Relative:
+.TP
+Relative:
.IP \(bu 4
\fBrateest1\fP \fIoperator\fP \fBrateest2\fP \fBrateest-bps\fP(without rate!)
.IP \(bu 4
\fBrateest1\fP \fIoperator\fP \fBrateest2\fP \fBrateest-pps\fP(without rate!)
-.\" * Relative + Delta:
+.TP
+Relative + Delta:
.IP \(bu 4
(\fBrateest1\fP minus \fBrateest-bps1\fP) \fIoperator\fP
(\fBrateest2\fP minus \fBrateest-bps2\fP)
@@ -31,7 +35,7 @@ combinations:
For each estimator (either absolute or relative mode), calculate the difference
between the estimator-determined flow rate and the static value chosen with the
BPS/PPS options. If the flow rate is higher than the specified BPS/PPS, 0 will
-be used instead of a negative value. In other words, "max(0, rateest#_rate -
+be used instead of a negative value. In other words, "max(0, rateest#_rate \-
rateest#_bps)" is used.
.TP
[\fB!\fP] \fB\-\-rateest\-lt\fP
@@ -68,7 +72,7 @@ The names of the two rate estimators for relative mode.
\fB\-\-rateest\-pps2\fP [\fIvalue\fP]
Compare the estimator(s) by bytes or packets per second, and compare against
the chosen value. See the above bullet list for which option is to be used in
-which case. A unit suffix may be used - available ones are: bit, [kmgt]bit,
+which case. A unit suffix may be used \(em available ones are: bit, [kmgt]bit,
[KMGT]ibit, Bps, [KMGT]Bps, [KMGT]iBps.
.PP
Example: This is what can be used to route outgoing data connections from an
diff --git a/extensions/libxt_recent.t b/extensions/libxt_recent.t
index 9a83918e..cf23aabc 100644
--- a/extensions/libxt_recent.t
+++ b/extensions/libxt_recent.t
@@ -1,8 +1,8 @@
:INPUT,FORWARD,OUTPUT
--m recent --set;=;OK
+-m recent --set;-m recent --set --name DEFAULT --mask 255.255.255.255 --rsource;OK
-m recent --rcheck --hitcount 8 --name foo --mask 255.255.255.255 --rsource;=;OK
-m recent --rcheck --hitcount 12 --name foo --mask 255.255.255.255 --rsource;=;OK
--m recent --update --rttl;=;OK
+-m recent --update --rttl;-m recent --update --rttl --name DEFAULT --mask 255.255.255.255 --rsource;OK
-m recent --set --rttl;;FAIL
-m recent --rcheck --hitcount 999 --name foo --mask 255.255.255.255 --rsource;;FAIL
# nonsensical, but all should load successfully:
diff --git a/extensions/libxt_rpfilter.txlate b/extensions/libxt_rpfilter.txlate
index 8d7733ba..a551c419 100644
--- a/extensions/libxt_rpfilter.txlate
+++ b/extensions/libxt_rpfilter.txlate
@@ -1,8 +1,8 @@
iptables-translate -t mangle -A PREROUTING -m rpfilter
-nft add rule ip mangle PREROUTING fib saddr . iif oif != 0 counter
+nft 'add rule ip mangle PREROUTING fib saddr . iif oif != 0 counter'
iptables-translate -t mangle -A PREROUTING -m rpfilter --validmark --loose
-nft add rule ip mangle PREROUTING fib saddr . mark oif != 0 counter
+nft 'add rule ip mangle PREROUTING fib saddr . mark oif != 0 counter'
ip6tables-translate -t mangle -A PREROUTING -m rpfilter --validmark --invert
-nft add rule ip6 mangle PREROUTING fib saddr . mark . iif oif 0 counter
+nft 'add rule ip6 mangle PREROUTING fib saddr . mark . iif oif 0 counter'
diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c
index 140de265..6e2b2745 100644
--- a/extensions/libxt_sctp.c
+++ b/extensions/libxt_sctp.c
@@ -50,7 +50,7 @@ static void sctp_help(void)
" --dport ...\n"
"[!] --chunk-types (all|any|none) (chunktype[:flags])+ match if all, any or none of\n"
" chunktypes are present\n"
-"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN ALL NONE\n");
+"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE I_DATA RE_CONFIG PAD ASCONF ASCONF_ACK FORWARD_TSN I_FORWARD_TSN ALL NONE\n");
}
static const struct option sctp_opts[] = {
@@ -69,7 +69,7 @@ parse_sctp_ports(const char *portstring,
char *buffer;
char *cp;
- buffer = strdup(portstring);
+ buffer = xtables_strdup(portstring);
DEBUGP("%s\n", portstring);
if ((cp = strchr(buffer, ':')) == NULL) {
ports[0] = ports[1] = xtables_parse_port(buffer, "sctp");
@@ -92,28 +92,33 @@ struct sctp_chunk_names {
const char *name;
unsigned int chunk_type;
const char *valid_flags;
+ const char *nftname;
};
/*'ALL' and 'NONE' will be treated specially. */
static const struct sctp_chunk_names sctp_chunk_names[]
-= { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE"},
- { .name = "INIT", .chunk_type = 1, .valid_flags = "--------"},
- { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------"},
- { .name = "SACK", .chunk_type = 3, .valid_flags = "--------"},
- { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------"},
- { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------"},
- { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T"},
- { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------"},
- { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------"},
- { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------"},
- { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------"},
- { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------"},
- { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------"},
- { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------"},
- { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T"},
- { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------"},
- { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------"},
- { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------"},
+= { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE", .nftname = "data" },
+ { .name = "INIT", .chunk_type = 1, .valid_flags = "--------", .nftname = "init" },
+ { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------", .nftname = "init-ack" },
+ { .name = "SACK", .chunk_type = 3, .valid_flags = "--------", .nftname = "sack" },
+ { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------", .nftname = "heartbeat" },
+ { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------", .nftname = "heartbeat-ack" },
+ { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T", .nftname = "abort" },
+ { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------", .nftname = "shutdown" },
+ { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------", .nftname = "shutdown-ack" },
+ { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------", .nftname = "error" },
+ { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------", .nftname = "cookie-echo" },
+ { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------", .nftname = "cookie-ack" },
+ { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------", .nftname = "ecne" },
+ { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------", .nftname = "cwr" },
+ { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T", .nftname = "shutdown-complete" },
+ { .name = "I_DATA", .chunk_type = 64, .valid_flags = "----IUBE", .nftname = "i-data"},
+ { .name = "RE_CONFIG", .chunk_type = 130, .valid_flags = "--------", .nftname = "re-config"},
+ { .name = "PAD", .chunk_type = 132, .valid_flags = "--------", .nftname = "pad"},
+ { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------", .nftname = "asconf" },
+ { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------", .nftname = "asconf-ack" },
+ { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------", .nftname = "forward-tsn" },
+ { .name = "I_FORWARD_TSN", .chunk_type = 194, .valid_flags = "--------", .nftname = "i-forward-tsn" },
};
static void
@@ -139,10 +144,8 @@ save_chunk_flag_info(struct xt_sctp_flag_info *flag_info,
}
if (*flag_count == XT_NUM_SCTP_FLAGS) {
- xtables_error (PARAMETER_PROBLEM,
- "Number of chunk types with flags exceeds currently allowed limit."
- "Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and"
- "recompiling both the kernel space and user space modules\n");
+ xtables_error(PARAMETER_PROBLEM,
+ "Number of chunk types with flags exceeds currently allowed limit. Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and recompiling both the kernel space and user space modules");
}
flag_info[*flag_count].chunktype = chunktype;
@@ -163,7 +166,7 @@ parse_sctp_chunk(struct xt_sctp_info *einfo,
int found = 0;
char *chunk_flags;
- buffer = strdup(chunks);
+ buffer = xtables_strdup(chunks);
DEBUGP("Buffer: %s\n", buffer);
SCTP_CHUNKMAP_RESET(einfo->chunkmap);
@@ -214,7 +217,8 @@ parse_sctp_chunk(struct xt_sctp_info *einfo,
isupper(chunk_flags[j]));
} else {
xtables_error(PARAMETER_PROBLEM,
- "Invalid flags for chunk type %d\n", i);
+ "Invalid flags for chunk type %d",
+ i);
}
}
}
@@ -485,41 +489,85 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static void sctp_xlate_chunk(struct xt_xlate *xl,
+ const struct xt_sctp_info *einfo,
+ const struct sctp_chunk_names *scn)
+{
+ bool inv = einfo->invflags & XT_SCTP_CHUNK_TYPES;
+ const struct xt_sctp_flag_info *flag_info = NULL;
+ int i;
+
+ if (!scn->nftname)
+ return;
+
+ if (!SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, scn->chunk_type)) {
+ if (einfo->chunk_match_type != SCTP_CHUNK_MATCH_ONLY)
+ return;
+
+ xt_xlate_add(xl, "sctp chunk %s %s",
+ scn->nftname, inv ? "exists" : "missing");
+ return;
+ }
+
+ for (i = 0; i < einfo->flag_count; i++) {
+ if (einfo->flag_info[i].chunktype == scn->chunk_type) {
+ flag_info = &einfo->flag_info[i];
+ break;
+ }
+ }
+
+ if (!flag_info) {
+ xt_xlate_add(xl, "sctp chunk %s %s",
+ scn->nftname, inv ? "missing" : "exists");
+ return;
+ }
+
+ xt_xlate_add(xl, "sctp chunk %s flags & 0x%x %s 0x%x",
+ scn->nftname, flag_info->flag_mask,
+ inv ? "!=" : "==", flag_info->flag);
+}
+
static int sctp_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct xt_sctp_info *einfo =
(const struct xt_sctp_info *)params->match->data;
- char *space = "";
if (!einfo->flags)
return 0;
- xt_xlate_add(xl, "sctp ");
-
if (einfo->flags & XT_SCTP_SRC_PORTS) {
if (einfo->spts[0] != einfo->spts[1])
- xt_xlate_add(xl, "sport%s %u-%u",
+ xt_xlate_add(xl, "sctp sport%s %u-%u",
einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
einfo->spts[0], einfo->spts[1]);
else
- xt_xlate_add(xl, "sport%s %u",
+ xt_xlate_add(xl, "sctp sport%s %u",
einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
einfo->spts[0]);
- space = " ";
}
if (einfo->flags & XT_SCTP_DEST_PORTS) {
if (einfo->dpts[0] != einfo->dpts[1])
- xt_xlate_add(xl, "%sdport%s %u-%u", space,
+ xt_xlate_add(xl, "sctp dport%s %u-%u",
einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
einfo->dpts[0], einfo->dpts[1]);
else
- xt_xlate_add(xl, "%sdport%s %u", space,
+ xt_xlate_add(xl, "sctp dport%s %u",
einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
einfo->dpts[0]);
}
+ if (einfo->flags & XT_SCTP_CHUNK_TYPES) {
+ int i;
+
+ if (einfo->chunk_match_type == SCTP_CHUNK_MATCH_ANY)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(sctp_chunk_names); i++)
+ sctp_xlate_chunk(xl, einfo, &sctp_chunk_names[i]);
+ }
+
return 1;
}
diff --git a/extensions/libxt_sctp.man b/extensions/libxt_sctp.man
index 3779d05a..06da04f8 100644
--- a/extensions/libxt_sctp.man
+++ b/extensions/libxt_sctp.man
@@ -8,12 +8,25 @@ This module matches Stream Control Transmission Protocol headers.
The flag letter in upper case indicates that the flag is to match if set,
in the lower case indicates to match if unset.
-Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK FORWARD_TSN
+Match types:
+.TP
+all
+Match if all given chunk types are present and flags match.
+.TP
+any
+Match if any of the given chunk types is present with given flags.
+.TP
+only
+Match if only the given chunk types are present with given flags and none are missing.
+
+Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE I_DATA RE_CONFIG PAD ASCONF ASCONF_ACK FORWARD_TSN I_FORWARD_TSN
chunk type available flags
.br
DATA I U B E i u b e
.br
+I_DATA I U B E i u b e
+.br
ABORT T t
.br
SHUTDOWN_COMPLETE T t
diff --git a/extensions/libxt_sctp.t b/extensions/libxt_sctp.t
index 4016e4fb..4d3b113d 100644
--- a/extensions/libxt_sctp.t
+++ b/extensions/libxt_sctp.t
@@ -27,3 +27,7 @@
-p sctp -m sctp --chunk-types all ASCONF_ACK;=;OK
-p sctp -m sctp --chunk-types all FORWARD_TSN;=;OK
-p sctp -m sctp --chunk-types all SHUTDOWN_COMPLETE;=;OK
+-p sctp -m sctp --chunk-types all I_DATA;=;OK
+-p sctp -m sctp --chunk-types all RE_CONFIG;=;OK
+-p sctp -m sctp --chunk-types all PAD;=;OK
+-p sctp -m sctp --chunk-types all I_FORWARD_TSN;=;OK
diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate
index 72f4641a..0aa7371d 100644
--- a/extensions/libxt_sctp.txlate
+++ b/extensions/libxt_sctp.txlate
@@ -1,38 +1,44 @@
iptables-translate -A INPUT -p sctp --dport 80 -j DROP
-nft add rule ip filter INPUT sctp dport 80 counter drop
+nft 'add rule ip filter INPUT sctp dport 80 counter drop'
iptables-translate -A INPUT -p sctp --sport 50 -j DROP
-nft add rule ip filter INPUT sctp sport 50 counter drop
+nft 'add rule ip filter INPUT sctp sport 50 counter drop'
iptables-translate -A INPUT -p sctp ! --dport 80 -j DROP
-nft add rule ip filter INPUT sctp dport != 80 counter drop
+nft 'add rule ip filter INPUT sctp dport != 80 counter drop'
iptables-translate -A INPUT -p sctp ! --sport 50 -j DROP
-nft add rule ip filter INPUT sctp sport != 50 counter drop
+nft 'add rule ip filter INPUT sctp sport != 50 counter drop'
iptables-translate -A INPUT -p sctp --sport 80:100 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 80-100 counter accept
+nft 'add rule ip filter INPUT sctp sport 80-100 counter accept'
iptables-translate -A INPUT -p sctp --dport 50:56 -j ACCEPT
-nft add rule ip filter INPUT sctp dport 50-56 counter accept
+nft 'add rule ip filter INPUT sctp dport 50-56 counter accept'
iptables-translate -A INPUT -p sctp ! --sport 80:100 -j ACCEPT
-nft add rule ip filter INPUT sctp sport != 80-100 counter accept
+nft 'add rule ip filter INPUT sctp sport != 80-100 counter accept'
iptables-translate -A INPUT -p sctp ! --dport 50:56 -j ACCEPT
-nft add rule ip filter INPUT sctp dport != 50-56 counter accept
+nft 'add rule ip filter INPUT sctp dport != 50-56 counter accept'
iptables-translate -A INPUT -p sctp --dport 80 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport 80 counter accept
+nft 'add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept'
iptables-translate -A INPUT -p sctp --dport 80:100 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport 80-100 counter accept
+nft 'add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept'
iptables-translate -A INPUT -p sctp --dport 80 --sport 50:55 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50-55 dport 80 counter accept
+nft 'add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept'
iptables-translate -A INPUT -p sctp ! --dport 80:100 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport != 80-100 counter accept
+nft 'add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept'
iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT
-nft add rule ip filter INPUT sctp sport != 50-55 dport 80 counter accept
+nft 'add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept'
+
+iptables-translate -A INPUT -p sctp --chunk-types all INIT,DATA:iUbE,SACK,ABORT:T -j ACCEPT
+nft 'add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept'
+
+iptables-translate -A INPUT -p sctp --chunk-types only SHUTDOWN_COMPLETE -j ACCEPT
+nft 'add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk i-data missing sctp chunk re-config missing sctp chunk pad missing sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing sctp chunk i-forward-tsn missing counter accept'
diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c
index 16921023..471bde8a 100644
--- a/extensions/libxt_set.c
+++ b/extensions/libxt_set.c
@@ -22,6 +22,12 @@
#include <linux/netfilter/xt_set.h>
#include "libxt_set.h"
+#ifdef DEBUG
+#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args...)
+#endif
+
/* Revision 0 */
static void
@@ -328,8 +334,7 @@ parse_counter(const char *opt)
if (!xtables_strtoul(opt, NULL, &value, 0, UINT64_MAX))
xtables_error(PARAMETER_PROBLEM,
- "Cannot parse %s as a counter value\n",
- opt);
+ "Cannot parse %s as a counter value", opt);
return (uint64_t)value;
}
@@ -348,60 +353,54 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags,
case '0':
if (info->bytes.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --bytes-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --bytes-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--bytes-gt option cannot be inverted\n");
+ "--bytes-gt option cannot be inverted");
info->bytes.op = IPSET_COUNTER_GT;
info->bytes.value = parse_counter(optarg);
break;
case '9':
if (info->bytes.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --bytes-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --bytes-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--bytes-lt option cannot be inverted\n");
+ "--bytes-lt option cannot be inverted");
info->bytes.op = IPSET_COUNTER_LT;
info->bytes.value = parse_counter(optarg);
break;
case '8':
if (info->bytes.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --bytes-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --bytes-[eq|lt|gt] is allowed");
info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
info->bytes.value = parse_counter(optarg);
break;
case '7':
if (info->packets.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --packets-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --packets-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--packets-gt option cannot be inverted\n");
+ "--packets-gt option cannot be inverted");
info->packets.op = IPSET_COUNTER_GT;
info->packets.value = parse_counter(optarg);
break;
case '6':
if (info->packets.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --packets-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --packets-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--packets-lt option cannot be inverted\n");
+ "--packets-lt option cannot be inverted");
info->packets.op = IPSET_COUNTER_LT;
info->packets.value = parse_counter(optarg);
break;
case '5':
if (info->packets.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --packets-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --packets-[eq|lt|gt] is allowed");
info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
info->packets.value = parse_counter(optarg);
break;
@@ -412,7 +411,7 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags,
case '3':
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--return-nomatch flag cannot be inverted\n");
+ "--return-nomatch flag cannot be inverted");
info->flags |= IPSET_FLAG_RETURN_NOMATCH;
break;
case '2':
@@ -517,60 +516,54 @@ set_parse_v4(int c, char **argv, int invert, unsigned int *flags,
case '0':
if (info->bytes.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --bytes-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --bytes-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--bytes-gt option cannot be inverted\n");
+ "--bytes-gt option cannot be inverted");
info->bytes.op = IPSET_COUNTER_GT;
info->bytes.value = parse_counter(optarg);
break;
case '9':
if (info->bytes.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --bytes-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --bytes-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--bytes-lt option cannot be inverted\n");
+ "--bytes-lt option cannot be inverted");
info->bytes.op = IPSET_COUNTER_LT;
info->bytes.value = parse_counter(optarg);
break;
case '8':
if (info->bytes.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --bytes-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --bytes-[eq|lt|gt] is allowed");
info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
info->bytes.value = parse_counter(optarg);
break;
case '7':
if (info->packets.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --packets-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --packets-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--packets-gt option cannot be inverted\n");
+ "--packets-gt option cannot be inverted");
info->packets.op = IPSET_COUNTER_GT;
info->packets.value = parse_counter(optarg);
break;
case '6':
if (info->packets.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --packets-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --packets-[eq|lt|gt] is allowed");
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--packets-lt option cannot be inverted\n");
+ "--packets-lt option cannot be inverted");
info->packets.op = IPSET_COUNTER_LT;
info->packets.value = parse_counter(optarg);
break;
case '5':
if (info->packets.op != IPSET_COUNTER_NONE)
xtables_error(PARAMETER_PROBLEM,
- "only one of the --packets-[eq|lt|gt]"
- " is allowed\n");
+ "only one of the --packets-[eq|lt|gt] is allowed");
info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
info->packets.value = parse_counter(optarg);
break;
@@ -581,7 +574,7 @@ set_parse_v4(int c, char **argv, int invert, unsigned int *flags,
case '3':
if (invert)
xtables_error(PARAMETER_PROBLEM,
- "--return-nomatch flag cannot be inverted\n");
+ "--return-nomatch flag cannot be inverted");
info->flags |= IPSET_FLAG_RETURN_NOMATCH;
break;
case '2':
diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h
index 41dfbd30..b7de4cc4 100644
--- a/extensions/libxt_set.h
+++ b/extensions/libxt_set.h
@@ -6,12 +6,11 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
-#include "../iptables/xshared.h"
static int
get_version(unsigned *version)
{
- int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ int res, sockfd = socket(AF_INET, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
struct ip_set_req_version req_version;
socklen_t size = sizeof(req_version);
@@ -19,12 +18,6 @@ get_version(unsigned *version)
xtables_error(OTHER_PROBLEM,
"Can't open socket to ipset.\n");
- if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
- xtables_error(OTHER_PROBLEM,
- "Could not set close on exec: %s\n",
- strerror(errno));
- }
-
req_version.op = IP_SET_OP_VERSION;
res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size);
if (res != 0)
@@ -141,7 +134,7 @@ get_set_byname(const char *setname, struct xt_set_info *info)
static void
parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
{
- char *saved = strdup(opt_arg);
+ char *saved = xtables_strdup(opt_arg);
char *ptr, *tmp = saved;
int i = 0;
@@ -153,7 +146,7 @@ parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
info->u.flags[i++] |= IPSET_DST;
else
xtables_error(PARAMETER_PROBLEM,
- "You must spefify (the comma separated list of) 'src' or 'dst'.");
+ "You must specify (the comma separated list of) 'src' or 'dst'.");
}
if (tmp)
@@ -167,7 +160,7 @@ parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
static void
parse_dirs(const char *opt_arg, struct xt_set_info *info)
{
- char *saved = strdup(opt_arg);
+ char *saved = xtables_strdup(opt_arg);
char *ptr, *tmp = saved;
while (info->dim < IPSET_DIM_MAX && tmp != NULL) {
@@ -177,7 +170,7 @@ parse_dirs(const char *opt_arg, struct xt_set_info *info)
info->flags |= (1 << info->dim);
else if (strncmp(ptr, "dst", 3) != 0)
xtables_error(PARAMETER_PROBLEM,
- "You must spefify (the comma separated list of) 'src' or 'dst'.");
+ "You must specify (the comma separated list of) 'src' or 'dst'.");
}
if (tmp)
diff --git a/extensions/libxt_socket.c b/extensions/libxt_socket.c
index a99135cd..2dcfa221 100644
--- a/extensions/libxt_socket.c
+++ b/extensions/libxt_socket.c
@@ -159,6 +159,37 @@ socket_mt_print_v3(const void *ip, const struct xt_entry_match *match,
socket_mt_save_v3(ip, match);
}
+static int socket_mt_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params)
+{
+ const struct xt_socket_mtinfo3 *info = (const void *)params->match->data;
+
+ /* ONLY --nowildcard: match if socket exists. It does not matter
+ * to which address it is bound.
+ */
+ if (info->flags == XT_SOCKET_NOWILDCARD) {
+ xt_xlate_add(xl, "socket wildcard le 1");
+ return 1;
+ }
+
+ /* Without --nowildcard, restrict to sockets NOT bound to
+ * the any address.
+ */
+ if ((info->flags & XT_SOCKET_NOWILDCARD) == 0)
+ xt_xlate_add(xl, "socket wildcard 0");
+
+ if (info->flags & XT_SOCKET_TRANSPARENT)
+ xt_xlate_add(xl, "socket transparent 1");
+
+ /* If --nowildcard was given, -m socket should not test
+ * the bound address. We can simply ignore this; its
+ * equal to "wildcard <= 1".
+ */
+ if (info->flags & XT_SOCKET_RESTORESKMARK)
+ xt_xlate_add(xl, "meta mark set socket mark");
+
+ return 1;
+}
+
static struct xtables_match socket_mt_reg[] = {
{
.name = "socket",
@@ -180,6 +211,7 @@ static struct xtables_match socket_mt_reg[] = {
.save = socket_mt_save,
.x6_parse = socket_mt_parse,
.x6_options = socket_mt_opts,
+ .xlate = socket_mt_xlate,
},
{
.name = "socket",
@@ -193,6 +225,7 @@ static struct xtables_match socket_mt_reg[] = {
.save = socket_mt_save_v2,
.x6_parse = socket_mt_parse_v2,
.x6_options = socket_mt_opts_v2,
+ .xlate = socket_mt_xlate,
},
{
.name = "socket",
@@ -206,6 +239,7 @@ static struct xtables_match socket_mt_reg[] = {
.save = socket_mt_save_v3,
.x6_parse = socket_mt_parse_v3,
.x6_options = socket_mt_opts_v3,
+ .xlate = socket_mt_xlate,
},
};
diff --git a/extensions/libxt_socket.man b/extensions/libxt_socket.man
index f809df69..a268b443 100644
--- a/extensions/libxt_socket.man
+++ b/extensions/libxt_socket.man
@@ -29,7 +29,7 @@ to be matched when restoring the packet mark.
Example: An application opens 2 transparent (\fBIP_TRANSPARENT\fP) sockets and
sets a mark on them with \fBSO_MARK\fP socket option. We can filter matching packets:
.IP
-\-t mangle \-I PREROUTING \-m socket \-\-transparent \-\-restore-skmark \-j action
+\-t mangle \-I PREROUTING \-m socket \-\-transparent \-\-restore\-skmark \-j action
.IP
\-t mangle \-A action \-m mark \-\-mark 10 \-j action2
.IP
diff --git a/extensions/libxt_socket.txlate b/extensions/libxt_socket.txlate
new file mode 100644
index 00000000..7731e42e
--- /dev/null
+++ b/extensions/libxt_socket.txlate
@@ -0,0 +1,17 @@
+# old socket match, no options. Matches if sk can be found and it is not bound to 0.0.0.0/::
+iptables-translate -A INPUT -m socket
+nft 'add rule ip filter INPUT socket wildcard 0 counter'
+
+iptables-translate -A INPUT -m socket --transparent
+nft 'add rule ip filter INPUT socket wildcard 0 socket transparent 1 counter'
+
+# Matches if sk can be found. Doesn't matter as to what addess it is bound to.
+# therefore, emulate "exists".
+iptables-translate -A INPUT -m socket --nowildcard
+nft 'add rule ip filter INPUT socket wildcard le 1 counter'
+
+iptables-translate -A INPUT -m socket --restore-skmark
+nft 'add rule ip filter INPUT socket wildcard 0 meta mark set socket mark counter'
+
+iptables-translate -A INPUT -m socket --transparent --nowildcard --restore-skmark
+nft 'add rule ip filter INPUT socket transparent 1 meta mark set socket mark counter'
diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t
index 4313f7b7..7c83cfa3 100644
--- a/extensions/libxt_standard.t
+++ b/extensions/libxt_standard.t
@@ -9,3 +9,20 @@
-j ACCEPT;=;OK
-j RETURN;=;OK
! -p 0 -j ACCEPT;=;FAIL
+-s 10.11.12.13/8;-s 10.0.0.0/8;OK
+-s 10.11.12.13/9;-s 10.0.0.0/9;OK
+-s 10.11.12.13/10;-s 10.0.0.0/10;OK
+-s 10.11.12.13/11;-s 10.0.0.0/11;OK
+-s 10.11.12.13/12;-s 10.0.0.0/12;OK
+-s 10.11.12.13/30;-s 10.11.12.12/30;OK
+-s 10.11.12.13/31;-s 10.11.12.12/31;OK
+-s 10.11.12.13/32;-s 10.11.12.13/32;OK
+-s 10.11.12.13/255.0.0.0;-s 10.0.0.0/8;OK
+-s 10.11.12.13/255.128.0.0;-s 10.0.0.0/9;OK
+-s 10.11.12.13/255.0.255.0;-s 10.0.12.0/255.0.255.0;OK
+-s 10.11.12.13/255.0.12.0;-s 10.0.12.0/255.0.12.0;OK
+:FORWARD
+--protocol=tcp --source=1.2.3.4 --destination=5.6.7.8/32 --in-interface=eth0 --out-interface=eth1 --jump=ACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK
+-ptcp -s1.2.3.4 -d5.6.7.8/32 -ieth0 -oeth1 -jACCEPT;-s 1.2.3.4/32 -d 5.6.7.8/32 -i eth0 -o eth1 -p tcp -j ACCEPT;OK
+-i + -d 1.2.3.4;-d 1.2.3.4/32;OK
+-i + -p tcp;-p tcp;OK
diff --git a/extensions/libxt_statistic.c b/extensions/libxt_statistic.c
index 4f3341a3..37915adc 100644
--- a/extensions/libxt_statistic.c
+++ b/extensions/libxt_statistic.c
@@ -141,13 +141,19 @@ static int statistic_xlate(struct xt_xlate *xl,
switch (info->mode) {
case XT_STATISTIC_MODE_RANDOM:
- return 0;
+ xt_xlate_add(xl, "meta random & %u %s %u",
+ INT_MAX,
+ info->flags & XT_STATISTIC_INVERT ? ">=" : "<",
+ info->u.random.probability);
+ break;
case XT_STATISTIC_MODE_NTH:
xt_xlate_add(xl, "numgen inc mod %u %s%u",
info->u.nth.every + 1,
info->flags & XT_STATISTIC_INVERT ? "!= " : "",
info->u.nth.packet);
break;
+ default:
+ return 0;
}
return 1;
diff --git a/extensions/libxt_statistic.txlate b/extensions/libxt_statistic.txlate
index 4c3dea43..627120c5 100644
--- a/extensions/libxt_statistic.txlate
+++ b/extensions/libxt_statistic.txlate
@@ -1,8 +1,8 @@
iptables-translate -A OUTPUT -m statistic --mode nth --every 10 --packet 1
-nft add rule ip filter OUTPUT numgen inc mod 10 1 counter
+nft 'add rule ip filter OUTPUT numgen inc mod 10 1 counter'
iptables-translate -A OUTPUT -m statistic --mode nth ! --every 10 --packet 5
-nft add rule ip filter OUTPUT numgen inc mod 10 != 5 counter
+nft 'add rule ip filter OUTPUT numgen inc mod 10 != 5 counter'
iptables-translate -A OUTPUT -m statistic --mode random --probability 0.1
-nft # -A OUTPUT -m statistic --mode random --probability 0.1
+nft 'add rule ip filter OUTPUT meta random & 2147483647 < 214748365 counter'
diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c
index 7c6366cb..5d72a5cd 100644
--- a/extensions/libxt_string.c
+++ b/extensions/libxt_string.c
@@ -78,14 +78,13 @@ static void string_init(struct xt_entry_match *m)
static void
parse_string(const char *s, struct xt_string_info *info)
-{
+{
/* xt_string does not need \0 at the end of the pattern */
- if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
- strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
- info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
- return;
- }
- xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
+ if (strlen(s) > sizeof(info->pattern))
+ xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
+
+ info->patlen = strnlen(s, sizeof(info->pattern));
+ memcpy(info->pattern, s, info->patlen);
}
static void
@@ -269,7 +268,7 @@ string_print(const void *ip, const struct xt_entry_match *match, int numeric)
printf(" ALGO name %s", info->algo);
if (info->from_offset != 0)
printf(" FROM %u", info->from_offset);
- if (info->to_offset != 0)
+ if (info->to_offset != UINT16_MAX)
printf(" TO %u", info->to_offset);
if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
printf(" ICASE");
@@ -293,7 +292,7 @@ static void string_save(const void *ip, const struct xt_entry_match *match)
printf(" --algo %s", info->algo);
if (info->from_offset != 0)
printf(" --from %u", info->from_offset);
- if (info->to_offset != 0)
+ if (info->to_offset != UINT16_MAX)
printf(" --to %u", info->to_offset);
if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
printf(" --icase");
diff --git a/extensions/libxt_string.man b/extensions/libxt_string.man
index 5f1a993c..bdeb0a62 100644
--- a/extensions/libxt_string.man
+++ b/extensions/libxt_string.man
@@ -7,8 +7,9 @@ Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morri
Set the offset from which it starts looking for any matching. If not passed, default is 0.
.TP
\fB\-\-to\fP \fIoffset\fP
-Set the offset up to which should be scanned. That is, byte \fIoffset\fP-1
-(counting from 0) is the last one that is scanned.
+Set the offset up to which should be scanned. That is, byte \fIoffset\fP
+(counting from 0) is the last one that is scanned and the maximum position of
+\fIpattern\fP's last character.
If not passed, default is the packet size.
.TP
[\fB!\fP] \fB\-\-string\fP \fIpattern\fP
@@ -29,3 +30,18 @@ iptables \-A INPUT \-p tcp \-\-dport 80 \-m string \-\-algo bm \-\-string 'GET /
# The hex string pattern can be used for non-printable characters, like |0D 0A| or |0D0A|.
.br
iptables \-p udp \-\-dport 53 \-m string \-\-algo bm \-\-from 40 \-\-to 57 \-\-hex\-string '|03|www|09|netfilter|03|org|00|'
+.P
+Note: Since Boyer-Moore (BM) performs searches for matches from right to left and
+the kernel may store a packet in multiple discontiguous blocks, it's possible
+that a match could be spread over multiple blocks, in which case this algorithm
+won't find it.
+.P
+If you wish to ensure that such thing won't ever happen, use the
+Knuth-Pratt-Morris (KMP) algorithm instead. In conclusion, choose the proper
+string search algorithm depending on your use-case.
+.P
+For example, if you're using the module for filtering, NIDS or any similar
+security-focused purpose, then choose KMP. On the other hand, if you really care
+about performance \(em for example, you're classifying packets to apply Quality
+of Service (QoS) policies \(em and you don't mind about missing possible matches
+spread over multiple fragments, then choose BM.
diff --git a/extensions/libxt_string.t b/extensions/libxt_string.t
index d68f099d..2f4b30cb 100644
--- a/extensions/libxt_string.t
+++ b/extensions/libxt_string.t
@@ -1,18 +1,11 @@
:INPUT,FORWARD,OUTPUT
-# ERROR: cannot find: iptables -I INPUT -m string --algo bm --string "test"
-# -m string --algo bm --string "test";=;OK
-# ERROR: cannot find: iptables -I INPUT -m string --algo kmp --string "test")
-# -m string --algo kmp --string "test";=;OK
-# ERROR: cannot find: iptables -I INPUT -m string --algo kmp ! --string "test"
-# -m string --algo kmp ! --string "test";=;OK
-# cannot find: iptables -I INPUT -m string --algo bm --string "xxxxxxxxxxx" ....]
-# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK
-# ERROR: cannot load: iptables -A INPUT -m string --algo bm --string "xxxx"
-# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK
-# ERROR: cannot load: iptables -A INPUT -m string --algo bm --hexstring "|0a0a0a0a|"
-# -m string --algo bm --hexstring "|0a0a0a0a|";=;OK
-# ERROR: cannot find: iptables -I INPUT -m string --algo bm --from 0 --to 65535 --string "test"
-# -m string --algo bm --from 0 --to 65535 --string "test";=;OK
+-m string --algo bm --string "test";-m string --string "test" --algo bm;OK
+-m string --string "test" --algo kmp;=;OK
+-m string ! --string "test" --algo kmp;=;OK
+-m string --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --algo bm;=;OK
+-m string --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --algo bm;;FAIL
+-m string --hex-string "|0a0a0a0a|" --algo bm;=;OK
+-m string --algo bm --from 0 --to 65535 --string "test";-m string --string "test" --algo bm;OK
-m string --algo wrong;;FAIL
-m string --algo bm;;FAIL
-m string;;FAIL
diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c
index 58f3c0a0..32bbd684 100644
--- a/extensions/libxt_tcp.c
+++ b/extensions/libxt_tcp.c
@@ -43,7 +43,7 @@ parse_tcp_ports(const char *portstring, uint16_t *ports)
char *buffer;
char *cp;
- buffer = strdup(portstring);
+ buffer = xtables_strdup(portstring);
if ((cp = strchr(buffer, ':')) == NULL)
ports[0] = ports[1] = xtables_parse_port(buffer, "tcp");
else {
@@ -83,7 +83,7 @@ parse_tcp_flag(const char *flags)
char *ptr;
char *buffer;
- buffer = strdup(flags);
+ buffer = xtables_strdup(flags);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
unsigned int i;
@@ -225,13 +225,18 @@ print_port(uint16_t port, int numeric)
printf("%s", service);
}
+static bool skip_ports_match(uint16_t min, uint16_t max, bool inv)
+{
+ return min == 0 && max == UINT16_MAX && !inv;
+}
+
static void
print_ports(const char *name, uint16_t min, uint16_t max,
int invert, int numeric)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFFFF || invert) {
+ if (!skip_ports_match(min, max, invert)) {
printf(" %s", name);
if (min == max) {
printf(":%s", inv);
@@ -315,10 +320,11 @@ tcp_print(const void *ip, const struct xt_entry_match *match, int numeric)
static void tcp_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_tcp *tcpinfo = (struct xt_tcp *)match->data;
+ bool inv_srcpt = tcpinfo->invflags & XT_TCP_INV_SRCPT;
+ bool inv_dstpt = tcpinfo->invflags & XT_TCP_INV_DSTPT;
- if (tcpinfo->spts[0] != 0
- || tcpinfo->spts[1] != 0xFFFF) {
- if (tcpinfo->invflags & XT_TCP_INV_SRCPT)
+ if (!skip_ports_match(tcpinfo->spts[0], tcpinfo->spts[1], inv_srcpt)) {
+ if (inv_srcpt)
printf(" !");
if (tcpinfo->spts[0]
!= tcpinfo->spts[1])
@@ -330,9 +336,8 @@ static void tcp_save(const void *ip, const struct xt_entry_match *match)
tcpinfo->spts[0]);
}
- if (tcpinfo->dpts[0] != 0
- || tcpinfo->dpts[1] != 0xFFFF) {
- if (tcpinfo->invflags & XT_TCP_INV_DSTPT)
+ if (!skip_ports_match(tcpinfo->dpts[0], tcpinfo->dpts[1], inv_dstpt)) {
+ if (inv_dstpt)
printf(" !");
if (tcpinfo->dpts[0]
!= tcpinfo->dpts[1])
@@ -380,10 +385,9 @@ static void print_tcp_xlate(struct xt_xlate *xl, uint8_t flags)
for (i = 0; (flags & tcp_flag_names_xlate[i].flag) == 0; i++);
- if (have_flag)
- xt_xlate_add(xl, "|");
-
- xt_xlate_add(xl, "%s", tcp_flag_names_xlate[i].name);
+ xt_xlate_add(xl, "%s%s",
+ have_flag ? "," : "",
+ tcp_flag_names_xlate[i].name);
have_flag = 1;
flags &= ~tcp_flag_names_xlate[i].flag;
@@ -398,50 +402,55 @@ static int tcp_xlate(struct xt_xlate *xl,
{
const struct xt_tcp *tcpinfo =
(const struct xt_tcp *)params->match->data;
- char *space= "";
+ bool inv_srcpt = tcpinfo->invflags & XT_TCP_INV_SRCPT;
+ bool inv_dstpt = tcpinfo->invflags & XT_TCP_INV_DSTPT;
+ bool xlated = false;
- if (tcpinfo->spts[0] != 0 || tcpinfo->spts[1] != 0xffff) {
+ if (!skip_ports_match(tcpinfo->spts[0], tcpinfo->spts[1], inv_srcpt)) {
if (tcpinfo->spts[0] != tcpinfo->spts[1]) {
xt_xlate_add(xl, "tcp sport %s%u-%u",
- tcpinfo->invflags & XT_TCP_INV_SRCPT ?
- "!= " : "",
+ inv_srcpt ? "!= " : "",
tcpinfo->spts[0], tcpinfo->spts[1]);
} else {
xt_xlate_add(xl, "tcp sport %s%u",
- tcpinfo->invflags & XT_TCP_INV_SRCPT ?
- "!= " : "",
+ inv_srcpt ? "!= " : "",
tcpinfo->spts[0]);
}
- space = " ";
+ xlated = true;
}
- if (tcpinfo->dpts[0] != 0 || tcpinfo->dpts[1] != 0xffff) {
+ if (!skip_ports_match(tcpinfo->dpts[0], tcpinfo->dpts[1], inv_dstpt)) {
if (tcpinfo->dpts[0] != tcpinfo->dpts[1]) {
- xt_xlate_add(xl, "%stcp dport %s%u-%u", space,
- tcpinfo->invflags & XT_TCP_INV_DSTPT ?
- "!= " : "",
+ xt_xlate_add(xl, "tcp dport %s%u-%u",
+ inv_dstpt ? "!= " : "",
tcpinfo->dpts[0], tcpinfo->dpts[1]);
} else {
- xt_xlate_add(xl, "%stcp dport %s%u", space,
- tcpinfo->invflags & XT_TCP_INV_DSTPT ?
- "!= " : "",
+ xt_xlate_add(xl, "tcp dport %s%u",
+ inv_dstpt ? "!= " : "",
tcpinfo->dpts[0]);
}
- space = " ";
+ xlated = true;
}
- /* XXX not yet implemented */
- if (tcpinfo->option || (tcpinfo->invflags & XT_TCP_INV_OPTION))
- return 0;
+ if (tcpinfo->option) {
+ xt_xlate_add(xl, "tcp option %u %s", tcpinfo->option,
+ tcpinfo->invflags & XT_TCP_INV_OPTION ?
+ "missing" : "exists");
+ xlated = true;
+ }
if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) {
- xt_xlate_add(xl, "%stcp flags & (", space);
- print_tcp_xlate(xl, tcpinfo->flg_mask);
- xt_xlate_add(xl, ") %s ",
- tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!=": "==");
+ xt_xlate_add(xl, "tcp flags %s",
+ tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!= ": "");
print_tcp_xlate(xl, tcpinfo->flg_cmp);
+ xt_xlate_add(xl, " / ");
+ print_tcp_xlate(xl, tcpinfo->flg_mask);
+ xlated = true;
}
+ if (!xlated)
+ xt_xlate_add(xl, "meta l4proto tcp");
+
return 1;
}
diff --git a/extensions/libxt_tcp.t b/extensions/libxt_tcp.t
index b0e8006e..75d5b1ed 100644
--- a/extensions/libxt_tcp.t
+++ b/extensions/libxt_tcp.t
@@ -6,6 +6,18 @@
-p tcp -m tcp --sport 1:1023;=;OK
-p tcp -m tcp --sport 1024:65535;=;OK
-p tcp -m tcp --sport 1024:;-p tcp -m tcp --sport 1024:65535;OK
+-p tcp -m tcp --sport :;-p tcp -m tcp;OK
+-p tcp -m tcp ! --sport :;-p tcp -m tcp ! --sport 0:65535;OK
+-p tcp -m tcp --sport :4;-p tcp -m tcp --sport 0:4;OK
+-p tcp -m tcp --sport 4:;-p tcp -m tcp --sport 4:65535;OK
+-p tcp -m tcp --sport 4:4;-p tcp -m tcp --sport 4;OK
+-p tcp -m tcp --sport 4:3;;FAIL
+-p tcp -m tcp --dport :;-p tcp -m tcp;OK
+-p tcp -m tcp ! --dport :;-p tcp -m tcp ! --dport 0:65535;OK
+-p tcp -m tcp --dport :4;-p tcp -m tcp --dport 0:4;OK
+-p tcp -m tcp --dport 4:;-p tcp -m tcp --dport 4:65535;OK
+-p tcp -m tcp --dport 4:4;-p tcp -m tcp --dport 4;OK
+-p tcp -m tcp --dport 4:3;;FAIL
-p tcp -m tcp ! --sport 1;=;OK
-p tcp -m tcp ! --sport 65535;=;OK
-p tcp -m tcp ! --dport 1;=;OK
@@ -22,5 +34,8 @@
-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK
-p tcp -m tcp ! --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK
-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG RST;=;OK
+-m tcp --dport 1;;FAIL
+-m tcp --dport 1 -p tcp;-p tcp -m tcp --dport 1;OK
+-m tcp --dport 1 -p 6;-p tcp -m tcp --dport 1;OK
# should we accept this below?
-p tcp -m tcp;=;OK
diff --git a/extensions/libxt_tcp.txlate b/extensions/libxt_tcp.txlate
index bba63324..b3ddcc15 100644
--- a/extensions/libxt_tcp.txlate
+++ b/extensions/libxt_tcp.txlate
@@ -1,26 +1,38 @@
iptables-translate -A INPUT -p tcp -i eth0 --sport 53 -j ACCEPT
-nft add rule ip filter INPUT iifname "eth0" tcp sport 53 counter accept
+nft 'add rule ip filter INPUT iifname "eth0" tcp sport 53 counter accept'
iptables-translate -A OUTPUT -p tcp -o eth0 --dport 53:66 -j DROP
-nft add rule ip filter OUTPUT oifname "eth0" tcp dport 53-66 counter drop
+nft 'add rule ip filter OUTPUT oifname "eth0" tcp dport 53-66 counter drop'
iptables-translate -I OUTPUT -p tcp -d 8.8.8.8 -j ACCEPT
-nft insert rule ip filter OUTPUT ip protocol tcp ip daddr 8.8.8.8 counter accept
+nft 'insert rule ip filter OUTPUT ip protocol tcp ip daddr 8.8.8.8 counter accept'
iptables-translate -I OUTPUT -p tcp --dport 1020:1023 --sport 53 -j ACCEPT
-nft insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept
+nft 'insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept'
iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP
-nft add rule ip filter INPUT tcp flags & fin|ack == fin counter drop
+nft 'add rule ip filter INPUT tcp flags fin / fin,ack counter drop'
iptables-translate -A INPUT -p tcp --syn -j ACCEPT
-nft add rule ip filter INPUT tcp flags & (fin|syn|rst|ack) == syn counter accept
+nft 'add rule ip filter INPUT tcp flags syn / fin,syn,rst,ack counter accept'
iptables-translate -A INPUT -p tcp --syn --dport 80 -j ACCEPT
-nft add rule ip filter INPUT tcp dport 80 tcp flags & (fin|syn|rst|ack) == syn counter accept
+nft 'add rule ip filter INPUT tcp dport 80 tcp flags syn / fin,syn,rst,ack counter accept'
iptables-translate -A INPUT -f -p tcp
-nft add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter
+nft 'add rule ip filter INPUT ip frag-off & 0x1fff != 0 ip protocol tcp counter'
iptables-translate -A INPUT ! -f -p tcp --dport 22
-nft add rule ip filter INPUT ip frag-off & 0x1fff 0 tcp dport 22 counter
+nft 'add rule ip filter INPUT ip frag-off & 0x1fff 0 tcp dport 22 counter'
+
+iptables-translate -A INPUT -p tcp --tcp-option 23
+nft 'add rule ip filter INPUT tcp option 23 exists counter'
+
+iptables-translate -A INPUT -p tcp ! --tcp-option 23
+nft 'add rule ip filter INPUT tcp option 23 missing counter'
+
+iptables-translate -I OUTPUT -p tcp --sport 0:65535 -j ACCEPT
+nft 'insert rule ip filter OUTPUT meta l4proto tcp counter accept'
+
+iptables-translate -I OUTPUT -p tcp ! --sport 0:65535 -j ACCEPT
+nft 'insert rule ip filter OUTPUT tcp sport != 0-65535 counter accept'
diff --git a/extensions/libxt_tcpmss.c b/extensions/libxt_tcpmss.c
index bcd357aa..61b853d1 100644
--- a/extensions/libxt_tcpmss.c
+++ b/extensions/libxt_tcpmss.c
@@ -60,6 +60,21 @@ static void tcpmss_save(const void *ip, const struct xt_entry_match *match)
printf("%u:%u", info->mss_min, info->mss_max);
}
+static int tcpmss_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_tcpmss_match_info *info = (void *)params->match->data;
+
+ xt_xlate_add(xl, "tcp option maxseg size %s", info->invert ? "!= " : "");
+
+ if (info->mss_min == info->mss_max)
+ xt_xlate_add(xl, "%u", info->mss_min);
+ else
+ xt_xlate_add(xl, "%u-%u", info->mss_min, info->mss_max);
+
+ return 1;
+}
+
static struct xtables_match tcpmss_match = {
.family = NFPROTO_UNSPEC,
.name = "tcpmss",
@@ -71,6 +86,7 @@ static struct xtables_match tcpmss_match = {
.save = tcpmss_save,
.x6_parse = tcpmss_parse,
.x6_options = tcpmss_opts,
+ .xlate = tcpmss_xlate,
};
void _init(void)
diff --git a/extensions/libxt_tcpmss.t b/extensions/libxt_tcpmss.t
index 2b415957..d0fb52fa 100644
--- a/extensions/libxt_tcpmss.t
+++ b/extensions/libxt_tcpmss.t
@@ -1,6 +1,10 @@
:INPUT,FORWARD,OUTPUT
-m tcpmss --mss 42;;FAIL
-p tcp -m tcpmss --mss 42;=;OK
+-p tcp -m tcpmss --mss :;-p tcp -m tcpmss --mss 0:65535;OK
+-p tcp -m tcpmss --mss :42;-p tcp -m tcpmss --mss 0:42;OK
+-p tcp -m tcpmss --mss 42:;-p tcp -m tcpmss --mss 42:65535;OK
+-p tcp -m tcpmss --mss 42:42;-p tcp -m tcpmss --mss 42;OK
-p tcp -m tcpmss --mss 42:12345;=;OK
-p tcp -m tcpmss --mss 42:65536;;FAIL
-p tcp -m tcpmss --mss 65535:1000;;FAIL
diff --git a/extensions/libxt_tcpmss.txlate b/extensions/libxt_tcpmss.txlate
new file mode 100644
index 00000000..82475e67
--- /dev/null
+++ b/extensions/libxt_tcpmss.txlate
@@ -0,0 +1,11 @@
+iptables-translate -A INPUT -m tcpmss --mss 42
+nft 'add rule ip filter INPUT tcp option maxseg size 42 counter'
+
+iptables-translate -A INPUT -m tcpmss ! --mss 42
+nft 'add rule ip filter INPUT tcp option maxseg size != 42 counter'
+
+iptables-translate -A INPUT -m tcpmss --mss 42:1024
+nft 'add rule ip filter INPUT tcp option maxseg size 42-1024 counter'
+
+iptables-translate -A INPUT -m tcpmss ! --mss 1461:65535
+nft 'add rule ip filter INPUT tcp option maxseg size != 1461-65535 counter'
diff --git a/extensions/libxt_time.c b/extensions/libxt_time.c
index d27d84ca..580861d3 100644
--- a/extensions/libxt_time.c
+++ b/extensions/libxt_time.c
@@ -466,9 +466,10 @@ static int time_xlate(struct xt_xlate *xl,
const struct xt_time_info *info =
(const struct xt_time_info *)params->match->data;
unsigned int h, m, s,
- i, sep, mask, count;
+ i, mask, count;
time_t tt_start, tt_stop;
struct tm *t_start, *t_stop;
+ const char *sep = "";
if (info->date_start != 0 ||
info->date_stop != INT_MAX) {
@@ -498,7 +499,6 @@ static int time_xlate(struct xt_xlate *xl,
if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS)
return 0;
if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) {
- sep = 0;
mask = info->weekdays_match;
count = time_count_weekdays(mask);
@@ -507,12 +507,8 @@ static int time_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, "{");
for (i = 1; i <= 7; ++i)
if (mask & (1 << i)) {
- if (sep)
- xt_xlate_add(xl, ",%u", i%7);
- else {
- xt_xlate_add(xl, "%u", i%7);
- ++sep;
- }
+ xt_xlate_add(xl, "%s%u", sep, i%7);
+ sep = ", ";
}
if (count > 1)
xt_xlate_add(xl, "}");
diff --git a/extensions/libxt_time.man b/extensions/libxt_time.man
index 4c0cae06..5b749a48 100644
--- a/extensions/libxt_time.man
+++ b/extensions/libxt_time.man
@@ -58,7 +58,7 @@ rest of the system uses).
The caveat with the kernel timezone is that Linux distributions may ignore to
set the kernel timezone, and instead only set the system time. Even if a
particular distribution does set the timezone at boot, it is usually does not
-keep the kernel timezone offset - which is what changes on DST - up to date.
+keep the kernel timezone offset \(em which is what changes on DST \(em up to date.
ntpd will not touch the kernel timezone, so running it will not resolve the
issue. As such, one may encounter a timezone that is always +0000, or one that
is wrong half of the time of the year. As such, \fBusing \-\-kerneltz is highly
diff --git a/extensions/libxt_time.txlate b/extensions/libxt_time.txlate
index ff4a7b88..ed64b957 100644
--- a/extensions/libxt_time.txlate
+++ b/extensions/libxt_time.txlate
@@ -1,26 +1,26 @@
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --weekdays Sa,Su -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta day {6,0} counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta day { 6, 0 } counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestart 12:00 -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta hour "12:00:00"-"23:59:59" counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --timestop 12:00 -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta hour "00:00:00"-"12:00:00" counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2021 -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta time "2021-01-01 00:00:00"-"2038-01-19 03:14:07" counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021 -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-01 00:00:00" counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestop 2021-01-29T00:00:00 -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta time "1970-01-01 00:00:00"-"2021-01-29 00:00:00" counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"23:59:59" counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {1,2,3,4,5} counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 1, 2, 3, 4, 5 } counter reject'
iptables-translate -A INPUT -p icmp --icmp-type echo-request -m time --datestart 2020-01-29T00:00:00 --timestart 12:00 --timestop 19:00 ! --weekdays Mon,Tue,Wed,Thu,Fri -j REJECT
-nft add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day {6,0} counter reject
+nft 'add rule ip filter INPUT icmp type echo-request meta time "2020-01-29 00:00:00"-"2038-01-19 03:14:07" meta hour "12:00:00"-"19:00:00" meta day { 6, 0 } counter reject'
diff --git a/extensions/libxt_tos.t b/extensions/libxt_tos.t
index ccbe8009..6cceeeb4 100644
--- a/extensions/libxt_tos.t
+++ b/extensions/libxt_tos.t
@@ -4,10 +4,10 @@
-m tos --tos Maximize-Reliability;-m tos --tos 0x04/0x3f;OK
-m tos --tos Minimize-Cost;-m tos --tos 0x02/0x3f;OK
-m tos --tos Normal-Service;-m tos --tos 0x00/0x3f;OK
--m tos --tos 0xff;=;OK
--m tos ! --tos 0xff;=;OK
--m tos --tos 0x00;=;OK
--m tos --tos 0x0f;=;OK
+-m tos --tos 0xff;-m tos --tos 0xff/0xff;OK
+-m tos ! --tos 0xff;-m tos ! --tos 0xff/0xff;OK
+-m tos --tos 0x00;-m tos --tos 0x00/0xff;OK
+-m tos --tos 0x0f;-m tos --tos 0x0f/0xff;OK
-m tos --tos 0x0f/0x0f;=;OK
-m tos --tos wrong;;FAIL
-m tos;;FAIL
diff --git a/extensions/libxt_u32.man b/extensions/libxt_u32.man
index 40a69f8e..183a63f7 100644
--- a/extensions/libxt_u32.man
+++ b/extensions/libxt_u32.man
@@ -69,13 +69,13 @@ Example:
.IP
match IP packets with total length >= 256
.IP
-The IP header contains a total length field in bytes 2-3.
+The IP header contains a total length field in bytes 2\(en3.
.IP
\-\-u32 "\fB0 & 0xFFFF = 0x100:0xFFFF\fP"
.IP
-read bytes 0-3
+read bytes 0\(en3
.IP
-AND that with 0xFFFF (giving bytes 2-3), and test whether that is in the range
+AND that with 0xFFFF (giving bytes 2\(en3), and test whether that is in the range
[0x100:0xFFFF]
.PP
Example: (more realistic, hence more complicated)
@@ -86,7 +86,7 @@ First test that it is an ICMP packet, true iff byte 9 (protocol) = 1
.IP
\-\-u32 "\fB6 & 0xFF = 1 &&\fP ...
.IP
-read bytes 6-9, use \fB&\fP to throw away bytes 6-8 and compare the result to
+read bytes 6\(en9, use \fB&\fP to throw away bytes 6\(en8 and compare the result to
1. Next test that it is not a fragment. (If so, it might be part of such a
packet but we cannot always tell.) N.B.: This test is generally needed if you
want to match anything beyond the IP header. The last 6 bits of byte 6 and all
@@ -101,11 +101,11 @@ stored in the right half of byte 0 of the IP header itself.
.IP
... \fB0 >> 22 & 0x3C @ 0 >> 24 = 0\fP"
.IP
-The first 0 means read bytes 0-3, \fB>>22\fP means shift that 22 bits to the
+The first 0 means read bytes 0\(en3, \fB>>22\fP means shift that 22 bits to the
right. Shifting 24 bits would give the first byte, so only 22 bits is four
times that plus a few more bits. \fB&3C\fP then eliminates the two extra bits
on the right and the first four bits of the first byte. For instance, if IHL=5,
-then the IP header is 20 (4 x 5) bytes long. In this case, bytes 0-1 are (in
+then the IP header is 20 (4 x 5) bytes long. In this case, bytes 0\(en1 are (in
binary) xxxx0101 yyzzzzzz, \fB>>22\fP gives the 10 bit value xxxx0101yy and
\fB&3C\fP gives 010100. \fB@\fP means to use this number as a new offset into
the packet, and read four bytes starting from there. This is the first 4 bytes
@@ -115,7 +115,7 @@ the result with 0.
.PP
Example:
.IP
-TCP payload bytes 8-12 is any of 1, 2, 5 or 8
+TCP payload bytes 8\(en12 is any of 1, 2, 5 or 8
.IP
First we test that the packet is a tcp packet (similar to ICMP).
.IP
@@ -130,5 +130,5 @@ makes this the new offset into the packet, which is the start of the TCP
header. The length of the TCP header (again in 32 bit words) is the left half
of byte 12 of the TCP header. The \fB12>>26&3C\fP computes this length in bytes
(similar to the IP header before). "@" makes this the new offset, which is the
-start of the TCP payload. Finally, 8 reads bytes 8-12 of the payload and
+start of the TCP payload. Finally, 8 reads bytes 8\(en12 of the payload and
\fB=\fP checks whether the result is any of 1, 2, 5 or 8.
diff --git a/extensions/libxt_udp.c b/extensions/libxt_udp.c
index 0c7a4bc2..748d4180 100644
--- a/extensions/libxt_udp.c
+++ b/extensions/libxt_udp.c
@@ -82,13 +82,18 @@ print_port(uint16_t port, int numeric)
printf("%s", service);
}
+static bool skip_ports_match(uint16_t min, uint16_t max, bool inv)
+{
+ return min == 0 && max == UINT16_MAX && !inv;
+}
+
static void
print_ports(const char *name, uint16_t min, uint16_t max,
int invert, int numeric)
{
const char *inv = invert ? "!" : "";
- if (min != 0 || max != 0xFFFF || invert) {
+ if (!skip_ports_match(min, max, invert)) {
printf(" %s", name);
if (min == max) {
printf(":%s", inv);
@@ -122,10 +127,11 @@ udp_print(const void *ip, const struct xt_entry_match *match, int numeric)
static void udp_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_udp *udpinfo = (struct xt_udp *)match->data;
+ bool inv_srcpt = udpinfo->invflags & XT_UDP_INV_SRCPT;
+ bool inv_dstpt = udpinfo->invflags & XT_UDP_INV_DSTPT;
- if (udpinfo->spts[0] != 0
- || udpinfo->spts[1] != 0xFFFF) {
- if (udpinfo->invflags & XT_UDP_INV_SRCPT)
+ if (!skip_ports_match(udpinfo->spts[0], udpinfo->spts[1], inv_srcpt)) {
+ if (inv_srcpt)
printf(" !");
if (udpinfo->spts[0]
!= udpinfo->spts[1])
@@ -137,9 +143,8 @@ static void udp_save(const void *ip, const struct xt_entry_match *match)
udpinfo->spts[0]);
}
- if (udpinfo->dpts[0] != 0
- || udpinfo->dpts[1] != 0xFFFF) {
- if (udpinfo->invflags & XT_UDP_INV_DSTPT)
+ if (!skip_ports_match(udpinfo->dpts[0], udpinfo->dpts[1], inv_dstpt)) {
+ if (inv_dstpt)
printf(" !");
if (udpinfo->dpts[0]
!= udpinfo->dpts[1])
@@ -156,37 +161,39 @@ static int udp_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct xt_udp *udpinfo = (struct xt_udp *)params->match->data;
- char *space= "";
+ bool inv_srcpt = udpinfo->invflags & XT_UDP_INV_SRCPT;
+ bool inv_dstpt = udpinfo->invflags & XT_UDP_INV_DSTPT;
+ bool xlated = false;
- if (udpinfo->spts[0] != 0 || udpinfo->spts[1] != 0xFFFF) {
+ if (!skip_ports_match(udpinfo->spts[0], udpinfo->spts[1], inv_srcpt)) {
if (udpinfo->spts[0] != udpinfo->spts[1]) {
xt_xlate_add(xl,"udp sport %s%u-%u",
- udpinfo->invflags & XT_UDP_INV_SRCPT ?
- "!= ": "",
+ inv_srcpt ? "!= ": "",
udpinfo->spts[0], udpinfo->spts[1]);
} else {
xt_xlate_add(xl, "udp sport %s%u",
- udpinfo->invflags & XT_UDP_INV_SRCPT ?
- "!= ": "",
+ inv_srcpt ? "!= ": "",
udpinfo->spts[0]);
}
- space = " ";
+ xlated = true;
}
- if (udpinfo->dpts[0] != 0 || udpinfo->dpts[1] != 0xFFFF) {
+ if (!skip_ports_match(udpinfo->dpts[0], udpinfo->dpts[1], inv_dstpt)) {
if (udpinfo->dpts[0] != udpinfo->dpts[1]) {
- xt_xlate_add(xl,"%sudp dport %s%u-%u", space,
- udpinfo->invflags & XT_UDP_INV_SRCPT ?
- "!= ": "",
+ xt_xlate_add(xl,"udp dport %s%u-%u",
+ inv_dstpt ? "!= ": "",
udpinfo->dpts[0], udpinfo->dpts[1]);
} else {
- xt_xlate_add(xl,"%sudp dport %s%u", space,
- udpinfo->invflags & XT_UDP_INV_SRCPT ?
- "!= ": "",
+ xt_xlate_add(xl,"udp dport %s%u",
+ inv_dstpt ? "!= ": "",
udpinfo->dpts[0]);
}
+ xlated = true;
}
+ if (!xlated)
+ xt_xlate_add(xl, "meta l4proto udp");
+
return 1;
}
diff --git a/extensions/libxt_udp.t b/extensions/libxt_udp.t
index 1b4d3dd6..6a2c9d07 100644
--- a/extensions/libxt_udp.t
+++ b/extensions/libxt_udp.t
@@ -6,6 +6,18 @@
-p udp -m udp --sport 1:1023;=;OK
-p udp -m udp --sport 1024:65535;=;OK
-p udp -m udp --sport 1024:;-p udp -m udp --sport 1024:65535;OK
+-p udp -m udp --sport :;-p udp -m udp;OK
+-p udp -m udp ! --sport :;-p udp -m udp ! --sport 0:65535;OK
+-p udp -m udp --sport :4;-p udp -m udp --sport 0:4;OK
+-p udp -m udp --sport 4:;-p udp -m udp --sport 4:65535;OK
+-p udp -m udp --sport 4:4;-p udp -m udp --sport 4;OK
+-p udp -m udp --sport 4:3;;FAIL
+-p udp -m udp --dport :;-p udp -m udp;OK
+-p udp -m udp ! --dport :;-p udp -m udp ! --dport 0:65535;OK
+-p udp -m udp --dport :4;-p udp -m udp --dport 0:4;OK
+-p udp -m udp --dport 4:;-p udp -m udp --dport 4:65535;OK
+-p udp -m udp --dport 4:4;-p udp -m udp --dport 4;OK
+-p udp -m udp --dport 4:3;;FAIL
-p udp -m udp ! --sport 1;=;OK
-p udp -m udp ! --sport 65535;=;OK
-p udp -m udp ! --dport 1;=;OK
@@ -18,5 +30,8 @@
# -p udp -m udp --sport 65536;;FAIL
-p udp -m udp --sport -1;;FAIL
-p udp -m udp --dport -1;;FAIL
+-m udp --dport 1;;FAIL
+-m udp --dport 1 -p udp;-p udp -m udp --dport 1;OK
+-m udp --dport 1 -p 17;-p udp -m udp --dport 1;OK
# should we accept this below?
-p udp -m udp;=;OK
diff --git a/extensions/libxt_udp.txlate b/extensions/libxt_udp.txlate
index fbca5c12..d6bbb96f 100644
--- a/extensions/libxt_udp.txlate
+++ b/extensions/libxt_udp.txlate
@@ -1,11 +1,17 @@
iptables-translate -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT
-nft add rule ip filter INPUT iifname "eth0" udp sport 53 counter accept
+nft 'add rule ip filter INPUT iifname "eth0" udp sport 53 counter accept'
iptables-translate -A OUTPUT -p udp -o eth0 --dport 53:66 -j DROP
-nft add rule ip filter OUTPUT oifname "eth0" udp dport 53-66 counter drop
+nft 'add rule ip filter OUTPUT oifname "eth0" udp dport 53-66 counter drop'
iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT
-nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept
+nft 'insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept'
iptables-translate -I OUTPUT -p udp --dport 1020:1023 --sport 53 -j ACCEPT
-nft insert rule ip filter OUTPUT udp sport 53 udp dport 1020-1023 counter accept
+nft 'insert rule ip filter OUTPUT udp sport 53 udp dport 1020-1023 counter accept'
+
+iptables-translate -I OUTPUT -p udp --sport 0:65535 -j ACCEPT
+nft 'insert rule ip filter OUTPUT meta l4proto udp counter accept'
+
+iptables-translate -I OUTPUT -p udp ! --sport 0:65535 -j ACCEPT
+nft 'insert rule ip filter OUTPUT udp sport != 0-65535 counter accept'
diff --git a/include/Makefile.am b/include/Makefile.am
index ea34c2fe..07c88b90 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,16 +1,18 @@
# -*- Makefile -*-
-include_HEADERS =
-nobase_include_HEADERS = xtables.h xtables-version.h
+include_HEADERS = xtables.h
+nodist_include_HEADERS = xtables-version.h
if ENABLE_LIBIPQ
include_HEADERS += libipq/libipq.h
endif
-nobase_include_HEADERS += \
+nobase_include_HEADERS = \
libiptc/ipt_kernel_headers.h libiptc/libiptc.h \
libiptc/libip6tc.h libiptc/libxtc.h libiptc/xtcshared.h
+EXTRA_DIST = iptables linux iptables.h ip6tables.h
+
uninstall-hook:
dir=${includedir}/libiptc; { \
test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \
diff --git a/include/libipq/libipq.h b/include/libipq/libipq.h
index 3cd13292..dd0cb205 100644
--- a/include/libipq/libipq.h
+++ b/include/libipq/libipq.h
@@ -24,7 +24,7 @@
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
-#include <sys/types.h>
+#include <stdint.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <asm/types.h>
@@ -48,19 +48,19 @@ typedef unsigned long ipq_id_t;
struct ipq_handle
{
int fd;
- u_int8_t blocking;
+ uint8_t blocking;
struct sockaddr_nl local;
struct sockaddr_nl peer;
};
-struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol);
+struct ipq_handle *ipq_create_handle(uint32_t flags, uint32_t protocol);
int ipq_destroy_handle(struct ipq_handle *h);
ssize_t ipq_read(const struct ipq_handle *h,
unsigned char *buf, size_t len, int timeout);
-int ipq_set_mode(const struct ipq_handle *h, u_int8_t mode, size_t len);
+int ipq_set_mode(const struct ipq_handle *h, uint8_t mode, size_t len);
ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf);
diff --git a/include/libiptc/libxtc.h b/include/libiptc/libxtc.h
index 37010188..a1d16ef9 100644
--- a/include/libiptc/libxtc.h
+++ b/include/libiptc/libxtc.h
@@ -10,7 +10,7 @@ extern "C" {
#endif
#ifndef XT_MIN_ALIGN
-/* xt_entry has pointers and u_int64_t's in it, so if you align to
+/* xt_entry has pointers and uint64_t's in it, so if you align to
it, you'll also align to any crazy matches and targets someone
might write */
#define XT_MIN_ALIGN (__alignof__(struct xt_entry))
diff --git a/include/libipulog/libipulog.h b/include/libipulog/libipulog.h
deleted file mode 100644
index 3f4cc2c7..00000000
--- a/include/libipulog/libipulog.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _LIBIPULOG_H
-#define _LIBIPULOG_H
-
-/* libipulog.h,v 1.3 2001/05/21 19:15:16 laforge Exp */
-
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <asm/types.h>
-#include <linux/netlink.h>
-#include <net/if.h>
-#include <linux/netfilter_ipv4/ipt_ULOG.h>
-
-/* FIXME: glibc sucks */
-#ifndef MSG_TRUNC
-#define MSG_TRUNC 0x20
-#endif
-
-struct ipulog_handle;
-
-u_int32_t ipulog_group2gmask(u_int32_t group);
-
-struct ipulog_handle *ipulog_create_handle(u_int32_t gmask);
-
-void ipulog_destroy_handle(struct ipulog_handle *h);
-
-ssize_t ipulog_read(struct ipulog_handle *h,
- unsigned char *buf, size_t len, int timeout);
-
-ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h,
- const unsigned char *buf,
- size_t len);
-
-void ipulog_perror(const char *s);
-
-#endif /* _LIBULOG_H */
diff --git a/include/linux/const.h b/include/linux/const.h
new file mode 100644
index 00000000..1eb84b50
--- /dev/null
+++ b/include/linux/const.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* const.h: Macros for dealing with constants. */
+
+#ifndef _LINUX_CONST_H
+#define _LINUX_CONST_H
+
+/* Some constant macros are used in both assembler and
+ * C code. Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally. We
+ * use the following macros to deal with this.
+ *
+ * Similarly, _AT() will cast an expression with a type in C, but
+ * leave it unchanged in asm.
+ */
+
+#ifdef __ASSEMBLY__
+#define _AC(X,Y) X
+#define _AT(T,X) X
+#else
+#define __AC(X,Y) (X##Y)
+#define _AC(X,Y) __AC(X,Y)
+#define _AT(T,X) ((T)(X))
+#endif
+
+#define _UL(x) (_AC(x, UL))
+#define _ULL(x) (_AC(x, ULL))
+
+#define _BITUL(x) (_UL(1) << (x))
+#define _BITULL(x) (_ULL(1) << (x))
+
+#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
+#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+#endif /* _LINUX_CONST_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d4c59f65..5413a8c5 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -1,29 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _LINUX_KERNEL_H
#define _LINUX_KERNEL_H
-/*
- * 'kernel.h' contains some often-used function prototypes etc
- */
-#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
-#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
+#include <linux/sysinfo.h>
+#include <linux/const.h>
-
-#define SI_LOAD_SHIFT 16
-struct sysinfo {
- long uptime; /* Seconds since boot */
- unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
- unsigned long totalram; /* Total usable main memory size */
- unsigned long freeram; /* Available memory size */
- unsigned long sharedram; /* Amount of shared memory */
- unsigned long bufferram; /* Memory used by buffers */
- unsigned long totalswap; /* Total swap space size */
- unsigned long freeswap; /* swap space still available */
- unsigned short procs; /* Number of current processes */
- unsigned short pad; /* explicit padding for m68k */
- unsigned long totalhigh; /* Total high memory size */
- unsigned long freehigh; /* Available high memory size */
- unsigned int mem_unit; /* Memory unit size in bytes */
- char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
-};
-
-#endif
+#endif /* _LINUX_KERNEL_H */
diff --git a/include/linux/netfilter/nf_log.h b/include/linux/netfilter/nf_log.h
new file mode 100644
index 00000000..2ae00932
--- /dev/null
+++ b/include/linux/netfilter/nf_log.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NETFILTER_NF_LOG_H
+#define _NETFILTER_NF_LOG_H
+
+#define NF_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
+#define NF_LOG_TCPOPT 0x02 /* Log TCP options */
+#define NF_LOG_IPOPT 0x04 /* Log IP options */
+#define NF_LOG_UID 0x08 /* Log UID owning local socket */
+#define NF_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
+#define NF_LOG_MACDECODE 0x20 /* Decode MAC header */
+#define NF_LOG_MASK 0x2f
+
+#define NF_LOG_PREFIXLEN 128
+
+#endif /* _NETFILTER_NF_LOG_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 66dceee0..c4d4d8e4 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -8,6 +8,7 @@
#define NFT_SET_MAXNAMELEN NFT_NAME_MAXLEN
#define NFT_OBJ_MAXNAMELEN NFT_NAME_MAXLEN
#define NFT_USERDATA_MAXLEN 256
+#define NFT_OSF_MAXGENRELEN 16
/**
* enum nft_registers - nf_tables registers
@@ -47,6 +48,7 @@ enum nft_registers {
#define NFT_REG_SIZE 16
#define NFT_REG32_SIZE 4
+#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1)
/**
* enum nft_verdicts - nf_tables internal verdicts
@@ -95,6 +97,14 @@ enum nft_verdicts {
* @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes)
* @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
* @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
+ * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes)
+ * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
+ * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
+ * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
+ * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
+ * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
+ * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
*/
enum nf_tables_msg_types {
NFT_MSG_NEWTABLE,
@@ -122,6 +132,14 @@ enum nf_tables_msg_types {
NFT_MSG_NEWFLOWTABLE,
NFT_MSG_GETFLOWTABLE,
NFT_MSG_DELFLOWTABLE,
+ NFT_MSG_GETRULE_RESET,
+ NFT_MSG_DESTROYTABLE,
+ NFT_MSG_DESTROYCHAIN,
+ NFT_MSG_DESTROYRULE,
+ NFT_MSG_DESTROYSET,
+ NFT_MSG_DESTROYSETELEM,
+ NFT_MSG_DESTROYOBJ,
+ NFT_MSG_DESTROYFLOWTABLE,
NFT_MSG_MAX,
};
@@ -131,7 +149,7 @@ enum nf_tables_msg_types {
* @NFTA_LIST_ELEM: list element (NLA_NESTED)
*/
enum nft_list_attributes {
- NFTA_LIST_UNPEC,
+ NFTA_LIST_UNSPEC,
NFTA_LIST_ELEM,
__NFTA_LIST_MAX
};
@@ -143,12 +161,14 @@ enum nft_list_attributes {
* @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
* @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
* @NFTA_HOOK_DEV: netdevice name (NLA_STRING)
+ * @NFTA_HOOK_DEVS: list of netdevices (NLA_NESTED)
*/
enum nft_hook_attributes {
NFTA_HOOK_UNSPEC,
NFTA_HOOK_HOOKNUM,
NFTA_HOOK_PRIORITY,
NFTA_HOOK_DEV,
+ NFTA_HOOK_DEVS,
__NFTA_HOOK_MAX
};
#define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1)
@@ -160,7 +180,10 @@ enum nft_hook_attributes {
*/
enum nft_table_flags {
NFT_TABLE_F_DORMANT = 0x1,
+ NFT_TABLE_F_OWNER = 0x2,
};
+#define NFT_TABLE_F_MASK (NFT_TABLE_F_DORMANT | \
+ NFT_TABLE_F_OWNER)
/**
* enum nft_table_attributes - nf_tables table netlink attributes
@@ -168,6 +191,8 @@ enum nft_table_flags {
* @NFTA_TABLE_NAME: name of the table (NLA_STRING)
* @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
* @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
+ * @NFTA_TABLE_USERDATA: user data (NLA_BINARY)
+ * @NFTA_TABLE_OWNER: owner of this table through netlink portID (NLA_U32)
*/
enum nft_table_attributes {
NFTA_TABLE_UNSPEC,
@@ -176,10 +201,21 @@ enum nft_table_attributes {
NFTA_TABLE_USE,
NFTA_TABLE_HANDLE,
NFTA_TABLE_PAD,
+ NFTA_TABLE_USERDATA,
+ NFTA_TABLE_OWNER,
__NFTA_TABLE_MAX
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
+enum nft_chain_flags {
+ NFT_CHAIN_BASE = (1 << 0),
+ NFT_CHAIN_HW_OFFLOAD = (1 << 1),
+ NFT_CHAIN_BINDING = (1 << 2),
+};
+#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \
+ NFT_CHAIN_HW_OFFLOAD | \
+ NFT_CHAIN_BINDING)
+
/**
* enum nft_chain_attributes - nf_tables chain netlink attributes
*
@@ -191,6 +227,9 @@ enum nft_table_attributes {
* @NFTA_CHAIN_USE: number of references to this chain (NLA_U32)
* @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
* @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
+ * @NFTA_CHAIN_FLAGS: chain flags
+ * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
+ * @NFTA_CHAIN_USERDATA: user data (NLA_BINARY)
*/
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
@@ -203,6 +242,9 @@ enum nft_chain_attributes {
NFTA_CHAIN_TYPE,
NFTA_CHAIN_COUNTERS,
NFTA_CHAIN_PAD,
+ NFTA_CHAIN_FLAGS,
+ NFTA_CHAIN_ID,
+ NFTA_CHAIN_USERDATA,
__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
@@ -218,6 +260,7 @@ enum nft_chain_attributes {
* @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
* @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
* @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32)
+ * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32)
*/
enum nft_rule_attributes {
NFTA_RULE_UNSPEC,
@@ -230,6 +273,8 @@ enum nft_rule_attributes {
NFTA_RULE_USERDATA,
NFTA_RULE_PAD,
NFTA_RULE_ID,
+ NFTA_RULE_POSITION_ID,
+ NFTA_RULE_CHAIN_ID,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
@@ -266,8 +311,10 @@ enum nft_rule_compat_attributes {
* @NFT_SET_INTERVAL: set contains intervals
* @NFT_SET_MAP: set is used as a dictionary
* @NFT_SET_TIMEOUT: set uses timeouts
- * @NFT_SET_EVAL: set contains expressions for evaluation
+ * @NFT_SET_EVAL: set can be updated from the evaluation path
* @NFT_SET_OBJECT: set contains stateful objects
+ * @NFT_SET_CONCAT: set contains a concatenation
+ * @NFT_SET_EXPR: set contains expressions
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
@@ -277,6 +324,8 @@ enum nft_set_flags {
NFT_SET_TIMEOUT = 0x10,
NFT_SET_EVAL = 0x20,
NFT_SET_OBJECT = 0x40,
+ NFT_SET_CONCAT = 0x80,
+ NFT_SET_EXPR = 0x100,
};
/**
@@ -294,15 +343,29 @@ enum nft_set_policies {
* enum nft_set_desc_attributes - set element description
*
* @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
+ * @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED)
*/
enum nft_set_desc_attributes {
NFTA_SET_DESC_UNSPEC,
NFTA_SET_DESC_SIZE,
+ NFTA_SET_DESC_CONCAT,
__NFTA_SET_DESC_MAX
};
#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1)
/**
+ * enum nft_set_field_attributes - attributes of concatenated fields
+ *
+ * @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32)
+ */
+enum nft_set_field_attributes {
+ NFTA_SET_FIELD_UNSPEC,
+ NFTA_SET_FIELD_LEN,
+ __NFTA_SET_FIELD_MAX
+};
+#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1)
+
+/**
* enum nft_set_attributes - nf_tables set netlink attributes
*
* @NFTA_SET_TABLE: table name (NLA_STRING)
@@ -320,6 +383,8 @@ enum nft_set_desc_attributes {
* @NFTA_SET_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
* @NFTA_SET_HANDLE: set handle (NLA_U64)
+ * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -339,6 +404,8 @@ enum nft_set_attributes {
NFTA_SET_PAD,
NFTA_SET_OBJ_TYPE,
NFTA_SET_HANDLE,
+ NFTA_SET_EXPR,
+ NFTA_SET_EXPRESSIONS,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -347,9 +414,11 @@ enum nft_set_attributes {
* enum nft_set_elem_flags - nf_tables set element flags
*
* @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
+ * @NFT_SET_ELEM_CATCHALL: special catch-all element
*/
enum nft_set_elem_flags {
NFT_SET_ELEM_INTERVAL_END = 0x1,
+ NFT_SET_ELEM_CATCHALL = 0x2,
};
/**
@@ -363,6 +432,8 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
* @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
+ * @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data)
+ * @NFTA_SET_ELEM_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
@@ -375,6 +446,8 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_EXPR,
NFTA_SET_ELEM_PAD,
NFTA_SET_ELEM_OBJREF,
+ NFTA_SET_ELEM_KEY_END,
+ NFTA_SET_ELEM_EXPRESSIONS,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
@@ -440,11 +513,13 @@ enum nft_data_attributes {
*
* @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
* @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
+ * @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32)
*/
enum nft_verdict_attributes {
NFTA_VERDICT_UNSPEC,
NFTA_VERDICT_CODE,
NFTA_VERDICT_CHAIN,
+ NFTA_VERDICT_CHAIN_ID,
__NFTA_VERDICT_MAX
};
#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
@@ -478,6 +553,20 @@ enum nft_immediate_attributes {
#define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1)
/**
+ * enum nft_bitwise_ops - nf_tables bitwise operations
+ *
+ * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and
+ * XOR boolean operations
+ * @NFT_BITWISE_LSHIFT: left-shift operation
+ * @NFT_BITWISE_RSHIFT: right-shift operation
+ */
+enum nft_bitwise_ops {
+ NFT_BITWISE_BOOL,
+ NFT_BITWISE_LSHIFT,
+ NFT_BITWISE_RSHIFT,
+};
+
+/**
* enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
*
* @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers)
@@ -485,16 +574,20 @@ enum nft_immediate_attributes {
* @NFTA_BITWISE_LEN: length of operands (NLA_U32)
* @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes)
* @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops)
+ * @NFTA_BITWISE_DATA: argument for non-boolean operations
+ * (NLA_NESTED: nft_data_attributes)
*
- * The bitwise expression performs the following operation:
+ * The bitwise expression supports boolean and shift operations. It implements
+ * the boolean operations by performing the following operation:
*
* dreg = (sreg & mask) ^ xor
*
- * which allow to express all bitwise operations:
+ * with these mask and xor values:
*
* mask xor
* NOT: 1 1
- * OR: 0 x
+ * OR: ~x x
* XOR: 1 x
* AND: x 0
*/
@@ -505,6 +598,8 @@ enum nft_bitwise_attributes {
NFTA_BITWISE_LEN,
NFTA_BITWISE_MASK,
NFTA_BITWISE_XOR,
+ NFTA_BITWISE_OP,
+ NFTA_BITWISE_DATA,
__NFTA_BITWISE_MAX
};
#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
@@ -590,7 +685,7 @@ enum nft_range_ops {
* enum nft_range_attributes - nf_tables range expression netlink attributes
*
* @NFTA_RANGE_SREG: source register of data to compare (NLA_U32: nft_registers)
- * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_cmp_ops)
+ * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_range_ops)
* @NFTA_RANGE_FROM_DATA: data range from (NLA_NESTED: nft_data_attributes)
* @NFTA_RANGE_TO_DATA: data range to (NLA_NESTED: nft_data_attributes)
*/
@@ -631,10 +726,12 @@ enum nft_lookup_attributes {
enum nft_dynset_ops {
NFT_DYNSET_OP_ADD,
NFT_DYNSET_OP_UPDATE,
+ NFT_DYNSET_OP_DELETE,
};
enum nft_dynset_flags {
NFT_DYNSET_F_INV = (1 << 0),
+ NFT_DYNSET_F_EXPR = (1 << 1),
};
/**
@@ -648,6 +745,7 @@ enum nft_dynset_flags {
* @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
* @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
* @NFTA_DYNSET_FLAGS: flags (NLA_U32)
+ * @NFTA_DYNSET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_dynset_attributes {
NFTA_DYNSET_UNSPEC,
@@ -660,6 +758,7 @@ enum nft_dynset_attributes {
NFTA_DYNSET_EXPR,
NFTA_DYNSET_PAD,
NFTA_DYNSET_FLAGS,
+ NFTA_DYNSET_EXPRESSIONS,
__NFTA_DYNSET_MAX,
};
#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
@@ -670,11 +769,14 @@ enum nft_dynset_attributes {
* @NFT_PAYLOAD_LL_HEADER: link layer header
* @NFT_PAYLOAD_NETWORK_HEADER: network header
* @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
+ * @NFT_PAYLOAD_INNER_HEADER: inner header / payload
*/
enum nft_payload_bases {
NFT_PAYLOAD_LL_HEADER,
NFT_PAYLOAD_NETWORK_HEADER,
NFT_PAYLOAD_TRANSPORT_HEADER,
+ NFT_PAYLOAD_INNER_HEADER,
+ NFT_PAYLOAD_TUN_HEADER,
};
/**
@@ -682,16 +784,44 @@ enum nft_payload_bases {
*
* @NFT_PAYLOAD_CSUM_NONE: no checksumming
* @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791)
+ * @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309)
*/
enum nft_payload_csum_types {
NFT_PAYLOAD_CSUM_NONE,
NFT_PAYLOAD_CSUM_INET,
+ NFT_PAYLOAD_CSUM_SCTP,
};
enum nft_payload_csum_flags {
NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0),
};
+enum nft_inner_type {
+ NFT_INNER_UNSPEC = 0,
+ NFT_INNER_VXLAN,
+ NFT_INNER_GENEVE,
+};
+
+enum nft_inner_flags {
+ NFT_INNER_HDRSIZE = (1 << 0),
+ NFT_INNER_LL = (1 << 1),
+ NFT_INNER_NH = (1 << 2),
+ NFT_INNER_TH = (1 << 3),
+};
+#define NFT_INNER_MASK (NFT_INNER_HDRSIZE | NFT_INNER_LL | \
+ NFT_INNER_NH | NFT_INNER_TH)
+
+enum nft_inner_attributes {
+ NFTA_INNER_UNSPEC,
+ NFTA_INNER_NUM,
+ NFTA_INNER_TYPE,
+ NFTA_INNER_FLAGS,
+ NFTA_INNER_HDRSIZE,
+ NFTA_INNER_EXPR,
+ __NFTA_INNER_MAX
+};
+#define NFTA_INNER_MAX (__NFTA_INNER_MAX - 1)
+
/**
* enum nft_payload_attributes - nf_tables payload expression netlink attributes
*
@@ -727,10 +857,14 @@ enum nft_exthdr_flags {
*
* @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
* @NFT_EXTHDR_OP_TCP: match against tcp options
+ * @NFT_EXTHDR_OP_IPV4: match against ipv4 options
+ * @NFT_EXTHDR_OP_SCTP: match against sctp chunks
*/
enum nft_exthdr_op {
NFT_EXTHDR_OP_IPV6,
NFT_EXTHDR_OP_TCPOPT,
+ NFT_EXTHDR_OP_IPV4,
+ NFT_EXTHDR_OP_SCTP,
__NFT_EXTHDR_OP_MAX
};
#define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1)
@@ -744,7 +878,7 @@ enum nft_exthdr_op {
* @NFTA_EXTHDR_LEN: extension header length (NLA_U32)
* @NFTA_EXTHDR_FLAGS: extension header flags (NLA_U32)
* @NFTA_EXTHDR_OP: option match type (NLA_U32)
- * @NFTA_EXTHDR_SREG: option match type (NLA_U32)
+ * @NFTA_EXTHDR_SREG: source register (NLA_U32: nft_registers)
*/
enum nft_exthdr_attributes {
NFTA_EXTHDR_UNSPEC,
@@ -788,6 +922,16 @@ enum nft_exthdr_attributes {
* @NFT_META_CGROUP: socket control group (skb->sk->sk_classid)
* @NFT_META_PRANDOM: a 32bit pseudo-random number
* @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp)
+ * @NFT_META_IIFKIND: packet input interface kind name (dev->rtnl_link_ops->kind)
+ * @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind)
+ * @NFT_META_BRI_IIFPVID: packet input bridge port pvid
+ * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto
+ * @NFT_META_TIME_NS: time since epoch (in nanoseconds)
+ * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday)
+ * @NFT_META_TIME_HOUR: hour of day (in seconds)
+ * @NFT_META_SDIF: slave device interface index
+ * @NFT_META_SDIFNAME: slave device interface name
+ * @NFT_META_BRI_BROUTE: packet br_netfilter_broute bit
*/
enum nft_meta_keys {
NFT_META_LEN,
@@ -798,7 +942,8 @@ enum nft_meta_keys {
NFT_META_OIF,
NFT_META_IIFNAME,
NFT_META_OIFNAME,
- NFT_META_IIFTYPE,
+ NFT_META_IFTYPE,
+#define NFT_META_IIFTYPE NFT_META_IFTYPE
NFT_META_OIFTYPE,
NFT_META_SKUID,
NFT_META_SKGID,
@@ -816,6 +961,17 @@ enum nft_meta_keys {
NFT_META_CGROUP,
NFT_META_PRANDOM,
NFT_META_SECPATH,
+ NFT_META_IIFKIND,
+ NFT_META_OIFKIND,
+ NFT_META_BRI_IIFPVID,
+ NFT_META_BRI_IIFVPROTO,
+ NFT_META_TIME_NS,
+ NFT_META_TIME_DAY,
+ NFT_META_TIME_HOUR,
+ NFT_META_SDIF,
+ NFT_META_SDIFNAME,
+ NFT_META_BRI_BROUTE,
+ __NFT_META_IIFTYPE,
};
/**
@@ -825,13 +981,17 @@ enum nft_meta_keys {
* @NFT_RT_NEXTHOP4: routing nexthop for IPv4
* @NFT_RT_NEXTHOP6: routing nexthop for IPv6
* @NFT_RT_TCPMSS: fetch current path tcp mss
+ * @NFT_RT_XFRM: boolean, skb->dst->xfrm != NULL
*/
enum nft_rt_keys {
NFT_RT_CLASSID,
NFT_RT_NEXTHOP4,
NFT_RT_NEXTHOP6,
NFT_RT_TCPMSS,
+ NFT_RT_XFRM,
+ __NFT_RT_MAX
};
+#define NFT_RT_MAX (__NFT_RT_MAX - 1)
/**
* enum nft_hash_types - nf_tables hash expression types
@@ -854,6 +1014,8 @@ enum nft_hash_types {
* @NFTA_HASH_SEED: seed value (NLA_U32)
* @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
* @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types)
+ * @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING)
+ * @NFTA_HASH_SET_ID: id of the map (NLA_U32)
*/
enum nft_hash_attributes {
NFTA_HASH_UNSPEC,
@@ -864,6 +1026,8 @@ enum nft_hash_attributes {
NFTA_HASH_SEED,
NFTA_HASH_OFFSET,
NFTA_HASH_TYPE,
+ NFTA_HASH_SET_NAME, /* deprecated */
+ NFTA_HASH_SET_ID, /* deprecated */
__NFTA_HASH_MAX,
};
#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
@@ -899,6 +1063,39 @@ enum nft_rt_attributes {
#define NFTA_RT_MAX (__NFTA_RT_MAX - 1)
/**
+ * enum nft_socket_attributes - nf_tables socket expression netlink attributes
+ *
+ * @NFTA_SOCKET_KEY: socket key to match
+ * @NFTA_SOCKET_DREG: destination register
+ * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
+ */
+enum nft_socket_attributes {
+ NFTA_SOCKET_UNSPEC,
+ NFTA_SOCKET_KEY,
+ NFTA_SOCKET_DREG,
+ NFTA_SOCKET_LEVEL,
+ __NFTA_SOCKET_MAX
+};
+#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
+
+/*
+ * enum nft_socket_keys - nf_tables socket expression keys
+ *
+ * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
+ * @NFT_SOCKET_MARK: Value of the socket mark
+ * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
+ * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
+ */
+enum nft_socket_keys {
+ NFT_SOCKET_TRANSPARENT,
+ NFT_SOCKET_MARK,
+ NFT_SOCKET_WILDCARD,
+ NFT_SOCKET_CGROUPV2,
+ __NFT_SOCKET_MAX
+};
+#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
+
+/**
* enum nft_ct_keys - nf_tables ct expression keys
*
* @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info)
@@ -909,8 +1106,8 @@ enum nft_rt_attributes {
* @NFT_CT_EXPIRATION: relative conntrack expiration time in ms
* @NFT_CT_HELPER: connection tracking helper assigned to conntrack
* @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol
- * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address)
- * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address)
+ * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address, deprecated)
+ * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address, deprecated)
* @NFT_CT_PROTOCOL: conntrack layer 4 protocol
* @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
* @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
@@ -920,6 +1117,11 @@ enum nft_rt_attributes {
* @NFT_CT_AVGPKT: conntrack average bytes per packet
* @NFT_CT_ZONE: conntrack zone
* @NFT_CT_EVENTMASK: ctnetlink events to be generated for this conntrack
+ * @NFT_CT_SRC_IP: conntrack layer 3 protocol source (IPv4 address)
+ * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address)
+ * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address)
+ * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address)
+ * @NFT_CT_ID: conntrack id
*/
enum nft_ct_keys {
NFT_CT_STATE,
@@ -941,7 +1143,14 @@ enum nft_ct_keys {
NFT_CT_AVGPKT,
NFT_CT_ZONE,
NFT_CT_EVENTMASK,
+ NFT_CT_SRC_IP,
+ NFT_CT_DST_IP,
+ NFT_CT_SRC_IP6,
+ NFT_CT_DST_IP6,
+ NFT_CT_ID,
+ __NFT_CT_MAX
};
+#define NFT_CT_MAX (__NFT_CT_MAX - 1)
/**
* enum nft_ct_attributes - nf_tables ct expression netlink attributes
@@ -1002,6 +1211,24 @@ enum nft_limit_attributes {
};
#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
+enum nft_connlimit_flags {
+ NFT_CONNLIMIT_F_INV = (1 << 0),
+};
+
+/**
+ * enum nft_connlimit_attributes - nf_tables connlimit expression netlink attributes
+ *
+ * @NFTA_CONNLIMIT_COUNT: number of connections (NLA_U32)
+ * @NFTA_CONNLIMIT_FLAGS: flags (NLA_U32: enum nft_connlimit_flags)
+ */
+enum nft_connlimit_attributes {
+ NFTA_CONNLIMIT_UNSPEC,
+ NFTA_CONNLIMIT_COUNT,
+ NFTA_CONNLIMIT_FLAGS,
+ __NFTA_CONNLIMIT_MAX
+};
+#define NFTA_CONNLIMIT_MAX (__NFTA_CONNLIMIT_MAX - 1)
+
/**
* enum nft_counter_attributes - nf_tables counter expression netlink attributes
*
@@ -1018,12 +1245,27 @@ enum nft_counter_attributes {
#define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1)
/**
+ * enum nft_last_attributes - nf_tables last expression netlink attributes
+ *
+ * @NFTA_LAST_SET: last update has been set, zero means never updated (NLA_U32)
+ * @NFTA_LAST_MSECS: milliseconds since last update (NLA_U64)
+ */
+enum nft_last_attributes {
+ NFTA_LAST_UNSPEC,
+ NFTA_LAST_SET,
+ NFTA_LAST_MSECS,
+ NFTA_LAST_PAD,
+ __NFTA_LAST_MAX
+};
+#define NFTA_LAST_MAX (__NFTA_LAST_MAX - 1)
+
+/**
* enum nft_log_attributes - nf_tables log expression netlink attributes
*
- * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32)
+ * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U16)
* @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING)
* @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32)
- * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32)
+ * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U16)
* @NFTA_LOG_LEVEL: log level (NLA_U32)
* @NFTA_LOG_FLAGS: logging flags (NLA_U32)
*/
@@ -1040,6 +1282,33 @@ enum nft_log_attributes {
#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1)
/**
+ * enum nft_log_level - nf_tables log levels
+ *
+ * @NFT_LOGLEVEL_EMERG: system is unusable
+ * @NFT_LOGLEVEL_ALERT: action must be taken immediately
+ * @NFT_LOGLEVEL_CRIT: critical conditions
+ * @NFT_LOGLEVEL_ERR: error conditions
+ * @NFT_LOGLEVEL_WARNING: warning conditions
+ * @NFT_LOGLEVEL_NOTICE: normal but significant condition
+ * @NFT_LOGLEVEL_INFO: informational
+ * @NFT_LOGLEVEL_DEBUG: debug-level messages
+ * @NFT_LOGLEVEL_AUDIT: enabling audit logging
+ */
+enum nft_log_level {
+ NFT_LOGLEVEL_EMERG,
+ NFT_LOGLEVEL_ALERT,
+ NFT_LOGLEVEL_CRIT,
+ NFT_LOGLEVEL_ERR,
+ NFT_LOGLEVEL_WARNING,
+ NFT_LOGLEVEL_NOTICE,
+ NFT_LOGLEVEL_INFO,
+ NFT_LOGLEVEL_DEBUG,
+ NFT_LOGLEVEL_AUDIT,
+ __NFT_LOGLEVEL_MAX
+};
+#define NFT_LOGLEVEL_MAX (__NFT_LOGLEVEL_MAX - 1)
+
+/**
* enum nft_queue_attributes - nf_tables queue expression netlink attributes
*
* @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
@@ -1084,6 +1353,21 @@ enum nft_quota_attributes {
#define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1)
/**
+ * enum nft_secmark_attributes - nf_tables secmark object netlink attributes
+ *
+ * @NFTA_SECMARK_CTX: security context (NLA_STRING)
+ */
+enum nft_secmark_attributes {
+ NFTA_SECMARK_UNSPEC,
+ NFTA_SECMARK_CTX,
+ __NFTA_SECMARK_MAX,
+};
+#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1)
+
+/* Max security context length */
+#define NFT_SECMARK_CTX_MAXLEN 256
+
+/**
* enum nft_reject_types - nf_tables reject expression reject types
*
* @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
@@ -1165,6 +1449,22 @@ enum nft_nat_attributes {
#define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1)
/**
+ * enum nft_tproxy_attributes - nf_tables tproxy expression netlink attributes
+ *
+ * NFTA_TPROXY_FAMILY: Target address family (NLA_U32: nft_registers)
+ * NFTA_TPROXY_REG_ADDR: Target address register (NLA_U32: nft_registers)
+ * NFTA_TPROXY_REG_PORT: Target port register (NLA_U32: nft_registers)
+ */
+enum nft_tproxy_attributes {
+ NFTA_TPROXY_UNSPEC,
+ NFTA_TPROXY_FAMILY,
+ NFTA_TPROXY_REG_ADDR,
+ NFTA_TPROXY_REG_PORT,
+ __NFTA_TPROXY_MAX
+};
+#define NFTA_TPROXY_MAX (__NFTA_TPROXY_MAX - 1)
+
+/**
* enum nft_masq_attributes - nf_tables masquerade expression attributes
*
* @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
@@ -1214,10 +1514,14 @@ enum nft_dup_attributes {
* enum nft_fwd_attributes - nf_tables fwd expression netlink attributes
*
* @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register)
+ * @NFTA_FWD_SREG_ADDR: source register of destination address (NLA_U32: nft_register)
+ * @NFTA_FWD_NFPROTO: layer 3 family of source register address (NLA_U32: enum nfproto)
*/
enum nft_fwd_attributes {
NFTA_FWD_UNSPEC,
NFTA_FWD_SREG_DEV,
+ NFTA_FWD_SREG_ADDR,
+ NFTA_FWD_NFPROTO,
__NFTA_FWD_MAX
};
#define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1)
@@ -1302,12 +1606,38 @@ enum nft_ct_helper_attributes {
};
#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1)
+enum nft_ct_timeout_timeout_attributes {
+ NFTA_CT_TIMEOUT_UNSPEC,
+ NFTA_CT_TIMEOUT_L3PROTO,
+ NFTA_CT_TIMEOUT_L4PROTO,
+ NFTA_CT_TIMEOUT_DATA,
+ __NFTA_CT_TIMEOUT_MAX,
+};
+#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1)
+
+enum nft_ct_expectation_attributes {
+ NFTA_CT_EXPECT_UNSPEC,
+ NFTA_CT_EXPECT_L3PROTO,
+ NFTA_CT_EXPECT_L4PROTO,
+ NFTA_CT_EXPECT_DPORT,
+ NFTA_CT_EXPECT_TIMEOUT,
+ NFTA_CT_EXPECT_SIZE,
+ __NFTA_CT_EXPECT_MAX,
+};
+#define NFTA_CT_EXPECT_MAX (__NFTA_CT_EXPECT_MAX - 1)
+
#define NFT_OBJECT_UNSPEC 0
#define NFT_OBJECT_COUNTER 1
#define NFT_OBJECT_QUOTA 2
#define NFT_OBJECT_CT_HELPER 3
#define NFT_OBJECT_LIMIT 4
-#define __NFT_OBJECT_MAX 5
+#define NFT_OBJECT_CONNLIMIT 5
+#define NFT_OBJECT_TUNNEL 6
+#define NFT_OBJECT_CT_TIMEOUT 7
+#define NFT_OBJECT_SECMARK 8
+#define NFT_OBJECT_CT_EXPECT 9
+#define NFT_OBJECT_SYNPROXY 10
+#define __NFT_OBJECT_MAX 11
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
/**
@@ -1319,6 +1649,7 @@ enum nft_ct_helper_attributes {
* @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
* @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
* @NFTA_OBJ_HANDLE: object handle (NLA_U64)
+ * @NFTA_OBJ_USERDATA: user data (NLA_BINARY)
*/
enum nft_object_attributes {
NFTA_OBJ_UNSPEC,
@@ -1329,11 +1660,25 @@ enum nft_object_attributes {
NFTA_OBJ_USE,
NFTA_OBJ_HANDLE,
NFTA_OBJ_PAD,
+ NFTA_OBJ_USERDATA,
__NFTA_OBJ_MAX
};
#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
/**
+ * enum nft_flowtable_flags - nf_tables flowtable flags
+ *
+ * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled
+ * @NFT_FLOWTABLE_COUNTER: enable flow counters
+ */
+enum nft_flowtable_flags {
+ NFT_FLOWTABLE_HW_OFFLOAD = 0x1,
+ NFT_FLOWTABLE_COUNTER = 0x2,
+ NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD |
+ NFT_FLOWTABLE_COUNTER)
+};
+
+/**
* enum nft_flowtable_attributes - nf_tables flow table netlink attributes
*
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
@@ -1341,6 +1686,7 @@ enum nft_object_attributes {
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
+ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
*/
enum nft_flowtable_attributes {
NFTA_FLOWTABLE_UNSPEC,
@@ -1350,6 +1696,7 @@ enum nft_flowtable_attributes {
NFTA_FLOWTABLE_USE,
NFTA_FLOWTABLE_HANDLE,
NFTA_FLOWTABLE_PAD,
+ NFTA_FLOWTABLE_FLAGS,
__NFTA_FLOWTABLE_MAX
};
#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
@@ -1371,6 +1718,42 @@ enum nft_flowtable_hook_attributes {
#define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1)
/**
+ * enum nft_osf_attributes - nftables osf expression netlink attributes
+ *
+ * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8)
+ * @NFTA_OSF_FLAGS: flags (NLA_U32)
+ */
+enum nft_osf_attributes {
+ NFTA_OSF_UNSPEC,
+ NFTA_OSF_DREG,
+ NFTA_OSF_TTL,
+ NFTA_OSF_FLAGS,
+ __NFTA_OSF_MAX,
+};
+#define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
+
+enum nft_osf_flags {
+ NFT_OSF_F_VERSION = (1 << 0),
+};
+
+/**
+ * enum nft_synproxy_attributes - nf_tables synproxy expression netlink attributes
+ *
+ * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
+ * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
+ * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
+ */
+enum nft_synproxy_attributes {
+ NFTA_SYNPROXY_UNSPEC,
+ NFTA_SYNPROXY_MSS,
+ NFTA_SYNPROXY_WSCALE,
+ NFTA_SYNPROXY_FLAGS,
+ __NFTA_SYNPROXY_MAX,
+};
+#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
+
+/**
* enum nft_device_attributes - nf_tables device netlink attributes
*
* @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
@@ -1382,6 +1765,35 @@ enum nft_devices_attributes {
};
#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
+/*
+ * enum nft_xfrm_attributes - nf_tables xfrm expr netlink attributes
+ *
+ * @NFTA_XFRM_DREG: destination register (NLA_U32)
+ * @NFTA_XFRM_KEY: enum nft_xfrm_keys (NLA_U32)
+ * @NFTA_XFRM_DIR: direction (NLA_U8)
+ * @NFTA_XFRM_SPNUM: index in secpath array (NLA_U32)
+ */
+enum nft_xfrm_attributes {
+ NFTA_XFRM_UNSPEC,
+ NFTA_XFRM_DREG,
+ NFTA_XFRM_KEY,
+ NFTA_XFRM_DIR,
+ NFTA_XFRM_SPNUM,
+ __NFTA_XFRM_MAX
+};
+#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1)
+
+enum nft_xfrm_keys {
+ NFT_XFRM_KEY_UNSPEC,
+ NFT_XFRM_KEY_DADDR_IP4,
+ NFT_XFRM_KEY_DADDR_IP6,
+ NFT_XFRM_KEY_SADDR_IP4,
+ NFT_XFRM_KEY_SADDR_IP6,
+ NFT_XFRM_KEY_REQID,
+ NFT_XFRM_KEY_SPI,
+ __NFT_XFRM_KEY_MAX,
+};
+#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1)
/**
* enum nft_trace_attributes - nf_tables trace netlink attributes
@@ -1442,6 +1854,8 @@ enum nft_trace_types {
* @NFTA_NG_MODULUS: maximum counter value (NLA_U32)
* @NFTA_NG_TYPE: operation type (NLA_U32)
* @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32)
+ * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING)
+ * @NFTA_NG_SET_ID: id of the map (NLA_U32)
*/
enum nft_ng_attributes {
NFTA_NG_UNSPEC,
@@ -1449,6 +1863,8 @@ enum nft_ng_attributes {
NFTA_NG_MODULUS,
NFTA_NG_TYPE,
NFTA_NG_OFFSET,
+ NFTA_NG_SET_NAME, /* deprecated */
+ NFTA_NG_SET_ID, /* deprecated */
__NFTA_NG_MAX
};
#define NFTA_NG_MAX (__NFTA_NG_MAX - 1)
@@ -1460,4 +1876,104 @@ enum nft_ng_types {
};
#define NFT_NG_MAX (__NFT_NG_MAX - 1)
+enum nft_tunnel_key_ip_attributes {
+ NFTA_TUNNEL_KEY_IP_UNSPEC,
+ NFTA_TUNNEL_KEY_IP_SRC,
+ NFTA_TUNNEL_KEY_IP_DST,
+ __NFTA_TUNNEL_KEY_IP_MAX
+};
+#define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1)
+
+enum nft_tunnel_ip6_attributes {
+ NFTA_TUNNEL_KEY_IP6_UNSPEC,
+ NFTA_TUNNEL_KEY_IP6_SRC,
+ NFTA_TUNNEL_KEY_IP6_DST,
+ NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
+ __NFTA_TUNNEL_KEY_IP6_MAX
+};
+#define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1)
+
+enum nft_tunnel_opts_attributes {
+ NFTA_TUNNEL_KEY_OPTS_UNSPEC,
+ NFTA_TUNNEL_KEY_OPTS_VXLAN,
+ NFTA_TUNNEL_KEY_OPTS_ERSPAN,
+ NFTA_TUNNEL_KEY_OPTS_GENEVE,
+ __NFTA_TUNNEL_KEY_OPTS_MAX
+};
+#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
+
+enum nft_tunnel_opts_vxlan_attributes {
+ NFTA_TUNNEL_KEY_VXLAN_UNSPEC,
+ NFTA_TUNNEL_KEY_VXLAN_GBP,
+ __NFTA_TUNNEL_KEY_VXLAN_MAX
+};
+#define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1)
+
+enum nft_tunnel_opts_erspan_attributes {
+ NFTA_TUNNEL_KEY_ERSPAN_UNSPEC,
+ NFTA_TUNNEL_KEY_ERSPAN_VERSION,
+ NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
+ NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
+ NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
+ __NFTA_TUNNEL_KEY_ERSPAN_MAX
+};
+#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
+
+enum nft_tunnel_opts_geneve_attributes {
+ NFTA_TUNNEL_KEY_GENEVE_UNSPEC,
+ NFTA_TUNNEL_KEY_GENEVE_CLASS,
+ NFTA_TUNNEL_KEY_GENEVE_TYPE,
+ NFTA_TUNNEL_KEY_GENEVE_DATA,
+ __NFTA_TUNNEL_KEY_GENEVE_MAX
+};
+#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1)
+
+enum nft_tunnel_flags {
+ NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0),
+ NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1),
+ NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2),
+};
+#define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \
+ NFT_TUNNEL_F_DONT_FRAGMENT | \
+ NFT_TUNNEL_F_SEQ_NUMBER)
+
+enum nft_tunnel_key_attributes {
+ NFTA_TUNNEL_KEY_UNSPEC,
+ NFTA_TUNNEL_KEY_ID,
+ NFTA_TUNNEL_KEY_IP,
+ NFTA_TUNNEL_KEY_IP6,
+ NFTA_TUNNEL_KEY_FLAGS,
+ NFTA_TUNNEL_KEY_TOS,
+ NFTA_TUNNEL_KEY_TTL,
+ NFTA_TUNNEL_KEY_SPORT,
+ NFTA_TUNNEL_KEY_DPORT,
+ NFTA_TUNNEL_KEY_OPTS,
+ __NFTA_TUNNEL_KEY_MAX
+};
+#define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1)
+
+enum nft_tunnel_keys {
+ NFT_TUNNEL_PATH,
+ NFT_TUNNEL_ID,
+ __NFT_TUNNEL_MAX
+};
+#define NFT_TUNNEL_MAX (__NFT_TUNNEL_MAX - 1)
+
+enum nft_tunnel_mode {
+ NFT_TUNNEL_MODE_NONE,
+ NFT_TUNNEL_MODE_RX,
+ NFT_TUNNEL_MODE_TX,
+ __NFT_TUNNEL_MODE_MAX
+};
+#define NFT_TUNNEL_MODE_MAX (__NFT_TUNNEL_MODE_MAX - 1)
+
+enum nft_tunnel_attributes {
+ NFTA_TUNNEL_UNSPEC,
+ NFTA_TUNNEL_KEY,
+ NFTA_TUNNEL_DREG,
+ NFTA_TUNNEL_MODE,
+ __NFTA_TUNNEL_MAX
+};
+#define NFTA_TUNNEL_MAX (__NFTA_TUNNEL_MAX - 1)
+
#endif /* _LINUX_NF_TABLES_H */
diff --git a/include/linux/netfilter/xt_LOG.h b/include/linux/netfilter/xt_LOG.h
new file mode 100644
index 00000000..167d4ddd
--- /dev/null
+++ b/include/linux/netfilter/xt_LOG.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _XT_LOG_H
+#define _XT_LOG_H
+
+/* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */
+#define XT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
+#define XT_LOG_TCPOPT 0x02 /* Log TCP options */
+#define XT_LOG_IPOPT 0x04 /* Log IP options */
+#define XT_LOG_UID 0x08 /* Log UID owning local socket */
+#define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
+#define XT_LOG_MACDECODE 0x20 /* Decode MAC header */
+#define XT_LOG_MASK 0x2f
+
+struct xt_log_info {
+ unsigned char level;
+ unsigned char logflags;
+ char prefix[30];
+};
+
+#endif /* _XT_LOG_H */
diff --git a/include/linux/netfilter/xt_SECMARK.h b/include/linux/netfilter/xt_SECMARK.h
index 989092bd..31760a28 100644
--- a/include/linux/netfilter/xt_SECMARK.h
+++ b/include/linux/netfilter/xt_SECMARK.h
@@ -19,4 +19,10 @@ struct xt_secmark_target_info {
char secctx[SECMARK_SECCTX_MAX];
};
+struct xt_secmark_target_info_v1 {
+ __u8 mode;
+ char secctx[SECMARK_SECCTX_MAX];
+ __u32 secid;
+};
+
#endif /*_XT_SECMARK_H_target */
diff --git a/include/linux/netfilter_arp/arpt_mangle.h b/include/linux/netfilter_arp/arpt_mangle.h
index 250f5029..8c2b16a1 100644
--- a/include/linux/netfilter_arp/arpt_mangle.h
+++ b/include/linux/netfilter_arp/arpt_mangle.h
@@ -13,7 +13,7 @@ struct arpt_mangle
union {
struct in_addr tgt_ip;
} u_t;
- u_int8_t flags;
+ __u8 flags;
int target;
};
diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h
index c4bbc41b..ae5d4d10 100644
--- a/include/linux/netfilter_bridge/ebt_ip.h
+++ b/include/linux/netfilter_bridge/ebt_ip.h
@@ -23,8 +23,10 @@
#define EBT_IP_PROTO 0x08
#define EBT_IP_SPORT 0x10
#define EBT_IP_DPORT 0x20
+#define EBT_IP_ICMP 0x40
+#define EBT_IP_IGMP 0x80
#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
- EBT_IP_SPORT | EBT_IP_DPORT )
+ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
#define EBT_IP_MATCH "ip"
/* the same values are used for the invflags */
@@ -37,8 +39,15 @@ struct ebt_ip_info {
__u8 protocol;
__u8 bitmask;
__u8 invflags;
- __u16 sport[2];
- __u16 dport[2];
+ union {
+ __u16 sport[2];
+ __u8 icmp_type[2];
+ __u8 igmp_type[2];
+ };
+ union {
+ __u16 dport[2];
+ __u8 icmp_code[2];
+ };
};
#endif
diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h
deleted file mode 100644
index dcdbadf9..00000000
--- a/include/linux/netfilter_ipv4/ipt_LOG.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IPT_LOG_H
-#define _IPT_LOG_H
-
-/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
-#define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
-#define IPT_LOG_TCPOPT 0x02 /* Log TCP options */
-#define IPT_LOG_IPOPT 0x04 /* Log IP options */
-#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
-#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
-#define IPT_LOG_MACDECODE 0x20 /* Decode MAC header */
-#define IPT_LOG_MASK 0x2f
-
-struct ipt_log_info {
- unsigned char level;
- unsigned char logflags;
- char prefix[30];
-};
-
-#endif /*_IPT_LOG_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_LOG.h b/include/linux/netfilter_ipv6/ip6t_LOG.h
deleted file mode 100644
index 9dd5579e..00000000
--- a/include/linux/netfilter_ipv6/ip6t_LOG.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _IP6T_LOG_H
-#define _IP6T_LOG_H
-
-/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
-#define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
-#define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */
-#define IP6T_LOG_IPOPT 0x04 /* Log IP options */
-#define IP6T_LOG_UID 0x08 /* Log UID owning local socket */
-#define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */
-#define IP6T_LOG_MACDECODE 0x20 /* Decode MAC header */
-#define IP6T_LOG_MASK 0x2f
-
-struct ip6t_log_info {
- unsigned char level;
- unsigned char logflags;
- char prefix[30];
-};
-
-#endif /*_IPT_LOG_H*/
diff --git a/include/linux/sysinfo.h b/include/linux/sysinfo.h
new file mode 100644
index 00000000..435d5c23
--- /dev/null
+++ b/include/linux/sysinfo.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SYSINFO_H
+#define _LINUX_SYSINFO_H
+
+#include <linux/types.h>
+
+#define SI_LOAD_SHIFT 16
+struct sysinfo {
+ __kernel_long_t uptime; /* Seconds since boot */
+ __kernel_ulong_t loads[3]; /* 1, 5, and 15 minute load averages */
+ __kernel_ulong_t totalram; /* Total usable main memory size */
+ __kernel_ulong_t freeram; /* Available memory size */
+ __kernel_ulong_t sharedram; /* Amount of shared memory */
+ __kernel_ulong_t bufferram; /* Memory used by buffers */
+ __kernel_ulong_t totalswap; /* Total swap space size */
+ __kernel_ulong_t freeswap; /* swap space still available */
+ __u16 procs; /* Number of current processes */
+ __u16 pad; /* Explicit padding for m68k */
+ __kernel_ulong_t totalhigh; /* Total high memory size */
+ __kernel_ulong_t freehigh; /* Available high memory size */
+ __u32 mem_unit; /* Memory unit size in bytes */
+ char _f[20-2*sizeof(__kernel_ulong_t)-sizeof(__u32)]; /* Padding: libc5 uses this.. */
+};
+
+#endif /* _LINUX_SYSINFO_H */
diff --git a/include/xtables.h b/include/xtables.h
index 5044dd08..ab856ebc 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -12,6 +12,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/types.h>
@@ -61,7 +62,6 @@ struct in_addr;
* %XTTYPE_SYSLOGLEVEL: syslog level by name or number
* %XTTYPE_HOST: one host or address (ptr: union nf_inet_addr)
* %XTTYPE_HOSTMASK: one host or address, with an optional prefix length
- * (ptr: union nf_inet_addr; only host portion is stored)
* %XTTYPE_PROTOCOL: protocol number/name from /etc/protocols (ptr: uint8_t)
* %XTTYPE_PORT: 16-bit port name or number (supports %XTOPT_NBO)
* %XTTYPE_PORTRC: colon-separated port range (names acceptable),
@@ -69,6 +69,7 @@ struct in_addr;
* %XTTYPE_PLEN: prefix length
* %XTTYPE_PLENMASK: prefix length (ptr: union nf_inet_addr)
* %XTTYPE_ETHERMAC: Ethernet MAC address in hex form
+ * %XTTYPE_ETHERMACMASK: Ethernet MAC address in hex form with optional mask
*/
enum xt_option_type {
XTTYPE_NONE,
@@ -93,6 +94,7 @@ enum xt_option_type {
XTTYPE_PLEN,
XTTYPE_PLENMASK,
XTTYPE_ETHERMAC,
+ XTTYPE_ETHERMACMASK,
};
/**
@@ -122,6 +124,7 @@ enum xt_option_flags {
* @size: size of the item pointed to by @ptroff; this is a safeguard
* @min: lowest allowed value (for singular integral types)
* @max: highest allowed value (for singular integral types)
+ * @base: assumed base of parsed value for integer types (default 0)
*/
struct xt_option_entry {
const char *name;
@@ -129,7 +132,7 @@ struct xt_option_entry {
unsigned int id, excl, also, flags;
unsigned int ptroff;
size_t size;
- unsigned int min, max;
+ unsigned int min, max, base;
};
/**
@@ -167,7 +170,9 @@ struct xt_option_call {
struct {
uint32_t mark, mask;
};
- uint8_t ethermac[6];
+ struct {
+ uint8_t ethermac[ETH_ALEN], ethermacmask[ETH_ALEN];
+ };
} val;
/* Wished for a world where the ones below were gone: */
union {
@@ -203,6 +208,7 @@ struct xtables_lmap {
enum xtables_ext_flags {
XTABLES_EXT_ALIAS = 1 << 0,
+ XTABLES_EXT_WATCHER = 1 << 1,
};
struct xt_xlate;
@@ -211,14 +217,14 @@ struct xt_xlate_mt_params {
const void *ip;
const struct xt_entry_match *match;
int numeric;
- bool escape_quotes;
+ bool escape_quotes; /* not used anymore, retained for ABI */
};
struct xt_xlate_tg_params {
const void *ip;
const struct xt_entry_target *target;
int numeric;
- bool escape_quotes;
+ bool escape_quotes; /* not used anymore, retained for ABI */
};
/* Include file for additions: new matches and targets. */
@@ -453,6 +459,7 @@ extern void xtables_set_nfproto(uint8_t);
extern void *xtables_calloc(size_t, size_t);
extern void *xtables_malloc(size_t);
extern void *xtables_realloc(void *, size_t);
+char *xtables_strdup(const char *);
extern int xtables_insmod(const char *, const char *, bool);
extern int xtables_load_ko(const char *, bool);
@@ -484,6 +491,8 @@ extern void xtables_register_matches(struct xtables_match *, unsigned int);
extern void xtables_register_target(struct xtables_target *me);
extern void xtables_register_targets(struct xtables_target *, unsigned int);
+extern bool xtables_strtoul_base(const char *, char **, uintmax_t *,
+ uintmax_t, uintmax_t, unsigned int);
extern bool xtables_strtoul(const char *, char **, uintmax_t *,
uintmax_t, uintmax_t);
extern bool xtables_strtoui(const char *, char **, unsigned int *,
@@ -557,6 +566,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);
@@ -581,18 +593,6 @@ static inline void xtables_print_mark_mask(unsigned int mark,
xtables_print_val_mask(mark, mask, NULL);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
-# ifdef _INIT
-# undef _init
-# define _init _INIT
-# endif
- extern void init_extensions(void);
- extern void init_extensions4(void);
- extern void init_extensions6(void);
-#else
-# define _init __attribute__((constructor)) _INIT
-#endif
-
extern const struct xtables_pprot xtables_chain_protos[];
extern uint16_t xtables_parse_protocol(const char *s);
@@ -629,9 +629,21 @@ extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int);
struct xt_xlate *xt_xlate_alloc(int size);
void xt_xlate_free(struct xt_xlate *xl);
void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3)));
+void xt_xlate_add_nospc(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3)));
+#define xt_xlate_rule_add xt_xlate_add
+#define xt_xlate_rule_add_nospc xt_xlate_add_nospc
+void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3)));
+void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...) __attribute__((format(printf,2,3)));
void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment);
const char *xt_xlate_get_comment(struct xt_xlate *xl);
+void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family);
+uint8_t xt_xlate_get_family(struct xt_xlate *xl);
const char *xt_xlate_get(struct xt_xlate *xl);
+#define xt_xlate_rule_get xt_xlate_get
+const char *xt_xlate_set_get(struct xt_xlate *xl);
+
+/* informed target lookups */
+void xtables_announce_chain(const char *name);
#ifdef XTABLES_INTERNAL
@@ -641,9 +653,55 @@ const char *xt_xlate_get(struct xt_xlate *xl);
# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
# endif
+#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+# ifdef _INIT
+# undef _init
+# define _init _INIT
+# endif
+ extern void init_extensions(void);
+ extern void init_extensions4(void);
+ extern void init_extensions6(void);
+ extern void init_extensionsa(void);
+ extern void init_extensionsb(void);
+#else
+# define _init __attribute__((constructor)) _INIT
+# define EMPTY_FUNC_DEF(x) static inline void x(void) {}
+ EMPTY_FUNC_DEF(init_extensions)
+ EMPTY_FUNC_DEF(init_extensions4)
+ EMPTY_FUNC_DEF(init_extensions6)
+ EMPTY_FUNC_DEF(init_extensionsa)
+ EMPTY_FUNC_DEF(init_extensionsb)
+# undef EMPTY_FUNC_DEF
+#endif
+
extern void _init(void);
-#endif
+/**
+ * xtables_afinfo - protocol family dependent information
+ * @kmod: kernel module basename (e.g. "ip_tables")
+ * @proc_exists: file which exists in procfs when module already loaded
+ * @libprefix: prefix of .so library name (e.g. "libipt_")
+ * @family: nfproto family
+ * @ipproto: used by setsockopt (e.g. IPPROTO_IP)
+ * @so_rev_match: optname to check revision support of match
+ * @so_rev_target: optname to check revision support of target
+ */
+struct xtables_afinfo {
+ const char *kmod;
+ const char *proc_exists;
+ const char *libprefix;
+ uint8_t family;
+ uint8_t ipproto;
+ int so_rev_match;
+ int so_rev_target;
+};
+
+extern const struct xtables_afinfo *afinfo;
+
+/* base offset of merged extensions' consecutive options */
+#define XT_OPTION_OFFSET_SCALE 256
+
+#endif /* XTABLES_INTERNAL */
#ifdef __cplusplus
} /* extern "C" */
diff --git a/iptables-test.py b/iptables-test.py
index 52897a5d..cefe4233 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
#
@@ -15,6 +15,7 @@ import sys
import os
import subprocess
import argparse
+from difflib import unified_diff
IPTABLES = "iptables"
IP6TABLES = "ip6tables"
@@ -32,30 +33,34 @@ EXTENSIONS_PATH = "extensions"
LOGFILE="/tmp/iptables-test.log"
log_file = None
+STDOUT_IS_TTY = sys.stdout.isatty()
+STDERR_IS_TTY = sys.stderr.isatty()
-class Colors:
- HEADER = '\033[95m'
- BLUE = '\033[94m'
- GREEN = '\033[92m'
- YELLOW = '\033[93m'
- RED = '\033[91m'
- ENDC = '\033[0m'
+def maybe_colored(color, text, isatty):
+ terminal_sequences = {
+ 'green': '\033[92m',
+ 'red': '\033[91m',
+ }
+
+ return (
+ terminal_sequences[color] + text + '\033[0m' if isatty else text
+ )
def print_error(reason, filename=None, lineno=None):
'''
Prints an error with nice colors, indicating file and line number.
'''
- print(filename + ": " + Colors.RED + "ERROR" +
- Colors.ENDC + ": line %d (%s)" % (lineno, reason))
+ print(filename + ": " + maybe_colored('red', "ERROR", STDERR_IS_TTY) +
+ ": line %d (%s)" % (lineno, reason), file=sys.stderr)
-def delete_rule(iptables, rule, filename, lineno):
+def delete_rule(iptables, rule, filename, lineno, netns = None):
'''
Removes an iptables rule
'''
cmd = iptables + " -D " + rule
- ret = execute_cmd(cmd, filename, lineno)
+ ret = execute_cmd(cmd, filename, lineno, netns)
if ret == 1:
reason = "cannot delete: " + iptables + " -I " + rule
print_error(reason, filename, lineno)
@@ -69,26 +74,24 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
Executes an unit test. Returns the output of delete_rule().
Parameters:
- :param iptables: string with the iptables command to execute
+ :param iptables: string with the iptables command to execute
:param rule: string with iptables arguments for the rule to test
- :param rule_save: string to find the rule in the output of iptables -save
+ :param rule_save: string to find the rule in the output of iptables-save
:param res: expected result of the rule. Valid values: "OK", "FAIL"
:param filename: name of the file tested (used for print_error purposes)
:param lineno: line number being tested (used for print_error purposes)
+ :param netns: network namespace to call commands in (or None)
'''
ret = 0
cmd = iptables + " -A " + rule
- if netns:
- cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + cmd
-
- ret = execute_cmd(cmd, filename, lineno)
+ ret = execute_cmd(cmd, filename, lineno, netns)
#
# report failed test
#
if ret:
- if res == "OK":
+ if res != "FAIL":
reason = "cannot load: " + cmd
print_error(reason, filename, lineno)
return -1
@@ -99,32 +102,32 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
if res == "FAIL":
reason = "should fail: " + cmd
print_error(reason, filename, lineno)
- delete_rule(iptables, rule, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno, netns)
return -1
matching = 0
- splitted = iptables.split(" ")
- if len(splitted) == 2:
- if splitted[1] == '-4':
+ tokens = iptables.split(" ")
+ if len(tokens) == 2:
+ if tokens[1] == '-4':
command = IPTABLES_SAVE
- elif splitted[1] == '-6':
+ elif tokens[1] == '-6':
command = IP6TABLES_SAVE
- elif len(splitted) == 1:
- if splitted[0] == IPTABLES:
+ elif len(tokens) == 1:
+ if tokens[0] == IPTABLES:
command = IPTABLES_SAVE
- elif splitted[0] == IP6TABLES:
+ elif tokens[0] == IP6TABLES:
command = IP6TABLES_SAVE
- elif splitted[0] == ARPTABLES:
+ elif tokens[0] == ARPTABLES:
command = ARPTABLES_SAVE
- elif splitted[0] == EBTABLES:
+ elif tokens[0] == EBTABLES:
command = EBTABLES_SAVE
- command = EXECUTEABLE + " " + command
+ command = EXECUTABLE + " " + command
if netns:
- command = "ip netns exec ____iptables-container-test " + command
+ command = "ip netns exec " + netns + " " + command
- args = splitted[1:]
+ args = tokens[1:]
proc = subprocess.Popen(command, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -134,18 +137,29 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
# check for segfaults
#
if proc.returncode == -11:
- reason = "iptables-save segfaults: " + cmd
+ reason = command + " segfaults!"
print_error(reason, filename, lineno)
- delete_rule(iptables, rule, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno, netns)
return -1
# find the rule
- matching = out.find(rule_save.encode('utf-8'))
+ matching = out.find("\n-A {}\n".format(rule_save).encode('utf-8'))
+
if matching < 0:
- reason = "cannot find: " + iptables + " -I " + rule
- print_error(reason, filename, lineno)
- delete_rule(iptables, rule, filename, lineno)
- return -1
+ if res == "OK":
+ reason = "cannot find: " + iptables + " -I " + rule
+ print_error(reason, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno, netns)
+ return -1
+ else:
+ # do not report this error
+ return 0
+ else:
+ if res != "OK":
+ reason = "should not match: " + cmd
+ print_error(reason, filename, lineno)
+ delete_rule(iptables, rule, filename, lineno, netns)
+ return -1
# Test "ip netns del NETNS" path with rules in place
if netns:
@@ -153,7 +167,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
return delete_rule(iptables, rule, filename, lineno)
-def execute_cmd(cmd, filename, lineno):
+def execute_cmd(cmd, filename, lineno = 0, netns = None):
'''
Executes a command, checking for segfaults and returning the command exit
code.
@@ -161,10 +175,14 @@ def execute_cmd(cmd, filename, lineno):
:param cmd: string with the command to be executed
:param filename: name of the file tested (used for print_error purposes)
:param lineno: line number being tested (used for print_error purposes)
+ :param netns: network namespace to run command in
'''
global log_file
if cmd.startswith('iptables ') or cmd.startswith('ip6tables ') or cmd.startswith('ebtables ') or cmd.startswith('arptables '):
- cmd = EXECUTEABLE + " " + cmd
+ cmd = EXECUTABLE + " " + cmd
+
+ if netns:
+ cmd = "ip netns exec " + netns + " " + cmd
print("command: {}".format(cmd), file=log_file)
ret = subprocess.call(cmd, shell=True, universal_newlines=True,
@@ -172,17 +190,201 @@ def execute_cmd(cmd, filename, lineno):
log_file.flush()
# generic check for segfaults
- if ret == -11:
+ if ret == -11:
reason = "command segfaults: " + cmd
print_error(reason, filename, lineno)
return ret
+def variant_res(res, variant, alt_res=None):
+ '''
+ Adjust expected result with given variant
+
+ If expected result is scoped to a variant, the other one yields a different
+ result. Therefore map @res to itself if given variant is current, use the
+ alternate result, @alt_res, if specified, invert @res otherwise.
+
+ :param res: expected result from test spec ("OK", "FAIL" or "NOMATCH")
+ :param variant: variant @res is scoped to by test spec ("NFT" or "LEGACY")
+ :param alt_res: optional expected result for the alternate variant.
+ '''
+ variant_executable = {
+ "NFT": "xtables-nft-multi",
+ "LEGACY": "xtables-legacy-multi"
+ }
+ res_inverse = {
+ "OK": "FAIL",
+ "FAIL": "OK",
+ "NOMATCH": "OK"
+ }
+
+ if variant_executable[variant] == EXECUTABLE:
+ return res
+ if alt_res is not None:
+ return alt_res
+ return res_inverse[res]
+
+def fast_run_possible(filename):
+ '''
+ Keep things simple, run only for simple test files:
+ - no external commands
+ - no multiple tables
+ - no variant-specific results
+ '''
+ table = None
+ rulecount = 0
+ for line in open(filename):
+ if line[0] in ["#", ":"] or len(line.strip()) == 0:
+ continue
+ if line[0] == "*":
+ if table or rulecount > 0:
+ return False
+ table = line.rstrip()[1:]
+ if line[0] in ["@", "%"]:
+ return False
+ if len(line.split(";")) > 3:
+ return False
+ rulecount += 1
+
+ return True
+
+def run_test_file_fast(iptables, filename, netns):
+ '''
+ Run a test file, but fast
+
+ :param filename: name of the file with the test rules
+ :param netns: network namespace to perform test run in
+ '''
+
+ f = open(filename)
+
+ rules = {}
+ table = "filter"
+ chain_array = []
+ tests = 0
+
+ for lineno, line in enumerate(f):
+ if line[0] == "#" or len(line.strip()) == 0:
+ continue
+
+ if line[0] == "*":
+ table = line.rstrip()[1:]
+ continue
+
+ if line[0] == ":":
+ chain_array = line.rstrip()[1:].split(",")
+ continue
+
+ if len(chain_array) == 0:
+ return -1
+
+ tests += 1
+
+ for chain in chain_array:
+ item = line.split(";")
+ rule = chain + " " + item[0]
+
+ if item[1] == "=":
+ rule_save = chain + " " + item[0]
+ else:
+ rule_save = chain + " " + item[1]
+
+ if iptables == EBTABLES and rule_save.find('-j') < 0:
+ rule_save += " -j CONTINUE"
+
+ res = item[2].rstrip()
+ if res != "OK":
+ rule = chain + " -t " + table + " " + item[0]
+ ret = run_test(iptables, rule, rule_save,
+ res, filename, lineno + 1, netns)
+
+ if ret < 0:
+ return -1
+ continue
+
+ if not chain in rules.keys():
+ rules[chain] = []
+ rules[chain].append((rule, rule_save))
+
+ restore_data = ["*" + table]
+ out_expect = []
+ for chain in ["PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"]:
+ if not chain in rules.keys():
+ continue
+ for rule in rules[chain]:
+ restore_data.append("-A " + rule[0])
+ out_expect.append("-A " + rule[1])
+ restore_data.append("COMMIT")
+
+ out_expect = "\n".join(out_expect)
+
+ # load all rules via iptables_restore
+
+ command = EXECUTABLE + " " + iptables + "-restore"
+ if netns:
+ command = "ip netns exec " + netns + " " + command
+
+ for line in restore_data:
+ print(iptables + "-restore: " + line, file=log_file)
+
+ proc = subprocess.Popen(command, shell = True, text = True,
+ stdin = subprocess.PIPE,
+ stdout = subprocess.PIPE,
+ stderr = subprocess.PIPE)
+ restore_data = "\n".join(restore_data) + "\n"
+ out, err = proc.communicate(input = restore_data)
+
+ if proc.returncode == -11:
+ reason = iptables + "-restore segfaults!"
+ print_error(reason, filename, lineno)
+ msg = [iptables + "-restore segfault from:"]
+ msg.extend(["input: " + l for l in restore_data.split("\n")])
+ print("\n".join(msg), file=log_file)
+ return -1
+
+ if proc.returncode != 0:
+ print("%s-restore returned %d: %s" % (iptables, proc.returncode, err),
+ file=log_file)
+ return -1
+
+ # find all rules in iptables_save output
+
+ command = EXECUTABLE + " " + iptables + "-save"
+ if netns:
+ command = "ip netns exec " + netns + " " + command
+
+ proc = subprocess.Popen(command, shell = True,
+ stdin = subprocess.PIPE,
+ stdout = subprocess.PIPE,
+ stderr = subprocess.PIPE)
+ out, err = proc.communicate()
+
+ if proc.returncode == -11:
+ reason = iptables + "-save segfaults!"
+ print_error(reason, filename, lineno)
+ return -1
+
+ cmd = iptables + " -F -t " + table
+ execute_cmd(cmd, filename, 0, netns)
+
+ out = out.decode('utf-8').rstrip()
+ if out.find(out_expect) < 0:
+ print("dumps differ!", file=log_file)
+ out_clean = [ l for l in out.split("\n")
+ if not l[0] in ['*', ':', '#']]
+ diff = unified_diff(out_expect.split("\n"), out_clean,
+ fromfile="expect", tofile="got", lineterm='')
+ print("\n".join(diff), file=log_file)
+ return -1
+
+ return tests
+
def run_test_file(filename, netns):
'''
Runs a test file
:param filename: name of the file with the test rules
+ :param netns: network namespace to perform test run in
'''
#
# if this is not a test file, skip.
@@ -198,27 +400,36 @@ def run_test_file(filename, netns):
iptables = IPTABLES
elif "libarpt_" in filename:
# only supported with nf_tables backend
- if EXECUTEABLE != "xtables-nft-multi":
+ if EXECUTABLE != "xtables-nft-multi":
return 0, 0
iptables = ARPTABLES
elif "libebt_" in filename:
# only supported with nf_tables backend
- if EXECUTEABLE != "xtables-nft-multi":
+ if EXECUTABLE != "xtables-nft-multi":
return 0, 0
iptables = EBTABLES
else:
# default to iptables if not known prefix
iptables = IPTABLES
+ fast_failed = False
+ if fast_run_possible(filename):
+ tests = run_test_file_fast(iptables, filename, netns)
+ if tests > 0:
+ print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY))
+ return tests, tests
+ fast_failed = True
+
f = open(filename)
tests = 0
passed = 0
table = ""
+ chain_array = []
total_test_passed = True
if netns:
- execute_cmd("ip netns add ____iptables-container-test", filename, 0)
+ execute_cmd("ip netns add " + netns, filename)
for lineno, line in enumerate(f):
if line[0] == "#" or len(line.strip()) == 0:
@@ -228,20 +439,11 @@ def run_test_file(filename, netns):
chain_array = line.rstrip()[1:].split(",")
continue
- # external non-iptables invocation, executed as is.
- if line[0] == "@":
+ # external command invocation, executed as is.
+ # detects iptables commands to prefix with EXECUTABLE automatically
+ if line[0] in ["@", "%"]:
external_cmd = line.rstrip()[1:]
- if netns:
- external_cmd = "ip netns exec ____iptables-container-test " + external_cmd
- execute_cmd(external_cmd, filename, lineno)
- continue
-
- # external iptables invocation, executed as is.
- if line[0] == "%":
- external_cmd = line.rstrip()[1:]
- if netns:
- external_cmd = "ip netns exec ____iptables-container-test " + EXECUTEABLE + " " + external_cmd
- execute_cmd(external_cmd, filename, lineno)
+ execute_cmd(external_cmd, filename, lineno, netns)
continue
if line[0] == "*":
@@ -249,8 +451,10 @@ def run_test_file(filename, netns):
continue
if len(chain_array) == 0:
- print("broken test, missing chain, leaving")
- sys.exit()
+ print_error("broken test, missing chain",
+ filename = filename, lineno = lineno)
+ total_test_passed = False
+ break
test_passed = True
tests += 1
@@ -267,7 +471,18 @@ def run_test_file(filename, netns):
else:
rule_save = chain + " " + item[1]
+ if iptables == EBTABLES and rule_save.find('-j') < 0:
+ rule_save += " -j CONTINUE"
+
res = item[2].rstrip()
+ if len(item) > 3:
+ variant = item[3].rstrip()
+ if len(item) > 4:
+ alt_res = item[4].rstrip()
+ else:
+ alt_res = None
+ res = variant_res(res, variant, alt_res)
+
ret = run_test(iptables, rule, rule_save,
res, filename, lineno + 1, netns)
@@ -280,9 +495,12 @@ def run_test_file(filename, netns):
passed += 1
if netns:
- execute_cmd("ip netns del ____iptables-container-test", filename, 0)
+ execute_cmd("ip netns del " + netns, filename)
if total_test_passed:
- print(filename + ": " + Colors.GREEN + "OK" + Colors.ENDC)
+ suffix = ""
+ if fast_failed:
+ suffix = maybe_colored('red', " but fast mode failed!", STDOUT_IS_TTY)
+ print(filename + ": " + maybe_colored('green', "OK", STDOUT_IS_TTY) + suffix)
f.close()
return tests, passed
@@ -304,6 +522,31 @@ def show_missing():
print('\n'.join(missing))
+def spawn_netns():
+ # prefer unshare module
+ try:
+ import unshare
+ unshare.unshare(unshare.CLONE_NEWNET)
+ return True
+ except:
+ pass
+
+ # sledgehammer style:
+ # - call ourselves prefixed by 'unshare -n' if found
+ # - pass extra --no-netns parameter to avoid another recursion
+ try:
+ import shutil
+
+ unshare = shutil.which("unshare")
+ if unshare is None:
+ return False
+
+ sys.argv.append("--no-netns")
+ os.execv(unshare, [unshare, "-n", sys.executable] + sys.argv)
+ except:
+ pass
+
+ return False
#
# main
@@ -321,8 +564,11 @@ def main():
help='Check for missing tests')
parser.add_argument('-n', '--nftables', action='store_true',
help='Test iptables-over-nftables')
- parser.add_argument('-N', '--netns', action='store_true',
+ parser.add_argument('-N', '--netns', action='store_const',
+ const='____iptables-container-test',
help='Test netnamespace path')
+ parser.add_argument('--no-netns', action='store_true',
+ help='Do not run testsuite in own network namespace')
args = parser.parse_args()
#
@@ -332,49 +578,72 @@ def main():
show_missing()
return
- global EXECUTEABLE
- EXECUTEABLE = "xtables-legacy-multi"
+ variants = []
+ if args.legacy:
+ variants.append("legacy")
if args.nftables:
- EXECUTEABLE = "xtables-nft-multi"
+ variants.append("nft")
+ if len(variants) == 0:
+ variants = [ "legacy", "nft" ]
if os.getuid() != 0:
- print("You need to be root to run this, sorry")
- return
+ print("You need to be root to run this, sorry", file=sys.stderr)
+ return 77
+
+ if not args.netns and not args.no_netns and not spawn_netns():
+ print("Cannot run in own namespace, connectivity might break",
+ file=sys.stderr)
if not args.host:
os.putenv("XTABLES_LIBDIR", os.path.abspath(EXTENSIONS_PATH))
os.putenv("PATH", "%s/iptables:%s" % (os.path.abspath(os.path.curdir),
os.getenv("PATH")))
- test_files = 0
- tests = 0
- passed = 0
-
- # setup global var log file
- global log_file
- try:
- log_file = open(LOGFILE, 'w')
- except IOError:
- print("Couldn't open log file %s" % LOGFILE)
- return
-
- if 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()
-
- for filename in file_list:
- file_tests, file_passed = run_test_file(filename, args.netns)
- if file_tests:
- tests += file_tests
- passed += file_passed
- test_files += 1
-
- print("%d test files, %d unit tests, %d passed" % (test_files, tests, passed))
-
+ total_test_files = 0
+ total_passed = 0
+ total_tests = 0
+ for variant in variants:
+ global EXECUTABLE
+ EXECUTABLE = "xtables-" + variant + "-multi"
+
+ test_files = 0
+ tests = 0
+ passed = 0
+
+ # setup global var log file
+ global log_file
+ try:
+ log_file = open(LOGFILE, 'w')
+ except IOError:
+ print("Couldn't open log file %s" % LOGFILE, file=sys.stderr)
+ return
+
+ if 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()
+
+ for filename in file_list:
+ file_tests, file_passed = run_test_file(filename, args.netns)
+ if file_tests:
+ tests += file_tests
+ passed += file_passed
+ test_files += 1
+
+ print("%s: %d test files, %d unit tests, %d passed"
+ % (variant, test_files, tests, passed))
+
+ total_passed += passed
+ total_tests += tests
+ total_test_files = max(total_test_files, test_files)
+
+ if len(variants) > 1:
+ print("total: %d test files, %d unit tests, %d passed"
+ % (total_test_files, total_tests, total_passed))
+ return total_passed - total_tests
if __name__ == '__main__':
- main()
+ sys.exit(main())
diff --git a/iptables/.gitignore b/iptables/.gitignore
index cd7d87b1..8141e34d 100644
--- a/iptables/.gitignore
+++ b/iptables/.gitignore
@@ -1,6 +1,11 @@
+/ebtables-translate.8
/ip6tables
+/ip6tables.8
+/ip6tables-apply.8
/ip6tables-save
+/ip6tables-save.8
/ip6tables-restore
+/ip6tables-restore.8
/ip6tables-static
/ip6tables-translate.8
/ip6tables-restore-translate.8
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 4bf5742c..2007cd10 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -1,50 +1,67 @@
# -*- Makefile -*-
AM_CFLAGS = ${regular_CFLAGS}
-AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir} ${kinclude_CPPFLAGS} ${libmnl_CFLAGS} ${libnftnl_CFLAGS} ${libnetfilter_conntrack_CFLAGS}
+AM_CPPFLAGS = ${regular_CPPFLAGS} \
+ -I${top_builddir}/include \
+ -I${top_srcdir}/include \
+ -I${top_srcdir} \
+ ${kinclude_CPPFLAGS} \
+ ${libmnl_CFLAGS} \
+ ${libnftnl_CFLAGS} \
+ ${libnetfilter_conntrack_CFLAGS}
+AM_LDFLAGS = ${regular_LDFLAGS}
BUILT_SOURCES =
-xtables_legacy_multi_SOURCES = xtables-legacy-multi.c iptables-xml.c
-xtables_legacy_multi_CFLAGS = ${AM_CFLAGS}
-xtables_legacy_multi_LDADD = ../extensions/libext.a
+common_sources = iptables-xml.c xtables-multi.h xshared.c xshared.h
+common_ldadd = ../extensions/libext.a ../libxtables/libxtables.la -lm
+common_cflags = ${AM_CFLAGS}
if ENABLE_STATIC
-xtables_legacy_multi_CFLAGS += -DALL_INCLUSIVE
+common_cflags += -DALL_INCLUSIVE
endif
+
+xtables_legacy_multi_SOURCES = ${common_sources} xtables-legacy-multi.c \
+ iptables-restore.c iptables-save.c
+xtables_legacy_multi_CFLAGS = ${common_cflags}
+xtables_legacy_multi_LDADD = ${common_ldadd}
if ENABLE_IPV4
-xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c
+xtables_legacy_multi_SOURCES += iptables-standalone.c iptables.c iptables-multi.h
xtables_legacy_multi_CFLAGS += -DENABLE_IPV4
xtables_legacy_multi_LDADD += ../libiptc/libip4tc.la ../extensions/libext4.a
endif
if ENABLE_IPV6
-xtables_legacy_multi_SOURCES += ip6tables-standalone.c ip6tables.c
+xtables_legacy_multi_SOURCES += ip6tables-standalone.c ip6tables.c ip6tables-multi.h
xtables_legacy_multi_CFLAGS += -DENABLE_IPV6
xtables_legacy_multi_LDADD += ../libiptc/libip6tc.la ../extensions/libext6.a
endif
-xtables_legacy_multi_SOURCES += xshared.c iptables-restore.c iptables-save.c
-xtables_legacy_multi_LDADD += ../libxtables/libxtables.la -lm
# iptables using nf_tables api
if ENABLE_NFTABLES
-xtables_nft_multi_SOURCES = xtables-nft-multi.c iptables-xml.c
-xtables_nft_multi_CFLAGS = ${AM_CFLAGS}
-xtables_nft_multi_LDADD = ../extensions/libext.a ../extensions/libext_ebt.a
-if ENABLE_STATIC
-xtables_nft_multi_CFLAGS += -DALL_INCLUSIVE
-endif
+xtables_nft_multi_SOURCES = ${common_sources} xtables-nft-multi.c
+xtables_nft_multi_CFLAGS = ${common_cflags}
+xtables_nft_multi_LDADD = ${common_ldadd} \
+ ../extensions/libext_arpt.a \
+ ../extensions/libext_ebt.a \
+ ../extensions/libext4.a \
+ ../extensions/libext6.a \
+ ${libmnl_LIBS} ${libnftnl_LIBS} \
+ ${libnetfilter_conntrack_LIBS}
xtables_nft_multi_CFLAGS += -DENABLE_NFTABLES -DENABLE_IPV4 -DENABLE_IPV6
-xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \
- xtables-standalone.c xtables.c nft.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 \
- xtables-eb-standalone.c xtables-eb.c \
- xtables-eb-translate.c \
- xtables-translate.c
-xtables_nft_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ${libnetfilter_conntrack_LIBS} ../extensions/libext4.a ../extensions/libext6.a ../extensions/libext_ebt.a ../extensions/libext_arpt.a
-xtables_nft_multi_SOURCES += xshared.c
-xtables_nft_multi_LDADD += ../libxtables/libxtables.la -lm
+xtables_nft_multi_SOURCES += nft.c nft.h \
+ nft-arp.c nft-ipv4.c nft-ipv6.c \
+ nft-bridge.c nft-bridge.h \
+ nft-cache.c nft-cache.h \
+ nft-chain.c nft-chain.h \
+ nft-cmd.c nft-cmd.h \
+ nft-ruleparse.c nft-ruleparse.h \
+ nft-ruleparse-arp.c nft-ruleparse-bridge.c \
+ nft-ruleparse-ipv4.c nft-ruleparse-ipv6.c \
+ nft-shared.c nft-shared.h \
+ xtables-monitor.c \
+ xtables.c xtables-arp.c xtables-eb.c \
+ xtables-standalone.c xtables-eb-standalone.c \
+ xtables-translate.c xtables-eb-translate.c \
+ xtables-save.c xtables-restore.c
endif
sbin_PROGRAMS = xtables-legacy-multi
@@ -56,22 +73,21 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \
ip6tables-save.8 iptables-extensions.8 \
iptables-apply.8 ip6tables-apply.8
-sbin_SCRIPTS = iptables-apply
+dist_sbin_SCRIPTS = iptables-apply
+dist_pkgdata_DATA = iptables.xslt
+
+xlate_man_links = iptables-translate.8 ip6tables-translate.8 \
+ iptables-restore-translate.8 ip6tables-restore-translate.8 \
+ ebtables-translate.8 arptables-translate.8
if ENABLE_NFTABLES
-man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
- iptables-translate.8 ip6tables-translate.8 \
- iptables-restore-translate.8 ip6tables-restore-translate.8 \
- xtables-monitor.8 \
- arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \
- ebtables-nft.8
+man_MANS += ${xlate_man_links} xtables-monitor.8
+
+dist_man_MANS = xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
+ arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8 \
+ ebtables-nft.8
endif
-CLEANFILES = iptables.8 xtables-monitor.8 \
- iptables-xml.1 iptables-apply.8 \
- iptables-extensions.8 iptables-extensions.8.tmpl \
- iptables-restore.8 iptables-save.8 \
- iptables-restore-translate.8 ip6tables-restore-translate.8 \
- iptables-translate.8 ip6tables-translate.8
+CLEANFILES = ${man_MANS} iptables-extensions.8.tmpl
vx_bin_links = iptables-xml
if ENABLE_IPV4
@@ -85,11 +101,12 @@ endif
if ENABLE_NFTABLES
x_sbin_links = iptables-nft iptables-nft-restore iptables-nft-save \
ip6tables-nft ip6tables-nft-restore ip6tables-nft-save \
- iptables-translate ip6tables-translate \
+ iptables-translate ip6tables-translate ebtables-translate \
iptables-restore-translate ip6tables-restore-translate \
arptables-nft arptables \
arptables-nft-restore arptables-restore \
arptables-nft-save arptables-save \
+ arptables-translate \
ebtables-nft ebtables \
ebtables-nft-restore ebtables-restore \
ebtables-nft-save ebtables-save \
@@ -97,12 +114,15 @@ x_sbin_links = iptables-nft iptables-nft-restore iptables-nft-save \
endif
iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../extensions/targets.man
- ${AM_VERBOSE_GEN} sed \
+ ${AM_V_GEN} sed \
-e '/@MATCH@/ r ../extensions/matches.man' \
-e '/@TARGET@/ r ../extensions/targets.man' $< >$@;
-iptables-translate.8 ip6tables-translate.8 iptables-restore-translate.8 ip6tables-restore-translate.8:
- ${AM_VERBOSE_GEN} echo '.so man8/xtables-translate.8' >$@
+${xlate_man_links}:
+ ${AM_V_GEN} echo '.so man8/xtables-translate.8' >$@
+
+ip6tables.8 ip6tables-apply.8 ip6tables-restore.8 ip6tables-save.8:
+ ${AM_V_GEN} echo "$@" | sed 's|^ip6|.so man8/ip|' >$@
pkgconfig_DATA = xtables.pc
@@ -138,3 +158,5 @@ uninstall-hook:
); \
( cd "$$dir" && rm -f ip6tables-apply ); \
}
+
+EXTRA_DIST = tests
diff --git a/iptables/arptables-nft-restore.8 b/iptables/arptables-nft-restore.8
index 09d9082c..596ca1c9 100644
--- a/iptables/arptables-nft-restore.8
+++ b/iptables/arptables-nft-restore.8
@@ -20,9 +20,9 @@
.\"
.\"
.SH NAME
-arptables-restore \- Restore ARP Tables (nft-based)
+arptables-restore \(em Restore ARP Tables (nft-based)
.SH SYNOPSIS
-\fBarptables\-restore
+\fBarptables\-restore\fP
.SH DESCRIPTION
.PP
.B arptables-restore
diff --git a/iptables/arptables-nft-save.8 b/iptables/arptables-nft-save.8
index 905e5985..e9171d5d 100644
--- a/iptables/arptables-nft-save.8
+++ b/iptables/arptables-nft-save.8
@@ -20,7 +20,7 @@
.\"
.\"
.SH NAME
-arptables-save \- dump arptables rules to stdout (nft-based)
+arptables-save \(em dump arptables rules to stdout (nft-based)
.SH SYNOPSIS
\fBarptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP]
.P
diff --git a/iptables/arptables-nft.8 b/iptables/arptables-nft.8
index ea31e084..c48a2cc2 100644
--- a/iptables/arptables-nft.8
+++ b/iptables/arptables-nft.8
@@ -22,22 +22,36 @@
.\"
.\"
.SH NAME
-arptables \- ARP table administration (nft-based)
+arptables \(em ARP table administration (nft-based)
.SH SYNOPSIS
-.BR "arptables " [ "-t table" ] " -" [ AD ] " chain rule-specification " [ options ]
-.br
-.BR "arptables " [ "-t table" ] " -" [ RI ] " chain rulenum rule-specification " [ options ]
-.br
-.BR "arptables " [ "-t table" ] " -D chain rulenum " [ options ]
-.br
-.BR "arptables " [ "-t table" ] " -" [ "LFZ" ] " " [ chain ] " " [ options ]
-.br
-.BR "arptables " [ "-t table" ] " -" [ "NX" ] " chain"
-.br
-.BR "arptables " [ "-t table" ] " -E old-chain-name new-chain-name"
-.br
-.BR "arptables " [ "-t table" ] " -P chain target " [ options ]
-
+\fBarptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A|\-D\fP} \fIchain\fP
+\fIrule-specification\fP [options...]
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] \fB\-I\fP \fIchain\fP [\fIrulenum\fP]
+\fIrule-specification\fP
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] \fB\-R\fP \fIchain rulenum
+rule-specification\fP
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] \fB\-D\fP \fIchain rulenum\fP
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] {\fB\-F\fP|\fB\-L\fP|\fB\-Z\fP}
+[\fIchain\fP [\fIrulenum\fP]] [\fIoptions...\fP]
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] \fB\-N\fP \fIchain\fP
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] \fB\-X\fP [\fIchain\fP]
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] \fB\-P\fP \fIchain policy\fP
+.PP
+\fBarptables\fP [\fB\-t\fP \fItable\fP] \fB\-E\fP \fIold-chain-name
+new-chain-name\fP
+.PP
+rule-specification := [matches...] [target]
+.PP
+match := \fB\-m\fP \fImatchname\fP [per-match-options]
+.PP
+target := \fB\-j\fP \fItargetname\fP [per-target-options]
.SH DESCRIPTION
.B arptables
is a user space tool, it is used to set up and maintain the
@@ -88,11 +102,11 @@ section of this man page.
There is only one ARP table in the Linux
kernel. The table is
.BR filter.
-You can drop the '-t filter' argument to the arptables command.
-The -t argument must be the
+You can drop the '\-t filter' argument to the arptables command.
+The \-t argument must be the
first argument on the arptables command line, if used.
.TP
-.B "-t, --table"
+.B "\-t, \-\-table"
.br
.BR filter ,
is the only table and contains two built-in chains:
@@ -109,79 +123,79 @@ are commands, miscellaneous commands, rule-specifications, match-extensions,
and watcher-extensions.
.SS COMMANDS
The arptables command arguments specify the actions to perform on the table
-defined with the -t argument. If you do not use the -t argument to name
+defined with the \-t argument. If you do not use the \-t argument to name
a table, the commands apply to the default filter table.
With the exception of the
-.B "-Z"
+.B "\-Z"
command, only one command may be used on the command line at a time.
.TP
-.B "-A, --append"
+.B "\-A, \-\-append"
Append a rule to the end of the selected chain.
.TP
-.B "-D, --delete"
+.B "\-D, \-\-delete"
Delete the specified rule from the selected chain. There are two ways to
use this command. The first is by specifying an interval of rule numbers
to delete, syntax: start_nr[:end_nr]. Using negative numbers is allowed, for more
-details about using negative numbers, see the -I command. The second usage is by
+details about using negative numbers, see the \-I command. The second usage is by
specifying the complete rule as it would have been specified when it was added.
.TP
-.B "-I, --insert"
+.B "\-I, \-\-insert"
Insert the specified rule into the selected chain at the specified rule number.
If the current number of rules equals N, then the specified number can be
-between -N and N+1. For a positive number i, it holds that i and i-N-1 specify the
+between \-N and N+1. For a positive number i, it holds that i and i\-N\-1 specify the
same place in the chain where the rule should be inserted. The number 0 specifies
the place past the last rule in the chain and using this number is therefore
-equivalent with using the -A command.
+equivalent with using the \-A command.
.TP
-.B "-R, --replace"
+.B "\-R, \-\-replace"
Replaces the specified rule into the selected chain at the specified rule number.
If the current number of rules equals N, then the specified number can be
between 1 and N. i specifies the place in the chain where the rule should be replaced.
.TP
-.B "-P, --policy"
+.B "\-P, \-\-policy"
Set the policy for the chain to the given target. The policy can be
.BR ACCEPT ", " DROP " or " RETURN .
.TP
-.B "-F, --flush"
+.B "\-F, \-\-flush"
Flush the selected chain. If no chain is selected, then every chain will be
flushed. Flushing the chain does not change the policy of the
chain, however.
.TP
-.B "-Z, --zero"
+.B "\-Z, \-\-zero"
Set the counters of the selected chain to zero. If no chain is selected, all the counters
are set to zero. The
-.B "-Z"
+.B "\-Z"
command can be used in conjunction with the
-.B "-L"
+.B "\-L"
command.
When both the
-.B "-Z"
+.B "\-Z"
and
-.B "-L"
+.B "\-L"
commands are used together in this way, the rule counters are printed on the screen
before they are set to zero.
.TP
-.B "-L, --list"
+.B "\-L, \-\-list"
List all rules in the selected chain. If no chain is selected, all chains
are listed.
.TP
-.B "-N, --new-chain"
+.B "\-N, \-\-new-chain"
Create a new user-defined chain with the given name. The number of
user-defined chains is unlimited. A user-defined chain name has maximum
length of 31 characters.
.TP
-.B "-X, --delete-chain"
+.B "\-X, \-\-delete-chain"
Delete the specified user-defined chain. There must be no remaining references
to the specified chain, otherwise
.B arptables
will refuse to delete it. If no chain is specified, all user-defined
chains that aren't referenced will be removed.
.TP
-.B "-E, --rename-chain"
+.B "\-E, \-\-rename\-chain"
Rename the specified chain to a new name. Besides renaming a user-defined
chain, you may rename a standard chain name to a name that suits your
taste. For example, if you like PREBRIDGING more than PREROUTING,
-then you can use the -E command to rename the PREROUTING chain. If you do
+then you can use the \-E command to rename the PREROUTING chain. If you do
rename one of the standard
.B arptables
chain names, please be sure to mention
@@ -195,15 +209,15 @@ of the
.B arptables
kernel table.
-.SS MISCELLANOUS COMMANDS
+.SS MISCELLANEOUS COMMANDS
.TP
-.B "-V, --version"
+.B "\-V, \-\-version"
Show the version of the arptables userspace program.
.TP
-.B "-h, --help"
+.B "\-h, \-\-help"
Give a brief description of the command syntax.
.TP
-.BR "-j, --jump " "\fItarget\fP"
+.BR "\-j, \-\-jump " "\fItarget\fP"
The target of the rule. This is one of the following values:
.BR ACCEPT ,
.BR DROP ,
@@ -213,7 +227,7 @@ a target extension (see
.BR "TARGET EXTENSIONS" ")"
or a user-defined chain name.
.TP
-.BI "-c, --set-counters " "PKTS BYTES"
+.BI "\-c, \-\-set-counters " "PKTS BYTES"
This enables the administrator to initialize the packet and byte
counters of a rule (during
.B INSERT,
@@ -227,38 +241,38 @@ in the add and delete commands). A "!" option before the specification
inverts the test for that specification. Apart from these standard rule
specifications there are some other command line arguments of interest.
.TP
-.BR "-s, --source-ip " "[!] \fIaddress\fP[/\fImask]\fP"
+.BR "\-s, \-\-source\-ip " "[!] \fIaddress\fP[/\fImask]\fP"
The Source IP specification.
.TP
-.BR "-d, --destination-ip " "[!] \fIaddress\fP[/\fImask]\fP"
+.BR "\-d, \-\-destination\-ip " "[!] \fIaddress\fP[/\fImask]\fP"
The Destination IP specification.
.TP
-.BR "--source-mac " "[!] \fIaddress\fP[/\fImask\fP]"
+.BR "\-\-source\-mac " "[!] \fIaddress\fP[/\fImask\fP]"
The source mac address. Both mask and address are written as 6 hexadecimal
numbers separated by colons.
.TP
-.BR "--destination-mac " "[!] \fIaddress\fP[/\fImask\fP]"
+.BR "\-\-destination\-mac " "[!] \fIaddress\fP[/\fImask\fP]"
The destination mac address. Both mask and address are written as 6 hexadecimal
numbers separated by colons.
.TP
-.BR "-i, --in-interface " "[!] \fIname\fP"
+.BR "\-i, \-\-in\-interface " "[!] \fIname\fP"
The interface via which a frame is received (for the
.B INPUT
chain). The flag
-.B --in-if
+.B \-\-in\-if
is an alias for this option.
.TP
-.BR "-o, --out-interface " "[!] \fIname\fP"
+.BR "\-o, \-\-out-interface " "[!] \fIname\fP"
The interface via which a frame is going to be sent (for the
.B OUTPUT
chain). The flag
-.B --out-if
+.B \-\-out\-if
is an alias for this option.
.TP
-.BR "-l, --h-length " "\fIlength\fP[/\fImask\fP]"
+.BR "\-l, \-\-h\-length " "\fIlength\fP[/\fImask\fP]"
The hardware length (nr of bytes)
.TP
-.BR "--opcode " "\fIcode\fP[/\fImask\fP]
+.BR "\-\-opcode " "\fIcode\fP[/\fImask\fP]
The operation code (2 bytes). Available values are:
.BR 1 = Request
.BR 2 = Reply
@@ -270,63 +284,63 @@ The operation code (2 bytes). Available values are:
.BR 8 = InARP_Request
.BR 9 = ARP_NAK .
.TP
-.BR "--h-type " "\fItype\fP[/\fImask\fP]"
+.BR "\-\-h\-type " "\fItype\fP[/\fImask\fP]"
The hardware type (2 bytes, hexadecimal). Available values are:
.BR 1 = Ethernet .
.TP
-.BR "--proto-type " "\fItype\fP[/\fImask\fP]"
+.BR "\-\-proto\-type " "\fItype\fP[/\fImask\fP]"
The protocol type (2 bytes). Available values are:
.BR 0x800 = IPv4 .
.SS TARGET-EXTENSIONS
.B arptables
extensions are precompiled into the userspace tool. So there is no need
-to explicitly load them with a -m option like in
+to explicitly load them with a \-m option like in
.BR iptables .
However, these
extensions deal with functionality supported by supplemental kernel modules.
.SS mangle
.TP
-.BR "--mangle-ip-s IP address"
+.BR "\-\-mangle\-ip\-s IP address"
Mangles Source IP Address to given value.
.TP
-.BR "--mangle-ip-d IP address"
+.BR "\-\-mangle\-ip\-d IP address"
Mangles Destination IP Address to given value.
.TP
-.BR "--mangle-mac-s MAC address"
+.BR "\-\-mangle\-mac\-s MAC address"
Mangles Source MAC Address to given value.
.TP
-.BR "--mangle-mac-d MAC address"
+.BR "\-\-mangle\-mac\-d MAC address"
Mangles Destination MAC Address to given value.
.TP
-.BR "--mangle-target target "
+.BR "\-\-mangle\-target target "
Target of ARP mangle operation
-.BR "" ( DROP ", " CONTINUE " or " ACCEPT " -- default is " ACCEPT ).
+.BR "" ( DROP ", " CONTINUE " or " ACCEPT " \(em default is " ACCEPT ).
.SS CLASSIFY
-This module allows you to set the skb->priority value (and thus clas-
-sify the packet into a specific CBQ class).
+This module allows you to set the skb\->priority value (and thus
+classify the packet into a specific CBQ class).
.TP
-.BR "--set-class major:minor"
+.BR "\-\-set\-class major:minor"
Set the major and minor class value. The values are always
interpreted as hexadecimal even if no 0x prefix is given.
.SS MARK
-This module allows you to set the skb->mark value (and thus classify
+This module allows you to set the skb\->mark value (and thus classify
the packet by the mark in u32)
.TP
-.BR "--set-mark mark"
+.BR "\-\-set\-mark mark"
Set the mark value. The values are always
interpreted as hexadecimal even if no 0x prefix is given
.TP
-.BR "--and-mark mark"
+.BR "\-\-and\-mark mark"
Binary AND the mark with bits.
.TP
-.BR "--or-mark mark"
+.BR "\-\-or\-mark mark"
Binary OR the mark with bits.
.SH NOTES
@@ -343,6 +357,6 @@ chain in
.SH MAILINGLISTS
.BR "" "See " http://netfilter.org/mailinglists.html
.SH SEE ALSO
-.BR xtables-nft "(8), " iptables "(8), " ebtables "(8), " ip (8)
+.BR xtables\-nft "(8), " iptables "(8), " ebtables "(8), " ip (8)
.PP
.BR "" "See " https://wiki.nftables.org
diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8
index 1fa5ad93..29c7d9fa 100644
--- a/iptables/ebtables-nft.8
+++ b/iptables/ebtables-nft.8
@@ -24,7 +24,7 @@
.\"
.\"
.SH NAME
-ebtables \- Ethernet bridge frame table administration (nft-based)
+ebtables \(em Ethernet bridge frame table administration (nft-based)
.SH SYNOPSIS
.BR "ebtables " [ -t " table ] " - [ ACDI "] chain rule specification [match extensions] [watcher extensions] target"
.br
@@ -44,12 +44,6 @@ ebtables \- Ethernet bridge frame table administration (nft-based)
.br
.BR "ebtables " [ -t " table ] " --init-table
.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-commit
-.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-init
-.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save
-.br
.SH DESCRIPTION
.B ebtables
@@ -61,7 +55,7 @@ It is analogous to the
application, but less complicated, due to the fact that the Ethernet protocol
is much simpler than the IP protocol.
.SS CHAINS
-There are two ebtables tables with built-in chains in the
+There are three ebtables tables with built-in chains in the
Linux kernel. These tables are used to divide functionality into
different sets of rules. Each set of rules is called a chain.
Each chain is an ordered list of rules that can match Ethernet frames. If a
@@ -87,7 +81,10 @@ an 'extension' (see below) or a jump to a user-defined chain.
.B ACCEPT
means to let the frame through.
.B DROP
-means the frame has to be dropped.
+means the frame has to be dropped. In the
+.BR BROUTING " chain however, the " ACCEPT " and " DROP " target have different"
+meanings (see the info provided for the
+.BR -t " option)."
.B CONTINUE
means the next rule has to be checked. This can be handy, f.e., to know how many
frames pass a certain point in the chain, to log those frames or to apply multiple
@@ -99,17 +96,13 @@ For the extension targets please refer to the
.B "TARGET EXTENSIONS"
section of this man page.
.SS TABLES
-As stated earlier, there are two ebtables tables in the Linux
-kernel. The table names are
-.BR filter " and " nat .
-Of these two tables,
+As stated earlier, the table names are
+.BR filter ", " nat " and " broute .
+Of these tables,
the filter table is the default table that the command operates on.
-If you are working with the filter table, then you can drop the '-t filter'
-argument to the ebtables command. However, you will need to provide
-the -t argument for
-.B nat
-table. Moreover, the -t argument must be the
-first argument on the ebtables command line, if used.
+If you are working with a table other than filter, you will need to provide
+the -t argument. Moreover, the -t argument must be the
+first argument on the ebtables command line, if used.
.TP
.B "-t, --table"
.br
@@ -137,6 +130,23 @@ iptables world to ebtables it is easier to have the same names. Note that you
can change the name
.BR "" ( -E )
if you don't like the default.
+.br
+.br
+.B broute
+is used to make a brouter, it has one built-in chain:
+.BR BROUTING .
+The targets
+.BR DROP " and " ACCEPT
+have a special meaning in the broute table (these names are used for
+compatibility reasons with ebtables-legacy).
+.B DROP
+actually means the frame has to be routed, while
+.B ACCEPT
+means the frame has to be bridged. The
+.B BROUTING
+chain is traversed very early.
+Normally those frames
+would be bridged, but you can decide otherwise here.
.SH EBTABLES COMMAND LINE ARGUMENTS
After the initial ebtables '-t table' command line argument, the remaining
arguments can be divided into several groups. These groups
@@ -149,11 +159,9 @@ a table, the commands apply to the default filter table.
Only one command may be used on the command line at a time, except when
the commands
.BR -L " and " -Z
-are combined, the commands
+are combined or the commands
.BR -N " and " -P
-are combined, or when
-.B --atomic-file
-is used.
+are combined.
.TP
.B "-A, --append"
Append a rule to the end of the selected chain.
@@ -313,40 +321,13 @@ of the ebtables kernel table.
.TP
.B "--init-table"
Replace the current table data by the initial table data.
+.SS MISCELLANEOUS COMMANDS
.TP
-.B "--atomic-init"
-Copy the kernel's initial data of the table to the specified
-file. This can be used as the first action, after which rules are added
-to the file. The file can be specified using the
-.B --atomic-file
-command or through the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
-.B "--atomic-save"
-Copy the kernel's current data of the table to the specified
-file. This can be used as the first action, after which rules are added
-to the file. The file can be specified using the
-.B --atomic-file
-command or through the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
-.B "--atomic-commit"
-Replace the kernel table data with the data contained in the specified
-file. This is a useful command that allows you to load all your rules of a
-certain table into the kernel at once, saving the kernel a lot of precious
-time and allowing atomic updates of the tables. The file which contains
-the table data is constructed by using either the
-.B "--atomic-init"
-or the
-.B "--atomic-save"
-command to generate a starting file. After that, using the
-.B "--atomic-file"
-command when constructing rules or setting the
-.IR EBTABLES_ATOMIC_FILE " environment variable"
-allows you to extend the file and build the complete table before
-committing it to the kernel. This command can be very useful in boot scripts
-to populate the ebtables tables in a fast way.
-.SS MISCELLANOUS COMMANDS
+.B "-v, --verbose"
+Verbose mode.
+For appending, insertion, deletion and replacement, this causes
+detailed information on the rule or rules to be printed. \fB\-v\fP may be
+specified multiple times to possibly emit more detailed debug statements.
.TP
.B "-V, --version"
Show the version of the ebtables userspace program.
@@ -371,16 +352,6 @@ a target extension (see
.BR "TARGET EXTENSIONS" ")"
or a user-defined chain name.
.TP
-.B --atomic-file "\fIfile\fP"
-Let the command operate on the specified
-.IR file .
-The data of the table to
-operate on will be extracted from the file and the result of the operation
-will be saved back into the file. If specified, this option should come
-before the command specification. An alternative that should be preferred,
-is setting the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
.B -M, --modprobe "\fIprogram\fP"
When talking to the kernel, use this
.I program
@@ -401,7 +372,7 @@ and the
.BR "WATCHER EXTENSIONS"
below.
.TP
-.BR "-p, --protocol " "[!] \fIprotocol\fP"
+.RB [ ! ] " -p" , " --protocol " \fIprotocol\fP
The protocol that was responsible for creating the frame. This can be a
hexadecimal number, above
.IR 0x0600 ,
@@ -431,7 +402,7 @@ See that file for more information. The flag
.B --proto
is an alias for this option.
.TP
-.BR "-i, --in-interface " "[!] \fIname\fP"
+.RB [ ! ] " -i" , " --in-interface " \fIname\fP
The interface (bridge port) via which a frame is received (this option is useful in the
.BR INPUT ,
.BR FORWARD ,
@@ -442,7 +413,7 @@ The flag
.B --in-if
is an alias for this option.
.TP
-.BR "--logical-in " "[!] \fIname\fP"
+.RB [ ! ] " --logical-in " \fIname\fP
The (logical) bridge interface via which a frame is received (this option is useful in the
.BR INPUT ,
.BR FORWARD ,
@@ -451,7 +422,7 @@ chains).
If the interface name ends with '+', then
any interface name that begins with this name (disregarding '+') will match.
.TP
-.BR "-o, --out-interface " "[!] \fIname\fP"
+.RB [ ! ] " -o" , " --out-interface " \fIname\fP
The interface (bridge port) via which a frame is going to be sent (this option is useful in the
.BR OUTPUT ,
.B FORWARD
@@ -463,7 +434,7 @@ The flag
.B --out-if
is an alias for this option.
.TP
-.BR "--logical-out " "[!] \fIname\fP"
+.RB [ ! ] " --logical-out " \fIname\fP
The (logical) bridge interface via which a frame is going to be sent (this option
is useful in the
.BR OUTPUT ,
@@ -474,7 +445,7 @@ chains).
If the interface name ends with '+', then
any interface name that begins with this name (disregarding '+') will match.
.TP
-.BR "-s, --source " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " -s" , " --source " \fIaddress\fP[ / \fImask\fP]
The source MAC address. Both mask and address are written as 6 hexadecimal
numbers separated by colons. Alternatively one can specify Unicast,
Multicast, Broadcast or BGA (Bridge Group Address):
@@ -488,7 +459,7 @@ address will also match the multicast specification. The flag
.B --src
is an alias for this option.
.TP
-.BR "-d, --destination " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " -d" , " --destination " \fIaddress\fP[ / \fImask\fP]
The destination MAC address. See
.B -s
(above) for more details on MAC addresses. The flag
@@ -513,11 +484,11 @@ the core ebtables code.
Specify 802.3 DSAP/SSAP fields or SNAP type. The protocol must be specified as
.IR "LENGTH " "(see the option " " -p " above).
.TP
-.BR "--802_3-sap " "[!] \fIsap\fP"
+.RB [ ! ] " --802_3-sap " \fIsap\fP
DSAP and SSAP are two one byte 802.3 fields. The bytes are always
equal, so only one byte (hexadecimal) is needed as an argument.
.TP
-.BR "--802_3-type " "[!] \fItype\fP"
+.RB [ ! ] " --802_3-type " \fItype\fP
If the 802.3 DSAP and SSAP values are 0xaa then the SNAP type field must
be consulted to determine the payload protocol. This is a two byte
(hexadecimal) argument. Only 802.3 frames with DSAP/SSAP 0xaa are
@@ -532,88 +503,88 @@ the MAC address is optional. Multiple MAC/IP address pairs with the same MAC add
but different IP address (and vice versa) can be specified. If the MAC address doesn't
match any entry from the list, the frame doesn't match the rule (unless "!" was used).
.TP
-.BR "--among-dst " "[!] \fIlist\fP"
+.RB [ ! ] " --among-dst " \fIlist\fP
Compare the MAC destination to the given list. If the Ethernet frame has type
.IR IPv4 " or " ARP ,
then comparison with MAC/IP destination address pairs from the
list is possible.
.TP
-.BR "--among-src " "[!] \fIlist\fP"
+.RB [ ! ] " --among-src " \fIlist\fP
Compare the MAC source to the given list. If the Ethernet frame has type
.IR IPv4 " or " ARP ,
then comparison with MAC/IP source address pairs from the list
is possible.
.TP
-.BR "--among-dst-file " "[!] \fIfile\fP"
+.RB [ ! ] " --among-dst-file " \fIfile\fP
Same as
.BR --among-dst " but the list is read in from the specified file."
.TP
-.BR "--among-src-file " "[!] \fIfile\fP"
+.RB [ ! ] " --among-src-file " \fIfile\fP
Same as
.BR --among-src " but the list is read in from the specified file."
.SS arp
Specify (R)ARP fields. The protocol must be specified as
.IR ARP " or " RARP .
.TP
-.BR "--arp-opcode " "[!] \fIopcode\fP"
+.RB [ ! ] " --arp-opcode " \fIopcode\fP
The (R)ARP opcode (decimal or a string, for more details see
.BR "ebtables -h arp" ).
.TP
-.BR "--arp-htype " "[!] \fIhardware type\fP"
+.RB [ ! ] " --arp-htype " \fIhardware-type\fP
The hardware type, this can be a decimal or the string
.I Ethernet
(which sets
.I type
to 1). Most (R)ARP packets have Eternet as hardware type.
.TP
-.BR "--arp-ptype " "[!] \fIprotocol type\fP"
+.RB [ ! ] " --arp-ptype " \fIprotocol-type\fP
The protocol type for which the (r)arp is used (hexadecimal or the string
.IR IPv4 ,
denoting 0x0800).
Most (R)ARP packets have protocol type IPv4.
.TP
-.BR "--arp-ip-src " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --arp-ip-src " \fIaddress\fP[ / \fImask\fP]
The (R)ARP IP source address specification.
.TP
-.BR "--arp-ip-dst " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --arp-ip-dst " \fIaddress\fP[ / \fImask\fP]
The (R)ARP IP destination address specification.
.TP
-.BR "--arp-mac-src " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --arp-mac-src " \fIaddress\fP[ / \fImask\fP]
The (R)ARP MAC source address specification.
.TP
-.BR "--arp-mac-dst " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --arp-mac-dst " \fIaddress\fP[ / \fImask\fP]
The (R)ARP MAC destination address specification.
.TP
-.BR "" "[!]" " --arp-gratuitous"
+.RB [ ! ] " --arp-gratuitous"
Checks for ARP gratuitous packets: checks equality of IPv4 source
address and IPv4 destination address inside the ARP header.
.SS ip
Specify IPv4 fields. The protocol must be specified as
.IR IPv4 .
.TP
-.BR "--ip-source " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --ip-source " \fIaddress\fP[ / \fImask\fP]
The source IP address.
The flag
.B --ip-src
is an alias for this option.
.TP
-.BR "--ip-destination " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --ip-destination " \fIaddress\fP[ / \fImask\fP]
The destination IP address.
The flag
.B --ip-dst
is an alias for this option.
.TP
-.BR "--ip-tos " "[!] \fItos\fP"
+.RB [ ! ] " --ip-tos " \fItos\fP
The IP type of service, in hexadecimal numbers.
.BR IPv4 .
.TP
-.BR "--ip-protocol " "[!] \fIprotocol\fP"
+.RB [ ! ] " --ip-protocol " \fIprotocol\fP
The IP protocol.
The flag
.B --ip-proto
is an alias for this option.
.TP
-.BR "--ip-source-port " "[!] \fIport1\fP[:\fIport2\fP]"
+.RB [ ! ] " --ip-source-port " \fIport1\fP[ : \fIport2\fP]
The source port or port range for the IP protocols 6 (TCP), 17
(UDP), 33 (DCCP) or 132 (SCTP). The
.B --ip-protocol
@@ -625,7 +596,7 @@ The flag
.B --ip-sport
is an alias for this option.
.TP
-.BR "--ip-destination-port " "[!] \fIport1\fP[:\fIport2\fP]"
+.RB [ ! ] " --ip-destination-port " \fIport1\fP[ : \fIport2\fP]
The destination port or port range for ip protocols 6 (TCP), 17
(UDP), 33 (DCCP) or 132 (SCTP). The
.B --ip-protocol
@@ -640,28 +611,28 @@ is an alias for this option.
Specify IPv6 fields. The protocol must be specified as
.IR IPv6 .
.TP
-.BR "--ip6-source " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --ip6-source " \fIaddress\fP[ / \fImask\fP]
The source IPv6 address.
The flag
.B --ip6-src
is an alias for this option.
.TP
-.BR "--ip6-destination " "[!] \fIaddress\fP[/\fImask\fP]"
+.RB [ ! ] " --ip6-destination " \fIaddress\fP[ / \fImask\fP]
The destination IPv6 address.
The flag
.B --ip6-dst
is an alias for this option.
.TP
-.BR "--ip6-tclass " "[!] \fItclass\fP"
+.RB [ ! ] " --ip6-tclass " \fItclass\fP
The IPv6 traffic class, in hexadecimal numbers.
.TP
-.BR "--ip6-protocol " "[!] \fIprotocol\fP"
+.RB [ ! ] " --ip6-protocol " \fIprotocol\fP
The IP protocol.
The flag
.B --ip6-proto
is an alias for this option.
.TP
-.BR "--ip6-source-port " "[!] \fIport1\fP[:\fIport2\fP]"
+.RB [ ! ] " --ip6-source-port " \fIport1\fP[ : \fIport2\fP]
The source port or port range for the IPv6 protocols 6 (TCP), 17
(UDP), 33 (DCCP) or 132 (SCTP). The
.B --ip6-protocol
@@ -673,7 +644,7 @@ The flag
.B --ip6-sport
is an alias for this option.
.TP
-.BR "--ip6-destination-port " "[!] \fIport1\fP[:\fIport2\fP]"
+.RB [ ! ] " --ip6-destination-port " \fIport1\fP[ : \fIport2\fP]
The destination port or port range for IPv6 protocols 6 (TCP), 17
(UDP), 33 (DCCP) or 132 (SCTP). The
.B --ip6-protocol
@@ -685,7 +656,7 @@ The flag
.B --ip6-dport
is an alias for this option.
.TP
-.BR "--ip6-icmp-type " "[!] {\fItype\fP[:\fItype\fP]/\fIcode\fP[:\fIcode\fP]|\fItypename\fP}"
+.RB [ ! ] " --ip6-icmp-type " {\fItype\fP[ : \fItype\fP] / \fIcode\fP[ : \fIcode\fP]|\fItypename\fP}
Specify ipv6\-icmp type and code to match.
Ranges for both type and code are supported. Type and code are
separated by a slash. Valid numbers for type and range are 0 to 255.
@@ -714,7 +685,7 @@ number; the default is
.IR 5 .
.SS mark_m
.TP
-.BR "--mark " "[!] [\fIvalue\fP][/\fImask\fP]"
+.RB [ ! ] " --mark " [\fIvalue\fP][ / \fImask\fP]
Matches frames with the given unsigned mark value. If a
.IR value " and " mask " are specified, the logical AND of the mark value of the frame and"
the user-specified
@@ -733,7 +704,7 @@ non-zero. Only specifying a
.IR mask " is useful to match multiple mark values."
.SS pkttype
.TP
-.BR "--pkttype-type " "[!] \fItype\fP"
+.RB [ ! ] " --pkttype-type " \fItype\fP
Matches on the Ethernet "class" of the frame, which is determined by the
generic networking code. Possible values:
.IR broadcast " (MAC destination is the broadcast address),"
@@ -750,47 +721,47 @@ if the lower bound is omitted (but the colon is not), then the lowest possible l
for that option is used, while if the upper bound is omitted (but the colon again is not), the
highest possible upper bound for that option is used.
.TP
-.BR "--stp-type " "[!] \fItype\fP"
-The BPDU type (0-255), recognized non-numerical types are
+.RB [ ! ] " --stp-type " \fItype\fP
+The BPDU type (0\(en255), recognized non-numerical types are
.IR config ", denoting a configuration BPDU (=0), and"
.IR tcn ", denothing a topology change notification BPDU (=128)."
.TP
-.BR "--stp-flags " "[!] \fIflag\fP"
-The BPDU flag (0-255), recognized non-numerical flags are
+.RB [ ! ] " --stp-flags " \fIflag\fP
+The BPDU flag (0\(en255), recognized non-numerical flags are
.IR topology-change ", denoting the topology change flag (=1), and"
.IR topology-change-ack ", denoting the topology change acknowledgement flag (=128)."
.TP
-.BR "--stp-root-prio " "[!] [\fIprio\fP][:\fIprio\fP]"
-The root priority (0-65535) range.
+.RB [ ! ] " --stp-root-prio " [\fIprio\fP][ : \fIprio\fP]
+The root priority (0\(en65535) range.
.TP
-.BR "--stp-root-addr " "[!] [\fIaddress\fP][/\fImask\fP]"
+.RB [ ! ] " --stp-root-addr " [\fIaddress\fP][ / \fImask\fP]
The root mac address, see the option
.BR -s " for more details."
.TP
-.BR "--stp-root-cost " "[!] [\fIcost\fP][:\fIcost\fP]"
-The root path cost (0-4294967295) range.
+.RB [ ! ] " --stp-root-cost " [\fIcost\fP][ : \fIcost\fP]
+The root path cost (0\(en4294967295) range.
.TP
-.BR "--stp-sender-prio " "[!] [\fIprio\fP][:\fIprio\fP]"
-The BPDU's sender priority (0-65535) range.
+.RB [ ! ] " --stp-sender-prio " [\fIprio\fP][ : \fIprio\fP]
+The BPDU's sender priority (0\(en65535) range.
.TP
-.BR "--stp-sender-addr " "[!] [\fIaddress\fP][/\fImask\fP]"
+.RB [ ! ] " --stp-sender-addr " [\fIaddress\fP][ / \fImask\fP]
The BPDU's sender mac address, see the option
.BR -s " for more details."
.TP
-.BR "--stp-port " "[!] [\fIport\fP][:\fIport\fP]"
-The port identifier (0-65535) range.
+.RB [ ! ] " --stp-port " [\fIport\fP][ : \fIport\fP]
+The port identifier (0\(en65535) range.
.TP
-.BR "--stp-msg-age " "[!] [\fIage\fP][:\fIage\fP]"
-The message age timer (0-65535) range.
+.RB [ ! ] " --stp-msg-age " [\fIage\fP][ : \fIage\fP]
+The message age timer (0\(en65535) range.
.TP
-.BR "--stp-max-age " "[!] [\fIage\fP][:\fIage\fP]"
-The max age timer (0-65535) range.
+.RB [ ! ] " --stp-max-age " [\fIage\fP][ : \fIage\fP]
+The max age timer (0\(en65535) range.
.TP
-.BR "--stp-hello-time " "[!] [\fItime\fP][:\fItime\fP]"
-The hello time timer (0-65535) range.
+.RB [ ! ] " --stp-hello-time " [\fItime\fP][ : \fItime\fP]
+The hello time timer (0\(en65535) range.
.TP
-.BR "--stp-forward-delay " "[!] [\fIdelay\fP][:\fIdelay\fP]"
-The forward delay timer (0-65535) range.
+.RB [ ! ] " --stp-forward-delay " [\fIdelay\fP][ : \fIdelay\fP]
+The forward delay timer (0\(en65535) range.
.\" .SS string
.\" This module matches on a given string using some pattern matching strategy.
.\" .TP
@@ -803,10 +774,10 @@ The forward delay timer (0-65535) range.
.\" .BR "--string-to " "\fIoffset\fP"
.\" The highest offset from which a match can start. (default: size of frame)
.\" .TP
-.\" .BR "--string " "[!] \fIpattern\fP"
+.\" .RB [ ! ] " --string " \fIpattern\fP
.\" Matches the given pattern.
.\" .TP
-.\" .BR "--string-hex " "[!] \fIpattern\fP"
+.\" .RB [ ! ] " --string-hex " \fIpattern\fP
.\" Matches the given pattern in hex notation, e.g. '|0D 0A|', '|0D0A|', 'www|09|netfilter|03|org|00|'
.\" .TP
.\" .BR "--string-icase"
@@ -816,15 +787,15 @@ Specify 802.1Q Tag Control Information fields.
The protocol must be specified as
.IR 802_1Q " (0x8100)."
.TP
-.BR "--vlan-id " "[!] \fIid\fP"
+.RB [ ! ] " --vlan-id " \fIid\fP
The VLAN identifier field (VID). Decimal number from 0 to 4095.
.TP
-.BR "--vlan-prio " "[!] \fIprio\fP"
+.RB [ ! ] " --vlan-prio " \fIprio\fP
The user priority field, a decimal number from 0 to 7.
The VID should be set to 0 ("null VID") or unspecified
(in the latter case the VID is deliberately set to 0).
.TP
-.BR "--vlan-encap " "[!] \fItype\fP"
+.RB [ ! ] " --vlan-encap " \fItype\fP
The encapsulated Ethernet frame type/length.
Specified as a hexadecimal
number from 0x0000 to 0xFFFF or as a symbolic name
@@ -841,7 +812,7 @@ The log watcher writes descriptive data about a frame to the syslog.
.TP
.B "--log"
.br
-Log with the default loggin options: log-level=
+Log with the default logging options: log-level=
.IR info ,
log-prefix="", no ip logging, no arp logging.
.TP
@@ -887,7 +858,7 @@ Log with the default logging options
.TP
.B --nflog-group "\fInlgroup\fP"
.br
-The netlink group (1 - 2^32-1) to which packets are (only applicable for
+The netlink group (1\(en2\(ha32\-1) to which packets are (only applicable for
nfnetlink_log). The default value is 1.
.TP
.B --nflog-prefix "\fIprefix\fP"
@@ -1100,16 +1071,17 @@ arp message and the hardware address length in the arp header is 6 bytes.
.br
.SH FILES
.I /etc/ethertypes
-.SH ENVIRONMENT VARIABLES
-.I EBTABLES_ATOMIC_FILE
.SH MAILINGLISTS
.BR "" "See " http://netfilter.org/mailinglists.html
.SH BUGS
The version of ebtables this man page ships with does not support the
-.B broute
-table. Also there is no support for
.B string
-match. And finally, this list is probably not complete.
+match. Further, support for atomic-options
+.RB ( --atomic-file ", " --atomic-init ", " --atomic-save ", " --atomic-commit )
+has not been implemented, although
+.BR ebtables-save " and " ebtables-restore
+might replace them entirely given the inherent atomicity of nftables.
+Finally, this list is probably not complete.
.SH SEE ALSO
.BR xtables-nft "(8), " iptables "(8), " ip (8)
.PP
diff --git a/iptables/ip6tables-apply.8 b/iptables/ip6tables-apply.8
deleted file mode 100644
index 994b487a..00000000
--- a/iptables/ip6tables-apply.8
+++ /dev/null
@@ -1 +0,0 @@
-.so man8/iptables-apply.8
diff --git a/iptables/ip6tables-restore.8 b/iptables/ip6tables-restore.8
deleted file mode 100644
index cf4ea3e7..00000000
--- a/iptables/ip6tables-restore.8
+++ /dev/null
@@ -1 +0,0 @@
-.so man8/iptables-restore.8
diff --git a/iptables/ip6tables-save.8 b/iptables/ip6tables-save.8
deleted file mode 100644
index 182f55c1..00000000
--- a/iptables/ip6tables-save.8
+++ /dev/null
@@ -1 +0,0 @@
-.so man8/iptables-save.8
diff --git a/iptables/ip6tables-standalone.c b/iptables/ip6tables-standalone.c
index 105b83ba..7c8bb0c2 100644
--- a/iptables/ip6tables-standalone.c
+++ b/iptables/ip6tables-standalone.c
@@ -52,11 +52,8 @@ ip6tables_main(int argc, char *argv[])
ip6tables_globals.program_version);
exit(1);
}
-
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions6();
-#endif
ret = do_command6(argc, argv, &table, &handle, false);
if (ret) {
diff --git a/iptables/ip6tables.8 b/iptables/ip6tables.8
deleted file mode 100644
index 0dee41ad..00000000
--- a/iptables/ip6tables.8
+++ /dev/null
@@ -1 +0,0 @@
-.so man8/iptables.8
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index 576c2cf8..f9ae18ae 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[] = {
@@ -91,224 +87,13 @@ static struct option original_opts[] = {
{NULL},
};
-void ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals ip6tables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (legacy)",
.orig_opts = original_opts,
- .exit_err = ip6tables_exit_error,
.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,
-/* -s */ IP6T_INV_SRCIP,
-/* -d */ IP6T_INV_DSTIP,
-/* -p */ XT_INV_PROTO,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ IP6T_INV_VIA_IN,
-/* -o */ IP6T_INV_VIA_OUT,
-/*--line*/ 0,
-/* -c */ 0,
-};
-
-#define opts ip6tables_globals.opts
-#define prog_name ip6tables_globals.program_name
-#define prog_vers ip6tables_globals.program_version
-
-static void __attribute__((noreturn))
-exit_tryhelp(int status)
-{
- if (line != -1)
- fprintf(stderr, "Error occurred at line: %d\n", line);
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- prog_name, prog_name);
- xtables_free_opts(1);
- exit(status);
-}
-
-static void
-exit_printhelp(const struct xtables_rule_match *matches)
-{
- printf("%s v%s\n\n"
-"Usage: %s -[ACD] chain rule-specification [options]\n"
-" %s -I chain [rulenum] rule-specification [options]\n"
-" %s -R chain rulenum rule-specification [options]\n"
-" %s -D chain rulenum [options]\n"
-" %s -[LS] [chain [rulenum]] [options]\n"
-" %s -[FZ] [chain] [options]\n"
-" %s -[NX] chain\n"
-" %s -E old-chain-name new-chain-name\n"
-" %s -P chain target [options]\n"
-" %s -h (print this help information)\n\n",
- prog_name, prog_vers, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name);
-
- printf(
-"Commands:\n"
-"Either long or short options are allowed.\n"
-" --append -A chain Append to chain\n"
-" --check -C chain Check for the existence of a rule\n"
-" --delete -D chain Delete matching rule from chain\n"
-" --delete -D chain rulenum\n"
-" Delete rule rulenum (1 = first) from chain\n"
-" --insert -I chain [rulenum]\n"
-" Insert in chain as rulenum (default 1=first)\n"
-" --replace -R chain rulenum\n"
-" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain [rulenum]]\n"
-" List the rules in a chain or all chains\n"
-" --list-rules -S [chain [rulenum]]\n"
-" Print the rules in a chain or all chains\n"
-" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain [rulenum]]\n"
-" Zero counters in chain or all chains\n"
-" --new -N chain Create a new user-defined chain\n"
-" --delete-chain\n"
-" -X [chain] Delete a user-defined chain\n"
-" --policy -P chain target\n"
-" Change policy on chain to target\n"
-" --rename-chain\n"
-" -E old-chain new-chain\n"
-" Change chain name, (moving any references)\n"
-
-"Options:\n"
-" --ipv4 -4 Error (line is ignored by ip6tables-restore)\n"
-" --ipv6 -6 Nothing (line is ignored by iptables-restore)\n"
-"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
-"[!] --source -s address[/mask][,...]\n"
-" source specification\n"
-"[!] --destination -d address[/mask][,...]\n"
-" destination specification\n"
-"[!] --in-interface -i input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-#ifdef IP6T_F_GOTO
-" --goto -g chain\n"
-" jump to chain with no return\n"
-#endif
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-"[!] --out-interface -o output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
-" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
-" interval to wait for xtables lock\n"
-" default is 1 second\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-/*"[!] --fragment -f match second or further fragments only\n"*/
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
-
- print_extension_helps(xtables_targets, matches);
- exit(0);
-}
-
-void
-ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, "\n");
- if (status == PARAMETER_PROBLEM)
- exit_tryhelp(status);
- if (status == VERSION_PROBLEM)
- fprintf(stderr,
- "Perhaps ip6tables or your kernel needs to be upgraded.\n");
- /* On error paths, make sure that we don't leak memory */
- xtables_free_opts(1);
- 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.
@@ -318,113 +103,6 @@ opt2char(int option)
* return global static data.
*/
-/* These are invalid numbers as upper layer protocol */
-static int is_exthdr(uint16_t proto)
-{
- return (proto == IPPROTO_ROUTING ||
- proto == IPPROTO_FRAGMENT ||
- proto == IPPROTO_AH ||
- proto == IPPROTO_DSTOPTS);
-}
-
-static void
-parse_chain(const char *chainname)
-{
- const char *ptr;
-
- if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- chainname, XT_EXTENSION_MAXNAMELEN);
-
- if (*chainname == '-' || *chainname == '!')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *chainname);
-
- if (xtables_find_target(chainname, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
-
- for (ptr = chainname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s'", chainname);
-}
-
-static void
-set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-
-static void
-print_header(unsigned int format, const char *chain, struct xtc_handle *handle)
-{
- struct xt_counters counters;
- const char *pol = ip6tc_get_policy(chain, &counters, handle);
- printf("Chain %s", chain);
- if (pol) {
- printf(" (policy %s", pol);
- if (!(format & FMT_NOCOUNTS)) {
- fputc(' ', stdout);
- xtables_print_num(counters.pcnt, (format|FMT_NOTABLE));
- fputs("packets, ", stdout);
- xtables_print_num(counters.bcnt, (format|FMT_NOTABLE));
- fputs("bytes", stdout);
- }
- printf(")\n");
- } else {
- unsigned int refs;
- if (!ip6tc_get_references(&refs, chain, handle))
- printf(" (ERROR obtaining refs)\n");
- else
- printf(" (%u references)\n", refs);
- }
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4s ", "%s "), "num");
- if (!(format & FMT_NOCOUNTS)) {
- if (format & FMT_KILOMEGAGIGA) {
- printf(FMT("%5s ","%s "), "pkts");
- printf(FMT("%5s ","%s "), "bytes");
- } else {
- printf(FMT("%8s ","%s "), "pkts");
- printf(FMT("%10s ","%s "), "bytes");
- }
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ","%s "), "target");
- fputs(" prot ", stdout);
- if (format & FMT_OPTIONS)
- fputs("opt", stdout);
- if (format & FMT_VIA) {
- printf(FMT(" %-6s ","%s "), "in");
- printf(FMT("%-6s ","%s "), "out");
- }
- printf(FMT(" %-19s ","%s "), "source");
- printf(FMT(" %-19s "," %s "), "destination");
- printf("\n");
-}
-
-
static int
print_match(const struct xt_entry_match *m,
const struct ip6t_ip6 *ip,
@@ -444,6 +122,9 @@ print_match(const struct xt_entry_match *m,
printf("%s%s ", match->name, unsupported_rev);
else
printf("%s ", match->name);
+
+ if (match->next == match)
+ free(match);
} else {
if (name[0])
printf("UNKNOWN match `%s' ", name);
@@ -471,33 +152,10 @@ print_firewall(const struct ip6t_entry *fw,
t = ip6t_get_target((struct ip6t_entry *)fw);
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4u ", "%u "), num);
-
- if (!(format & FMT_NOCOUNTS)) {
- xtables_print_num(fw->counters.pcnt, format);
- xtables_print_num(fw->counters.bcnt, format);
- }
-
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ", "%s "), targname);
-
- fputc(fw->ipv6.invflags & XT_INV_PROTO ? '!' : ' ', stdout);
- {
- const char *pname = proto_to_name(fw->ipv6.proto, format&FMT_NUMERIC);
- if (pname)
- printf(FMT("%-5s", "%s "), pname);
- else
- printf(FMT("%-5hu", "%hu "), fw->ipv6.proto);
- }
+ print_rule_details(num, &fw->counters, targname, fw->ipv6.proto,
+ fw->ipv6.flags, fw->ipv6.invflags, format);
- if (format & FMT_OPTIONS) {
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputc(' ', stdout); /* Invert flag of FRAG */
- fputc(' ', stdout); /* -f */
- fputc(' ', stdout);
- }
+ print_fragment(fw->ipv6.flags, fw->ipv6.invflags, format, true);
print_ifaces(fw->ipv6.iniface, fw->ipv6.outiface,
fw->ipv6.invflags, format);
@@ -524,6 +182,9 @@ print_firewall(const struct ip6t_entry *fw,
tg->print(&fw->ipv6, t, format & FMT_NUMERIC);
else if (target->print)
printf(" %s%s", target->name, unsupported_rev);
+
+ if (target->next == target)
+ free(target);
} else if (t->u.target_size != sizeof(*t))
printf("[%u bytes of unknown target data] ",
(unsigned int)(t->u.target_size - sizeof(*t)));
@@ -622,40 +283,6 @@ insert_entry(const xt_chainlabel chain,
return ret;
}
-static unsigned char *
-make_delete_mask(const struct xtables_rule_match *matches,
- const struct xtables_target *target)
-{
- /* Establish mask for comparison */
- unsigned int size;
- const struct xtables_rule_match *matchp;
- unsigned char *mask, *mptr;
-
- size = sizeof(struct ip6t_entry);
- for (matchp = matches; matchp; matchp = matchp->next)
- size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
-
- mask = xtables_calloc(1, size
- + XT_ALIGN(sizeof(struct xt_entry_target))
- + target->size);
-
- memset(mask, 0xFF, sizeof(struct ip6t_entry));
- mptr = mask + sizeof(struct ip6t_entry);
-
- for (matchp = matches; matchp; matchp = matchp->next) {
- memset(mptr, 0xFF,
- XT_ALIGN(sizeof(struct xt_entry_match))
- + matchp->match->userspacesize);
- mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
- }
-
- memset(mptr, 0xFF,
- XT_ALIGN(sizeof(struct xt_entry_target))
- + target->userspacesize);
-
- return mask;
-}
-
static int
delete_entry(const xt_chainlabel chain,
struct ip6t_entry *fw,
@@ -674,7 +301,7 @@ delete_entry(const xt_chainlabel chain,
int ret = 1;
unsigned char *mask;
- mask = make_delete_mask(matches, target);
+ mask = make_delete_mask(matches, target, sizeof(*fw));
for (i = 0; i < nsaddrs; i++) {
fw->ipv6.src = saddrs[i];
fw->ipv6.smsk = smasks[i];
@@ -704,7 +331,7 @@ check_entry(const xt_chainlabel chain, struct ip6t_entry *fw,
int ret = 1;
unsigned char *mask;
- mask = make_delete_mask(matches, target);
+ mask = make_delete_mask(matches, target, sizeof(*fw));
for (i = 0; i < nsaddrs; i++) {
fw->ipv6.src = saddrs[i];
fw->ipv6.smsk = smasks[i];
@@ -827,8 +454,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
if (found) printf("\n");
- if (!rulenum)
- print_header(format, this, handle);
+ if (!rulenum) {
+ struct xt_counters counters;
+ unsigned int urefs;
+ const char *pol;
+ int refs = - 1;
+
+ pol = ip6tc_get_policy(this, &counters, handle);
+ if (!pol && ip6tc_get_references(&urefs, this, handle))
+ refs = urefs;
+
+ print_header(format, this, pol, &counters, refs, 0);
+ }
i = ip6tc_first_rule(this, handle);
num = 0;
@@ -849,109 +486,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
return found;
}
-/* This assumes that mask is contiguous, and byte-bounded. */
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask,
- int invert)
-{
- unsigned int i;
-
- if (mask[0] == 0)
- return;
-
- printf("%s -%c ", invert ? " !" : "", letter);
-
- for (i = 0; i < IFNAMSIZ; i++) {
- if (mask[i] != 0) {
- if (iface[i] != '\0')
- printf("%c", iface[i]);
- } else {
- /* we can access iface[i-1] here, because
- * a few lines above we make sure that mask[0] != 0 */
- if (iface[i-1] != '\0')
- printf("+");
- break;
- }
- }
-}
-
-/* The ip6tables looks up the /etc/protocols. */
-static void print_proto(uint16_t proto, int invert)
-{
- if (proto) {
- unsigned int i;
- const char *invertstr = invert ? " !" : "";
-
- const struct protoent *pent = getprotobynumber(proto);
- if (pent) {
- printf("%s -p %s",
- invertstr, pent->p_name);
- return;
- }
-
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto) {
- printf("%s -p %s",
- invertstr, xtables_chain_protos[i].name);
- return;
- }
-
- printf("%s -p %u", invertstr, proto);
- }
-}
-
-static int print_match_save(const struct xt_entry_match *e,
- const struct ip6t_ip6 *ip)
-{
- const char *name = e->u.user.name;
- const int revision = e->u.user.revision;
- struct xtables_match *match, *mt, *mt2;
-
- match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
- if (match) {
- mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
- match, revision);
- if (!mt2)
- mt2 = match;
- printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
-
- /* some matches don't provide a save function */
- if (mt && mt->save)
- mt->save(ip, e);
- else if (match->save)
- printf(unsupported_rev);
- } else {
- if (e->u.match_size) {
- fprintf(stderr,
- "Can't find library for match `%s'\n",
- name);
- exit(1);
- }
- }
- return 0;
-}
-
-/* Print a given ip including mask if necessary. */
-static void print_ip(const char *prefix, const struct in6_addr *ip,
- const struct in6_addr *mask, int invert)
-{
- char buf[51];
- int l = xtables_ip6mask_to_cidr(mask);
-
- if (l == 0 && !invert)
- return;
-
- printf("%s %s %s",
- invert ? " !" : "",
- prefix,
- inet_ntop(AF_INET6, ip, buf, sizeof buf));
-
- if (l == -1)
- printf("/%s", inet_ntop(AF_INET6, mask, buf, sizeof buf));
- else
- printf("/%d", l);
-}
-
/* We want this to be readable, so only print out necessary fields.
* Because that's the kind of world I want to live in.
*/
@@ -969,19 +503,14 @@ void print_rule6(const struct ip6t_entry *e,
printf("-A %s", chain);
/* Print IP part. */
- print_ip("-s", &(e->ipv6.src), &(e->ipv6.smsk),
- e->ipv6.invflags & IP6T_INV_SRCIP);
-
- print_ip("-d", &(e->ipv6.dst), &(e->ipv6.dmsk),
- e->ipv6.invflags & IP6T_INV_DSTIP);
+ save_ipv6_addr('s', &e->ipv6.src, &e->ipv6.smsk,
+ e->ipv6.invflags & IP6T_INV_SRCIP);
- print_iface('i', e->ipv6.iniface, e->ipv6.iniface_mask,
- e->ipv6.invflags & IP6T_INV_VIA_IN);
+ save_ipv6_addr('d', &e->ipv6.dst, &e->ipv6.dmsk,
+ e->ipv6.invflags & IP6T_INV_DSTIP);
- print_iface('o', e->ipv6.outiface, e->ipv6.outiface_mask,
- e->ipv6.invflags & IP6T_INV_VIA_OUT);
-
- print_proto(e->ipv6.proto, e->ipv6.invflags & XT_INV_PROTO);
+ save_rule_details(e->ipv6.iniface, e->ipv6.outiface,
+ e->ipv6.proto, 0, e->ipv6.invflags);
#if 0
/* not definied in ipv6
@@ -1136,10 +665,27 @@ generate_entry(const struct ip6t_entry *fw,
int do_command6(int argc, char *argv[], char **table,
struct xtc_handle **handle, bool restore)
{
+ struct xt_cmd_parse_ops cmd_parse_ops = {
+ .proto_parse = ipv6_proto_parse,
+ .post_parse = ipv6_post_parse,
+ .option_name = ip46t_option_name,
+ .option_invert = ip46t_option_invert,
+ .command_default = command_default,
+ .print_help = xtables_printhelp,
+ };
+ struct xt_cmd_parse p = {
+ .table = *table,
+ .restore = restore,
+ .line = line,
+ .ops = &cmd_parse_ops,
+ };
struct iptables_command_state cs = {
.jumpto = "",
.argv = argv,
};
+ struct xtables_args args = {
+ .family = AF_INET6,
+ };
struct ip6t_entry *e = NULL;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in6_addr *saddrs = NULL, *daddrs = NULL;
@@ -1147,452 +693,34 @@ int do_command6(int argc, char *argv[], char **table,
int verbose = 0;
int wait = 0;
- struct timeval wait_interval = {
- .tv_sec = 1,
- };
- bool wait_interval_set = false;
const char *chain = NULL;
- const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
const char *policy = NULL, *newname = NULL;
unsigned int rulenum = 0, command = 0;
- const char *pcnt = NULL, *bcnt = NULL;
int ret = 1;
- struct xtables_match *m;
- struct xtables_rule_match *matchp;
- struct xtables_target *t;
- unsigned long long cnt;
- bool table_set = false;
-
- /* re-set optind to 0 in case do_command6 gets called
- * a second time */
- optind = 0;
-
- /* clear mflags in case do_command6 gets called a second time
- * (we clear the global list of all matches for security)*/
- for (m = xtables_matches; m; m = m->next)
- m->mflags = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- opterr = 0;
-
- opts = xt_params->orig_opts;
- while ((cs.c = getopt_long(argc, argv,
- "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvw::W::nt:m:xc:g:46",
- opts, NULL)) != -1) {
- switch (cs.c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&command, CMD_APPEND, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'C':
- add_command(&command, CMD_CHECK, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&command, CMD_REPLACE, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&command, CMD_INSERT, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else rulenum = 1;
- break;
-
- case 'L':
- add_command(&command, CMD_LIST,
- CMD_ZERO | CMD_ZERO_NUM, cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'S':
- add_command(&command, CMD_LIST_RULES,
- CMD_ZERO | CMD_ZERO_NUM, cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'F':
- add_command(&command, CMD_FLUSH, CMD_NONE,
- cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
- cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_ZERO_NUM;
- }
- break;
-
- case 'N':
- parse_chain(optarg);
- add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&command, CMD_SET_POLICY, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
- /* ip6tables -p icmp -h */
- if (!cs.matches && cs.protocol)
- xtables_find_match(cs.protocol, XTF_TRY_LOAD,
- &cs.matches);
-
- exit_printhelp(cs.matches);
-
- /*
- * Option selection
- */
- case 'p':
- set_option(&cs.options, OPT_PROTOCOL, &cs.fw6.ipv6.invflags,
- cs.invert);
-
- /* Canonicalize into lower case */
- for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
- *cs.protocol = tolower(*cs.protocol);
-
- cs.protocol = optarg;
- cs.fw6.ipv6.proto = xtables_parse_protocol(cs.protocol);
- cs.fw6.ipv6.flags |= IP6T_F_PROTO;
-
- if (cs.fw6.ipv6.proto == 0
- && (cs.fw6.ipv6.invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
-
- if (is_exthdr(cs.fw6.ipv6.proto)
- && (cs.fw6.ipv6.invflags & XT_INV_PROTO) == 0)
- fprintf(stderr,
- "Warning: never matched protocol: %s. "
- "use extension match instead.\n",
- cs.protocol);
- break;
-
- case 's':
- set_option(&cs.options, OPT_SOURCE, &cs.fw6.ipv6.invflags,
- cs.invert);
- shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs.options, OPT_DESTINATION, &cs.fw6.ipv6.invflags,
- cs.invert);
- dhostnetworkmask = optarg;
- break;
-
-#ifdef IP6T_F_GOTO
- case 'g':
- set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags,
- cs.invert);
- cs.fw6.ipv6.flags |= IP6T_F_GOTO;
- cs.jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs.options, OPT_JUMP, &cs.fw6.ipv6.invflags,
- cs.invert);
- command_jump(&cs, optarg);
- break;
-
-
- case 'i':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEIN, &cs.fw6.ipv6.invflags,
- cs.invert);
- xtables_parse_interface(optarg,
- cs.fw6.ipv6.iniface,
- cs.fw6.ipv6.iniface_mask);
- break;
-
- case 'o':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw6.ipv6.invflags,
- cs.invert);
- xtables_parse_interface(optarg,
- cs.fw6.ipv6.outiface,
- cs.fw6.ipv6.outiface_mask);
- break;
-
- case 'v':
- if (!verbose)
- set_option(&cs.options, OPT_VERBOSE,
- &cs.fw6.ipv6.invflags, cs.invert);
- verbose++;
- break;
-
- case 'w':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-w' from "
- "ip6tables-restore");
- }
- wait = parse_wait_time(argc, argv);
- break;
-
- case 'W':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-W' from "
- "ip6tables-restore");
- }
- parse_wait_interval(argc, argv, &wait_interval);
- wait_interval_set = true;
- break;
-
- case 'm':
- command_match(&cs);
- break;
-
- case 'n':
- set_option(&cs.options, OPT_NUMERIC, &cs.fw6.ipv6.invflags,
- cs.invert);
- break;
-
- case 't':
- if (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- if (restore && table_set)
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- *table = optarg;
- table_set = true;
- break;
-
- case 'x':
- set_option(&cs.options, OPT_EXPANDED, &cs.fw6.ipv6.invflags,
- cs.invert);
- break;
-
- case 'V':
- if (cs.invert)
- printf("Not %s ;-)\n", prog_vers);
- else
- printf("%s v%s (legacy)\n",
- prog_name, prog_vers);
- exit(0);
-
- case '0':
- set_option(&cs.options, OPT_LINENUMBERS, &cs.fw6.ipv6.invflags,
- cs.invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
-
- set_option(&cs.options, OPT_COUNTERS, &cs.fw6.ipv6.invflags,
- cs.invert);
- pcnt = optarg;
- bcnt = strchr(pcnt + 1, ',');
- if (bcnt)
- bcnt++;
- if (!bcnt && xs_has_arg(argc, argv))
- bcnt = argv[optind++];
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(pcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw6.counters.pcnt = cnt;
-
- if (sscanf(bcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw6.counters.bcnt = cnt;
- break;
-
- case '4':
- /* This is not the IPv4 iptables */
- if (line != -1)
- return 1; /* success: line ignored */
- fprintf(stderr, "This is the IPv6 version of ip6tables.\n");
- exit_tryhelp(2);
-
- case '6':
- /* This is indeed the IPv6 ip6tables */
- break;
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- cs.invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(&cs, &ip6tables_globals) == 1)
- /*
- * If new options were loaded, we must retry
- * getopt immediately and not allow
- * cs.invert=false to be executed.
- */
- continue;
- break;
- }
- cs.invert = false;
- }
-
- if (!wait && wait_interval_set)
- xtables_error(PARAMETER_PROBLEM,
- "--wait-interval only makes sense with --wait\n");
-
- if (strcmp(*table, "nat") == 0 &&
- ((policy != NULL && strcmp(policy, "DROP") == 0) ||
- (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
- xtables_error(PARAMETER_PROBLEM,
- "\nThe \"nat\" table is not intended for filtering, "
- "the use of DROP is therefore inhibited.\n\n");
-
- for (matchp = cs.matches; matchp; matchp = matchp->next)
- xtables_option_mfcall(matchp->match);
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
-
- /* Fix me: must put inverse options checking here --MN */
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (!command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
- if (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs.options & OPT_DESTINATION))
- dhostnetworkmask = "::0/0";
- if (!(cs.options & OPT_SOURCE))
- shostnetworkmask = "::0/0";
- }
-
- if (shostnetworkmask)
- xtables_ip6parse_multiple(shostnetworkmask, &saddrs,
- &smasks, &nsaddrs);
-
- if (dhostnetworkmask)
- xtables_ip6parse_multiple(dhostnetworkmask, &daddrs,
- &dmasks, &ndaddrs);
-
- if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
- " source or destination IP addresses");
-
- if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- generic_opt_check(command, cs.options);
+ do_parse(argc, argv, &p, &cs, &args);
+
+ command = p.command;
+ chain = p.chain;
+ *table = p.table;
+ rulenum = p.rulenum;
+ policy = p.policy;
+ newname = p.newname;
+ verbose = p.verbose;
+ wait = args.wait;
+ nsaddrs = args.s.naddrs;
+ ndaddrs = args.d.naddrs;
+ saddrs = args.s.addr.v6;
+ daddrs = args.d.addr.v6;
+ smasks = args.s.mask.v6;
+ dmasks = args.d.mask.v6;
+
+ iface_to_mask(cs.fw6.ipv6.iniface, cs.fw6.ipv6.iniface_mask);
+ iface_to_mask(cs.fw6.ipv6.outiface, cs.fw6.ipv6.outiface_mask);
/* Attempt to acquire the xtables lock */
if (!restore)
- xtables_lock_or_exit(wait, &wait_interval);
+ xtables_lock_or_exit(wait);
/* only allocate handle if we weren't called with a handle */
if (!*handle)
@@ -1612,26 +740,6 @@ int do_command6(int argc, char *argv[], char **table,
|| command == CMD_CHECK
|| command == CMD_INSERT
|| command == CMD_REPLACE) {
- if (strcmp(chain, "PREROUTING") == 0
- || strcmp(chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (cs.options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- chain);
- }
-
- if (strcmp(chain, "POSTROUTING") == 0
- || strcmp(chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (cs.options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- chain);
- }
-
if (cs.target && ip6tc_is_chain(cs.jumpto, *handle)) {
fprintf(stderr,
"Warning: using chain %s, not extension\n",
@@ -1670,13 +778,12 @@ int do_command6(int argc, char *argv[], char **table,
#ifdef IP6T_F_GOTO
if (cs.fw6.ipv6.flags & IP6T_F_GOTO)
xtables_error(PARAMETER_PROBLEM,
- "goto '%s' is not a chain\n",
- cs.jumpto);
+ "goto '%s' is not a chain",
+ cs.jumpto);
#endif
xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED);
} else {
e = generate_entry(&cs.fw6, cs.matches, cs.target->t);
- free(cs.target->t);
}
}
@@ -1767,25 +874,25 @@ int do_command6(int argc, char *argv[], char **table,
case CMD_SET_POLICY:
ret = ip6tc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw6.counters : NULL, *handle);
break;
+ case CMD_NONE:
+ /* do_parse ignored the line (eg: -4 with ip6tables-restore) */
+ break;
default:
/* We should never reach this... */
- exit_tryhelp(2);
+ exit_tryhelp(2, line);
}
if (verbose > 1)
dump_entries6(*handle);
- xtables_rule_matches_free(&cs.matches);
+ xtables_clear_iptables_command_state(&cs);
if (e != NULL) {
free(e);
e = NULL;
}
- free(saddrs);
- free(smasks);
- free(daddrs);
- free(dmasks);
+ xtables_clear_args(&args);
xtables_free_opts(1);
return ret;
diff --git a/iptables/iptables-apply b/iptables/iptables-apply
index 4683b1b4..c603fb21 100755
--- a/iptables/iptables-apply
+++ b/iptables/iptables-apply
@@ -141,9 +141,9 @@ for opt in $OPTS; do
;;
(*)
case "${OPT_STATE:-}" in
- (SET_TIMEOUT) eval TIMEOUT=$opt;;
+ (SET_TIMEOUT) eval TIMEOUT="$opt";;
(SET_SAVEFILE)
- eval SAVEFILE=$opt
+ eval SAVEFILE="$opt"
[ -z "$SAVEFILE" ] && SAVEFILE="$DEF_SAVEFILE"
;;
esac
@@ -163,13 +163,13 @@ done
# Validate parameters
if [ "$TIMEOUT" -ge 0 ] 2>/dev/null; then
- TIMEOUT=$(($TIMEOUT))
+ TIMEOUT=$((TIMEOUT))
else
echo "Error: timeout must be a positive number" >&2
exit 1
fi
-if [ -n "$SAVEFILE" -a -e "$SAVEFILE" -a ! -w "$SAVEFILE" ]; then
+if [ -n "$SAVEFILE" ] && [ -e "$SAVEFILE" ] && [ ! -w "$SAVEFILE" ]; then
echo "Error: savefile not writable: $SAVEFILE" >&2
exit 8
fi
@@ -205,8 +205,8 @@ esac
### Begin work
# Store old iptables rules to temporary file
-TMPFILE=`mktemp /tmp/$PROGNAME-XXXXXXXX`
-trap "rm -f $TMPFILE" EXIT HUP INT QUIT ILL TRAP ABRT BUS \
+TMPFILE=$(mktemp "/tmp/$PROGNAME-XXXXXXXX")
+trap 'rm -f $TMPFILE' EXIT HUP INT QUIT ILL TRAP ABRT BUS \
FPE USR1 SEGV USR2 PIPE ALRM TERM
if ! "$SAVE" >"$TMPFILE"; then
@@ -231,7 +231,6 @@ case "$MODE" in
"$RUNCMD" &
CMD_PID=$!
( sleep "$TIMEOUT"; kill "$CMD_PID" 2>/dev/null; exit 0 ) &
- CMDTIMEOUT_PID=$!
if ! wait "$CMD_PID"; then
echo "failed."
echo "Error: unknown error running command: $RUNCMD" >&2
@@ -258,13 +257,13 @@ esac
# Prompt user for confirmation
echo -n "Can you establish NEW connections to the machine? (y/N) "
-read -n1 -t "$TIMEOUT" ret 2>&1 || :
+read -r -n1 -t "$TIMEOUT" ret 2>&1 || :
case "${ret:-}" in
(y*|Y*)
# Success
echo
- if [ ! -z "$SAVEFILE" ]; then
+ if [ -n "$SAVEFILE" ]; then
# Write successfully applied rules to the savefile
echo "Writing successfully applied rules to '$SAVEFILE'..."
if ! "$SAVE" >"$SAVEFILE"; then
diff --git a/iptables/iptables-apply.8.in b/iptables/iptables-apply.8.in
index f0ed4e5f..33fd79fe 100644
--- a/iptables/iptables-apply.8.in
+++ b/iptables/iptables-apply.8.in
@@ -3,10 +3,8 @@
.\" Date: May 10, 2010
.\"
.TH IPTABLES\-APPLY 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@"
-.\" disable hyphenation
-.nh
.SH NAME
-iptables-apply \- a safer way to update iptables remotely
+iptables-apply \(em a safer way to update iptables remotely
.SH SYNOPSIS
\fBiptables\-apply\fP [\-\fBhV\fP] [\fB-t\fP \fItimeout\fP] [\fB-w\fP \fIsavefile\fP] {[\fIrulesfile]|-c [runcmd]}\fP
.SH "DESCRIPTION"
diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in
index b4b62f92..aa816f79 100644
--- a/iptables/iptables-restore.8.in
+++ b/iptables/iptables-restore.8.in
@@ -23,13 +23,13 @@ iptables-restore \(em Restore IP Tables
.P
ip6tables-restore \(em Restore IPv6 Tables
.SH SYNOPSIS
-\fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIsecs\fP]
-[\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP]
-[\fBfile\fP]
+\fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP]
+[\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP]
+[\fIfile\fP]
.P
-\fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIsecs\fP]
-[\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP]
-[\fBfile\fP]
+\fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIseconds\fP]
+[\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP]
+[\fIfile\fP]
.SH DESCRIPTION
.PP
.B iptables-restore
@@ -40,13 +40,13 @@ are used to restore IP and IPv6 Tables from data specified on STDIN or in
specify \fIfile\fP as an argument.
.TP
\fB\-c\fR, \fB\-\-counters\fR
-restore the values of all packet and byte counters
+Restore the values of all packet and byte counters.
.TP
\fB\-h\fP, \fB\-\-help\fP
Print a short option summary.
.TP
\fB\-n\fR, \fB\-\-noflush\fR
-don't flush the previous contents of the table. If not specified,
+Don't flush the previous contents of the table. If not specified,
both commands flush (delete) all previous contents of the respective table.
.TP
\fB\-t\fP, \fB\-\-test\fP
@@ -54,6 +54,7 @@ Only parse and construct the ruleset, but do not commit it.
.TP
\fB\-v\fP, \fB\-\-verbose\fP
Print additional debug info during ruleset processing.
+Specify multiple times to increase debug level.
.TP
\fB\-V\fP, \fB\-\-version\fP
Print the program version number.
@@ -66,16 +67,10 @@ the program will exit if the lock cannot be obtained. This option will
make the program wait (indefinitely or for optional \fIseconds\fP) until
the exclusive lock can be obtained.
.TP
-\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP
-Interval to wait per each iteration.
-When running latency sensitive applications, waiting for the xtables lock
-for extended durations may not be acceptable. This option will make each
-iteration take the amount of time specified. The default interval is
-1 second. This option only works with \fB\-w\fP.
-.TP
-\fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe_program\fP
-Specify the path to the modprobe program. By default, iptables-restore will
-inspect /proc/sys/kernel/modprobe to determine the executable's path.
+\fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe\fP
+Specify the path to the modprobe(8) program. By default,
+iptables-restore will inspect \fI/proc/sys/kernel/modprobe\fP to
+determine the executable's path.
.TP
\fB\-T\fP, \fB\-\-table\fP \fIname\fP
Restore only the named table even if the input stream contains other ones.
@@ -87,7 +82,7 @@ from Rusty Russell.
.br
Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-restore.
.SH SEE ALSO
-\fBiptables\-apply\fP(8),\fBiptables\-save\fP(8), \fBiptables\fP(8)
+\fBiptables\-apply\fP(8), \fBiptables\-save\fP(8), \fBiptables\fP(8)
.PP
The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO,
which details NAT, and the netfilter-hacking-HOWTO which details the
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index cc2c2b8b..53029738 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -22,10 +22,6 @@
static int counters, verbose, noflush, wait;
-static struct timeval wait_interval = {
- .tv_sec = 1,
-};
-
/* Keeping track of external matches and targets. */
static const struct option options[] = {
{.name = "counters", .has_arg = 0, .val = 'c'},
@@ -51,7 +47,6 @@ static void print_usage(const char *name, const char *version)
" [ --help ]\n"
" [ --noflush ]\n"
" [ --wait=<seconds>\n"
- " [ --wait-interval=<usecs>\n"
" [ --table=<TABLE> ]\n"
" [ --modprobe=<command> ]\n", name);
}
@@ -83,8 +78,9 @@ create_handle(const struct iptables_restore_cb *cb, const char *tablename)
}
if (!handle)
- xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize "
- "table '%s'\n", xt_params->program_name, tablename);
+ xtables_error(PARAMETER_PROBLEM,
+ "%s: unable to initialize table '%s'",
+ xt_params->program_name, tablename);
return handle;
}
@@ -101,6 +97,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
FILE *in;
int in_table = 0, testing = 0;
const char *tablename = NULL;
+ bool wait_interval_set = false;
line = 0;
lock = XT_LOCK_NOT_ACQUIRED;
@@ -114,10 +111,10 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
counters = 1;
break;
case 'v':
- verbose = 1;
+ verbose++;
break;
case 'V':
- printf("%s v%s (legacy)\n",
+ printf("%s v%s\n",
xt_params->program_name,
xt_params->program_version);
exit(0);
@@ -135,7 +132,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
wait = parse_wait_time(argc, argv);
break;
case 'W':
- parse_wait_interval(argc, argv, &wait_interval);
+ parse_wait_interval(argc, argv);
+ wait_interval_set = true;
break;
case 'M':
xtables_modprobe_program = optarg;
@@ -165,7 +163,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
}
else in = stdin;
- if (!wait_interval.tv_sec && !wait) {
+ if (wait_interval_set && !wait) {
fprintf(stderr, "Option --wait-interval requires option --wait\n");
exit(1);
}
@@ -187,12 +185,12 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
if (!testing) {
DEBUGP("Calling commit\n");
ret = cb->ops->commit(handle);
- cb->ops->free(handle);
- handle = NULL;
} else {
DEBUGP("Not calling commit, testing\n");
ret = 1;
}
+ cb->ops->free(handle);
+ handle = NULL;
/* Done with the current table, release the lock. */
if (lock >= 0) {
@@ -203,7 +201,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
in_table = 0;
} else if ((buffer[0] == '*') && (!in_table)) {
/* Acquire a lock before we create a new table handle */
- lock = xtables_lock_or_exit(wait, &wait_interval);
+ lock = xtables_lock_or_exit(wait);
/* New table */
char *table;
@@ -212,8 +210,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
DEBUGP("line %u, table '%s'\n", line, table);
if (!table)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u table name invalid\n",
- xt_params->program_name, line);
+ "%s: line %u table name invalid",
+ xt_params->program_name, line);
strncpy(curtable, table, XT_TABLE_MAXNAMELEN);
curtable[XT_TABLE_MAXNAMELEN] = '\0';
@@ -225,8 +223,6 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
}
continue;
}
- if (handle)
- cb->ops->free(handle);
handle = create_handle(cb, table);
if (noflush == 0) {
@@ -252,8 +248,8 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
DEBUGP("line %u, chain '%s'\n", line, chain);
if (!chain)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u chain name invalid\n",
- xt_params->program_name, line);
+ "%s: line %u chain name invalid",
+ xt_params->program_name, line);
if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -266,16 +262,14 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
DEBUGP("Flushing existing user defined chain '%s'\n", chain);
if (!cb->ops->flush_entries(chain, handle))
xtables_error(PARAMETER_PROBLEM,
- "error flushing chain "
- "'%s':%s\n", chain,
- strerror(errno));
+ "error flushing chain '%s':%s",
+ chain, strerror(errno));
} else {
DEBUGP("Creating new chain '%s'\n", chain);
if (!cb->ops->create_chain(chain, handle))
xtables_error(PARAMETER_PROBLEM,
- "error creating chain "
- "'%s':%s\n", chain,
- strerror(errno));
+ "error creating chain '%s':%s",
+ chain, strerror(errno));
}
}
@@ -283,45 +277,47 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
DEBUGP("line %u, policy '%s'\n", line, policy);
if (!policy)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u policy invalid\n",
- xt_params->program_name, line);
+ "%s: line %u policy invalid",
+ xt_params->program_name, line);
if (strcmp(policy, "-") != 0) {
+ char *ctrs = strtok(NULL, " \t\n");
struct xt_counters count = {};
- if (counters) {
- char *ctrs;
- ctrs = strtok(NULL, " \t\n");
-
- if (!ctrs || !parse_counters(ctrs, &count))
- xtables_error(PARAMETER_PROBLEM,
- "invalid policy counters "
- "for chain '%s'\n", chain);
- }
+ if ((!ctrs && counters) ||
+ (ctrs && !parse_counters(ctrs, &count)))
+ xtables_error(PARAMETER_PROBLEM,
+ "invalid policy counters for chain '%s'",
+ chain);
DEBUGP("Setting policy of chain %s to %s\n",
chain, policy);
- if (!cb->ops->set_policy(chain, policy, &count,
- handle))
+ if (!cb->ops->set_policy(chain, policy,
+ counters ? &count : NULL,
+ handle))
xtables_error(OTHER_PROBLEM,
- "Can't set policy `%s'"
- " on `%s' line %u: %s\n",
- policy, chain, line,
- cb->ops->strerror(errno));
+ "Can't set policy `%s' on `%s' line %u: %s",
+ policy, chain, line,
+ cb->ops->strerror(errno));
}
+ xtables_announce_chain(chain);
ret = 1;
} else if (in_table) {
char *pcnt = NULL;
char *bcnt = NULL;
char *parsestart = buffer;
+ int i;
add_argv(&av_store, argv[0], 0);
add_argv(&av_store, "-t", 0);
add_argv(&av_store, curtable, 0);
+ for (i = 0; !noflush && i < verbose; i++)
+ add_argv(&av_store, "-v", 0);
+
tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
if (counters && pcnt && bcnt) {
add_argv(&av_store, "--set-counters", 0);
@@ -382,10 +378,8 @@ iptables_restore_main(int argc, char *argv[])
iptables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
ret = ip46tables_restore_main(&ipt_restore_cb, argc, argv);
@@ -416,10 +410,8 @@ ip6tables_restore_main(int argc, char *argv[])
ip6tables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions6();
-#endif
ret = ip46tables_restore_main(&ip6t_restore_cb, argc, argv);
diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in
index 7683fd37..65c1f28c 100644
--- a/iptables/iptables-save.8.in
+++ b/iptables/iptables-save.8.in
@@ -36,23 +36,27 @@ and
are used to dump the contents of IP or IPv6 Table in easily parseable format
either to STDOUT or to a specified file.
.TP
-\fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe_program\fP
-Specify the path to the modprobe program. By default, iptables-save will
-inspect /proc/sys/kernel/modprobe to determine the executable's path.
+\fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe\fP
+Specify the path to the modprobe(8) program. By default,
+iptables-save will inspect \fI/proc/sys/kernel/modprobe\fP to determine
+the executable's path.
.TP
\fB\-f\fR, \fB\-\-file\fR \fIfilename\fP
Specify a filename to log the output to. If not specified, iptables-save
will log to STDOUT.
.TP
\fB\-c\fR, \fB\-\-counters\fR
-include the current values of all packet and byte counters in the output
+Include the current values of all packet and byte counters in the output.
.TP
\fB\-t\fR, \fB\-\-table\fR \fItablename\fP
-restrict output to only one table. If the kernel is configured with automatic
+Restrict output to only one table. If the kernel is configured with automatic
module loading, an attempt will be made to load the appropriate module for
that table if it is not already there.
.br
-If not specified, output includes all available tables.
+If not specified, output includes all available tables. No module loading takes
+place, so in order to include a specific table in the output, the respective
+module (something like \fBiptable_mangle\fP or \fBip6table_raw\fP) must be
+loaded first.
.SH BUGS
None known as of iptables-1.2.1 release
.SH AUTHORS
@@ -62,7 +66,7 @@ Rusty Russell <rusty@rustcorp.com.au>
.br
Andras Kis-Szabo <kisza@sch.bme.hu> contributed ip6tables-save.
.SH SEE ALSO
-\fBiptables\-apply\fP(8),\fBiptables\-restore\fP(8), \fBiptables\fP(8)
+\fBiptables\-apply\fP(8), \fBiptables\-restore\fP(8), \fBiptables\fP(8)
.PP
The iptables-HOWTO, which details more iptables usage, the NAT-HOWTO,
which details NAT, and the netfilter-hacking-HOWTO which details the
diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c
index 4efd6667..094adf22 100644
--- a/iptables/iptables-save.c
+++ b/iptables/iptables-save.c
@@ -61,8 +61,7 @@ for_each_table(int (*func)(struct iptables_save_cb *cb, const char *tablename),
while (fgets(tablename, sizeof(tablename), procfile)) {
if (tablename[strlen(tablename) - 1] != '\n')
xtables_error(OTHER_PROBLEM,
- "Badly formed tablename `%s'\n",
- tablename);
+ "Badly formed tablename `%s'", tablename);
tablename[strlen(tablename) - 1] = '\0';
ret &= func(cb, tablename);
}
@@ -85,7 +84,7 @@ static int do_output(struct iptables_save_cb *cb, const char *tablename)
h = cb->ops->init(tablename);
}
if (!h)
- xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n",
+ xtables_error(OTHER_PROBLEM, "Cannot initialize: %s",
cb->ops->strerror(errno));
time_t now = time(NULL);
@@ -173,7 +172,7 @@ do_iptables_save(struct iptables_save_cb *cb, int argc, char *argv[])
do_output(cb, tablename);
exit(0);
case 'V':
- printf("%s v%s (legacy)\n",
+ printf("%s v%s\n",
xt_params->program_name,
xt_params->program_version);
exit(0);
@@ -227,10 +226,8 @@ iptables_save_main(int argc, char *argv[])
iptables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
ret = do_iptables_save(&ipt_save_cb, argc, argv);
@@ -273,10 +270,8 @@ ip6tables_save_main(int argc, char *argv[])
ip6tables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions6();
-#endif
ret = do_iptables_save(&ip6t_save_cb, argc, argv);
diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c
index 8c67ea4d..0f263f6f 100644
--- a/iptables/iptables-standalone.c
+++ b/iptables/iptables-standalone.c
@@ -53,10 +53,8 @@ iptables_main(int argc, char *argv[])
iptables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
ret = do_command4(argc, argv, &table, &handle, false);
if (ret) {
diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c
index 98d03dda..396c0a12 100644
--- a/iptables/iptables-xml.c
+++ b/iptables/iptables-xml.c
@@ -210,11 +210,11 @@ saveChain(char *chain, char *policy, struct xt_counters *ctr)
{
if (nextChain >= maxChains)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u chain name invalid\n",
- prog_name, line);
+ "%s: line %u chain name invalid",
+ prog_name, line);
- chains[nextChain].chain = strdup(chain);
- chains[nextChain].policy = strdup(policy);
+ chains[nextChain].chain = xtables_strdup(chain);
+ chains[nextChain].policy = xtables_strdup(policy);
chains[nextChain].count = *ctr;
chains[nextChain].created = 0;
nextChain++;
@@ -225,13 +225,13 @@ finishChains(void)
{
int c;
- for (c = 0; c < nextChain; c++)
- if (!chains[c].created) {
+ for (c = 0; c < nextChain; c++) {
+ if (!chains[c].created)
openChain(chains[c].chain, chains[c].policy,
&(chains[c].count), '/');
- free(chains[c].chain);
- free(chains[c].policy);
- }
+ free(chains[c].chain);
+ free(chains[c].policy);
+ }
nextChain = 0;
}
@@ -610,8 +610,8 @@ iptables_xml_main(int argc, char *argv[])
DEBUGP("line %u, table '%s'\n", line, table);
if (!table)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u table name invalid\n",
- prog_name, line);
+ "%s: line %u table name invalid",
+ prog_name, line);
openTable(table);
@@ -626,8 +626,8 @@ iptables_xml_main(int argc, char *argv[])
DEBUGP("line %u, chain '%s'\n", line, chain);
if (!chain)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u chain name invalid\n",
- prog_name, line);
+ "%s: line %u chain name invalid",
+ prog_name, line);
DEBUGP("Creating new chain '%s'\n", chain);
@@ -635,8 +635,8 @@ iptables_xml_main(int argc, char *argv[])
DEBUGP("line %u, policy '%s'\n", line, policy);
if (!policy)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u policy invalid\n",
- prog_name, line);
+ "%s: line %u policy invalid",
+ prog_name, line);
ctrs = strtok(NULL, " \t\n");
parse_counters(ctrs, &count);
diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in
index 999cf339..21fb891d 100644
--- a/iptables/iptables.8.in
+++ b/iptables/iptables.8.in
@@ -25,10 +25,10 @@
.SH NAME
iptables/ip6tables \(em administration tool for IPv4/IPv6 packet filtering and NAT
.SH SYNOPSIS
-\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP}
+\fBiptables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP}
\fIchain\fP \fIrule-specification\fP
.P
-\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP}
+\fBip6tables\fP [\fB\-t\fP \fItable\fP] {\fB\-A\fP|\fB\-C\fP|\fB\-D\fP|\fB-V\fP}
\fIchain rule-specification\fP
.PP
\fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-I\fP \fIchain\fP [\fIrulenum\fP] \fIrule-specification\fP
@@ -45,15 +45,15 @@ iptables/ip6tables \(em administration tool for IPv4/IPv6 packet filtering and N
.PP
\fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-X\fP [\fIchain\fP]
.PP
-\fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-P\fP \fIchain target\fP
+\fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-P\fP \fIchain policy\fP
.PP
\fBiptables\fP [\fB\-t\fP \fItable\fP] \fB\-E\fP \fIold-chain-name new-chain-name\fP
.PP
-rule-specification = [\fImatches...\fP] [\fItarget\fP]
+rule-specification := [matches...] [target]
.PP
-match = \fB\-m\fP \fImatchname\fP [\fIper-match-options\fP]
+match := \fB\-m\fP \fImatchname\fP [per-match-options]
.PP
-target = \fB\-j\fP \fItargetname\fP [\fIper\-target\-options\fP]
+target := \fB\-j\fP \fItargetname\fP [per-target-options]
.SH DESCRIPTION
\fBIptables\fP and \fBip6tables\fP are used to set up, maintain, and inspect the
tables of IPv4 and IPv6 packet
@@ -125,8 +125,8 @@ This table is used mainly for configuring exemptions from connection
tracking in combination with the NOTRACK target. It registers at the netfilter
hooks with higher priority and is thus called before ip_conntrack, or any other
IP tables. It provides the following built-in chains: \fBPREROUTING\fP
-(for packets arriving via any network interface) \fBOUTPUT\fP
-(for packets generated by local processes)
+(for packets arriving via any network interface) and \fBOUTPUT\fP
+(for packets generated by local processes).
.TP
\fBsecurity\fP:
This table is used for Mandatory Access Control (MAC) networking rules, such
@@ -220,11 +220,11 @@ Create a new user-defined chain by the given name. There must be no
target of that name already.
.TP
\fB\-X\fP, \fB\-\-delete\-chain\fP [\fIchain\fP]
-Delete the optional user-defined chain specified. There must be no references
+Delete the chain specified. There must be no references
to the chain. If there are, you must delete or replace the referring rules
before the chain can be deleted. The chain must be empty, i.e. not contain
-any rules. If no argument is given, it will attempt to delete every
-non-builtin chain in the table.
+any rules. If no argument is given, it will delete all empty chains in the
+table. Empty builtin chains can only be deleted with \fBiptables-nft\fP.
.TP
\fB\-P\fP, \fB\-\-policy\fP \fIchain target\fP
Set the policy for the built-in (non-user-defined) chain to the given target.
@@ -244,13 +244,13 @@ add, delete, insert, replace and append commands).
\fB\-4\fP, \fB\-\-ipv4\fP
This option has no effect in iptables and iptables-restore.
If a rule using the \fB\-4\fP option is inserted with (and only with)
-ip6tables-restore, it will be silently ignored. Any other uses will throw an
+\fBip6tables\-restore\fP, it will be silently ignored. Any other uses will throw an
error. This option allows IPv4 and IPv6 rules in a single rule file
for use with both iptables-restore and ip6tables-restore.
.TP
\fB\-6\fP, \fB\-\-ipv6\fP
If a rule using the \fB\-6\fP option is inserted with (and only with)
-iptables-restore, it will be silently ignored. Any other uses will throw an
+\fBiptables\-restore\fP, it will be silently ignored. Any other uses will throw an
error. This option allows IPv4 and IPv6 rules in a single rule file
for use with both iptables-restore and ip6tables-restore.
This option has no effect in ip6tables and ip6tables-restore.
@@ -258,9 +258,9 @@ This option has no effect in ip6tables and ip6tables-restore.
[\fB!\fP] \fB\-p\fP, \fB\-\-protocol\fP \fIprotocol\fP
The protocol of the rule or of the packet to check.
The specified protocol can be one of \fBtcp\fP, \fBudp\fP, \fBudplite\fP,
-\fBicmp\fP, \fBicmpv6\fP,\fBesp\fP, \fBah\fP, \fBsctp\fP, \fBmh\fP or the special keyword "\fBall\fP",
+\fBicmp\fP, \fBicmpv6\fP, \fBesp\fP, \fBah\fP, \fBsctp\fP, \fBmh\fP or the special keyword "\fBall\fP",
or it can be a numeric value, representing one of these protocols or a
-different one. A protocol name from /etc/protocols is also allowed.
+different one. A protocol name from \fI/etc/protocols\fP is also allowed.
A "!" argument before the protocol inverts the
test. The number zero is equivalent to \fBall\fP. "\fBall\fP"
will match with all protocols and is taken as default when this
@@ -307,8 +307,8 @@ false, evaluation will stop.
This specifies the target of the rule; i.e., what to do if the packet
matches it. The target can be a user-defined chain (other than the
one this rule is in), one of the special builtin targets which decide
-the fate of the packet immediately, or an extension (see \fBEXTENSIONS\fP
-below). If this
+the fate of the packet immediately, or an extension (see \fBMATCH AND TARGET
+EXTENSIONS\fP below). If this
option is omitted in a rule (and \fB\-g\fP
is not used), then matching the rule will have no
effect on the packet's fate, but the counters on the rule will be
@@ -316,7 +316,7 @@ incremented.
.TP
\fB\-g\fP, \fB\-\-goto\fP \fIchain\fP
This specifies that the processing should continue in a user
-specified chain. Unlike the \-\-jump option return will not continue
+specified chain. Unlike with the \-\-jump option, \fBRETURN\fP will not continue
processing in this chain but instead in the chain that called us via
\-\-jump.
.TP
@@ -360,7 +360,14 @@ byte counters are also listed, with the suffix 'K', 'M' or 'G' for
the \fB\-x\fP flag to change this).
For appending, insertion, deletion and replacement, this causes
detailed information on the rule or rules to be printed. \fB\-v\fP may be
-specified multiple times to possibly emit more detailed debug statements.
+specified multiple times to possibly emit more detailed debug statements:
+Specified twice, \fBiptables-legacy\fP will dump table info and entries in
+libiptc, \fBiptables-nft\fP dumps rules in netlink (VM code) presentation.
+Specified three times, \fBiptables-nft\fP will also dump any netlink messages
+sent to kernel.
+.TP
+\fB\-V\fP, \fB\-\-version\fP
+Show program version and the kernel API used.
.TP
\fB\-w\fP, \fB\-\-wait\fP [\fIseconds\fP]
Wait for the xtables lock.
@@ -370,13 +377,6 @@ the program will exit if the lock cannot be obtained. This option will
make the program wait (indefinitely or for optional \fIseconds\fP) until
the exclusive lock can be obtained.
.TP
-\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP
-Interval to wait per each iteration.
-When running latency sensitive applications, waiting for the xtables lock
-for extended durations may not be acceptable. This option will make each
-iteration take the amount of time specified. The default interval is
-1 second. This option only works with \fB\-w\fP.
-.TP
\fB\-n\fP, \fB\-\-numeric\fP
Numeric output.
IP addresses and port numbers will be printed in numeric format.
@@ -386,7 +386,7 @@ network names, or services (whenever applicable).
\fB\-x\fP, \fB\-\-exact\fP
Expand numbers.
Display the exact value of the packet and byte counters,
-instead of only the rounded number in K's (multiples of 1000)
+instead of only the rounded number in K's (multiples of 1000),
M's (multiples of 1000K) or G's (multiples of 1000M). This option is
only relevant for the \fB\-L\fP command.
.TP
@@ -410,13 +410,21 @@ the default setting.
iptables can use extended packet matching and target modules.
A list of these is available in the \fBiptables\-extensions\fP(8) manpage.
.SH DIAGNOSTICS
-Various error messages are printed to standard error. The exit code
-is 0 for correct functioning. Errors which appear to be caused by
-invalid or abused command line parameters cause an exit code of 2, and
+Various error messages are printed to standard error. The exit code is 0 for
+correct functioning. Errors which appear to be caused by invalid or abused
+command line parameters cause an exit code of 2. Errors which indicate an
+incompatibility between kernel and user space cause an exit code of 3. Errors
+which indicate a resource problem, such as a busy lock, failing memory
+allocation or error messages from kernel cause an exit code of 4. Finally,
other errors cause an exit code of 1.
.SH BUGS
Bugs? What's this? ;-)
-Well, you might want to have a look at http://bugzilla.netfilter.org/
+Well, you might want to have a look at https://bugzilla.netfilter.org/
+\fBiptables\fP will exit immediately with an error code of 111 if it finds
+that it was called as a setuid-to-root program.
+iptables cannot be used safely in this manner because it trusts
+the shared libraries (matches, targets) loaded at run time, the search
+path can be set using environment variables.
.SH COMPATIBILITY WITH IPCHAINS
This \fBiptables\fP
is very similar to ipchains by Rusty Russell. The main difference is
@@ -433,7 +441,7 @@ entering the \fBFORWARD\fP chain.
.PP
The various forms of NAT have been separated out; \fBiptables\fP
is a pure packet filter when using the default `filter' table, with
-optional extension modules. This should simplify much of the previous
+optional extension modules. This should avoid much of the
confusion over the combination of IP masquerading and packet filtering
seen previously. So the following options are handled differently:
.nf
@@ -455,7 +463,7 @@ not in the standard distribution,
and the netfilter-hacking-HOWTO details the netfilter internals.
.br
See
-.BR "http://www.netfilter.org/" .
+.BR "https://www.netfilter.org/" .
.SH AUTHORS
Rusty Russell originally wrote iptables, in early consultation with Michael
Neuling.
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 88ef6cf6..8eb043e9 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[] = {
@@ -89,225 +84,13 @@ static struct option original_opts[] = {
{NULL},
};
-void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
-
struct xtables_globals iptables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (legacy)",
.orig_opts = original_opts,
- .exit_err = iptables_exit_error,
.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,
-/* -s */ IPT_INV_SRCIP,
-/* -d */ IPT_INV_DSTIP,
-/* -p */ XT_INV_PROTO,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ IPT_INV_VIA_IN,
-/* -o */ IPT_INV_VIA_OUT,
-/*--line*/ 0,
-/* -c */ 0,
-/* -f */ IPT_INV_FRAG,
-};
-
-#define opts iptables_globals.opts
-#define prog_name iptables_globals.program_name
-#define prog_vers iptables_globals.program_version
-
-static void __attribute__((noreturn))
-exit_tryhelp(int status)
-{
- if (line != -1)
- fprintf(stderr, "Error occurred at line: %d\n", line);
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- prog_name, prog_name);
- xtables_free_opts(1);
- exit(status);
-}
-
-static void
-exit_printhelp(const struct xtables_rule_match *matches)
-{
- printf("%s v%s\n\n"
-"Usage: %s -[ACD] chain rule-specification [options]\n"
-" %s -I chain [rulenum] rule-specification [options]\n"
-" %s -R chain rulenum rule-specification [options]\n"
-" %s -D chain rulenum [options]\n"
-" %s -[LS] [chain [rulenum]] [options]\n"
-" %s -[FZ] [chain] [options]\n"
-" %s -[NX] chain\n"
-" %s -E old-chain-name new-chain-name\n"
-" %s -P chain target [options]\n"
-" %s -h (print this help information)\n\n",
- prog_name, prog_vers, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name);
-
- printf(
-"Commands:\n"
-"Either long or short options are allowed.\n"
-" --append -A chain Append to chain\n"
-" --check -C chain Check for the existence of a rule\n"
-" --delete -D chain Delete matching rule from chain\n"
-" --delete -D chain rulenum\n"
-" Delete rule rulenum (1 = first) from chain\n"
-" --insert -I chain [rulenum]\n"
-" Insert in chain as rulenum (default 1=first)\n"
-" --replace -R chain rulenum\n"
-" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain [rulenum]]\n"
-" List the rules in a chain or all chains\n"
-" --list-rules -S [chain [rulenum]]\n"
-" Print the rules in a chain or all chains\n"
-" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain [rulenum]]\n"
-" Zero counters in chain or all chains\n"
-" --new -N chain Create a new user-defined chain\n"
-" --delete-chain\n"
-" -X [chain] Delete a user-defined chain\n"
-" --policy -P chain target\n"
-" Change policy on chain to target\n"
-" --rename-chain\n"
-" -E old-chain new-chain\n"
-" Change chain name, (moving any references)\n"
-
-"Options:\n"
-" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n"
-" --ipv6 -6 Error (line is ignored by iptables-restore)\n"
-"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
-"[!] --source -s address[/mask][...]\n"
-" source specification\n"
-"[!] --destination -d address[/mask][...]\n"
-" destination specification\n"
-"[!] --in-interface -i input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-#ifdef IPT_F_GOTO
-" --goto -g chain\n"
-" jump to chain with no return\n"
-#endif
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-"[!] --out-interface -o output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
-" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
-" default is 1 second\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-"[!] --fragment -f match second or further fragments only\n"
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
-
- print_extension_helps(xtables_targets, matches);
- exit(0);
-}
-
-void
-iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- fprintf(stderr, "%s v%s (legacy): ", prog_name, prog_vers);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, "\n");
- if (status == PARAMETER_PROBLEM)
- exit_tryhelp(status);
- if (status == VERSION_PROBLEM)
- fprintf(stderr,
- "Perhaps iptables or your kernel needs to be upgraded.\n");
- /* On error paths, make sure that we don't leak memory */
- xtables_free_opts(1);
- 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.
@@ -319,102 +102,6 @@ opt2char(int option)
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
-static void
-parse_chain(const char *chainname)
-{
- const char *ptr;
-
- if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- chainname, XT_EXTENSION_MAXNAMELEN);
-
- if (*chainname == '-' || *chainname == '!')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *chainname);
-
- if (xtables_find_target(chainname, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
-
- for (ptr = chainname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s'", chainname);
-}
-
-static void
-set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-static void
-print_header(unsigned int format, const char *chain, struct xtc_handle *handle)
-{
- struct xt_counters counters;
- const char *pol = iptc_get_policy(chain, &counters, handle);
- printf("Chain %s", chain);
- if (pol) {
- printf(" (policy %s", pol);
- if (!(format & FMT_NOCOUNTS)) {
- fputc(' ', stdout);
- xtables_print_num(counters.pcnt, (format|FMT_NOTABLE));
- fputs("packets, ", stdout);
- xtables_print_num(counters.bcnt, (format|FMT_NOTABLE));
- fputs("bytes", stdout);
- }
- printf(")\n");
- } else {
- unsigned int refs;
- if (!iptc_get_references(&refs, chain, handle))
- printf(" (ERROR obtaining refs)\n");
- else
- printf(" (%u references)\n", refs);
- }
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4s ", "%s "), "num");
- if (!(format & FMT_NOCOUNTS)) {
- if (format & FMT_KILOMEGAGIGA) {
- printf(FMT("%5s ","%s "), "pkts");
- printf(FMT("%5s ","%s "), "bytes");
- } else {
- printf(FMT("%8s ","%s "), "pkts");
- printf(FMT("%10s ","%s "), "bytes");
- }
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ","%s "), "target");
- fputs(" prot ", stdout);
- if (format & FMT_OPTIONS)
- fputs("opt", stdout);
- if (format & FMT_VIA) {
- printf(FMT(" %-6s ","%s "), "in");
- printf(FMT("%-6s ","%s "), "out");
- }
- printf(FMT(" %-19s ","%s "), "source");
- printf(FMT(" %-19s "," %s "), "destination");
- printf("\n");
-}
-
static int
print_match(const struct xt_entry_match *m,
@@ -435,6 +122,9 @@ print_match(const struct xt_entry_match *m,
printf("%s%s ", match->name, unsupported_rev);
else
printf("%s ", match->name);
+
+ if (match->next == match)
+ free(match);
} else {
if (name[0])
printf("UNKNOWN match `%s' ", name);
@@ -453,7 +143,6 @@ print_firewall(const struct ipt_entry *fw,
{
struct xtables_target *target, *tg;
const struct xt_entry_target *t;
- uint8_t flags;
if (!iptc_is_chain(targname, handle))
target = xtables_find_target(targname, XTF_TRY_LOAD);
@@ -462,35 +151,11 @@ print_firewall(const struct ipt_entry *fw,
XTF_LOAD_MUST_SUCCEED);
t = ipt_get_target((struct ipt_entry *)fw);
- flags = fw->ip.flags;
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4u ", "%u "), num);
+ print_rule_details(num, &fw->counters, targname, fw->ip.proto,
+ fw->ip.flags, fw->ip.invflags, format);
- if (!(format & FMT_NOCOUNTS)) {
- xtables_print_num(fw->counters.pcnt, format);
- xtables_print_num(fw->counters.bcnt, format);
- }
-
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ", "%s "), targname);
-
- fputc(fw->ip.invflags & XT_INV_PROTO ? '!' : ' ', stdout);
- {
- const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
- if (pname)
- printf(FMT("%-5s", "%s "), pname);
- else
- printf(FMT("%-5hu", "%hu "), fw->ip.proto);
- }
-
- if (format & FMT_OPTIONS) {
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
- fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
- fputc(' ', stdout);
- }
+ print_fragment(fw->ip.flags, fw->ip.invflags, format, false);
print_ifaces(fw->ip.iniface, fw->ip.outiface, fw->ip.invflags, format);
@@ -516,6 +181,9 @@ print_firewall(const struct ipt_entry *fw,
tg->print(&fw->ip, t, format & FMT_NUMERIC);
else if (target->print)
printf(" %s%s", target->name, unsupported_rev);
+
+ if (target->next == target)
+ free(target);
} else if (t->u.target_size != sizeof(*t))
printf("[%u bytes of unknown target data] ",
(unsigned int)(t->u.target_size - sizeof(*t)));
@@ -614,40 +282,6 @@ insert_entry(const xt_chainlabel chain,
return ret;
}
-static unsigned char *
-make_delete_mask(const struct xtables_rule_match *matches,
- const struct xtables_target *target)
-{
- /* Establish mask for comparison */
- unsigned int size;
- const struct xtables_rule_match *matchp;
- unsigned char *mask, *mptr;
-
- size = sizeof(struct ipt_entry);
- for (matchp = matches; matchp; matchp = matchp->next)
- size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
-
- mask = xtables_calloc(1, size
- + XT_ALIGN(sizeof(struct xt_entry_target))
- + target->size);
-
- memset(mask, 0xFF, sizeof(struct ipt_entry));
- mptr = mask + sizeof(struct ipt_entry);
-
- for (matchp = matches; matchp; matchp = matchp->next) {
- memset(mptr, 0xFF,
- XT_ALIGN(sizeof(struct xt_entry_match))
- + matchp->match->userspacesize);
- mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
- }
-
- memset(mptr, 0xFF,
- XT_ALIGN(sizeof(struct xt_entry_target))
- + target->userspacesize);
-
- return mask;
-}
-
static int
delete_entry(const xt_chainlabel chain,
struct ipt_entry *fw,
@@ -666,7 +300,7 @@ delete_entry(const xt_chainlabel chain,
int ret = 1;
unsigned char *mask;
- mask = make_delete_mask(matches, target);
+ mask = make_delete_mask(matches, target, sizeof(*fw));
for (i = 0; i < nsaddrs; i++) {
fw->ip.src.s_addr = saddrs[i].s_addr;
fw->ip.smsk.s_addr = smasks[i].s_addr;
@@ -696,7 +330,7 @@ check_entry(const xt_chainlabel chain, struct ipt_entry *fw,
int ret = 1;
unsigned char *mask;
- mask = make_delete_mask(matches, target);
+ mask = make_delete_mask(matches, target, sizeof(*fw));
for (i = 0; i < nsaddrs; i++) {
fw->ip.src.s_addr = saddrs[i].s_addr;
fw->ip.smsk.s_addr = smasks[i].s_addr;
@@ -819,8 +453,18 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
if (found) printf("\n");
- if (!rulenum)
- print_header(format, this, handle);
+ if (!rulenum) {
+ struct xt_counters counters;
+ unsigned int urefs;
+ const char *pol;
+ int refs = -1;
+
+ pol = iptc_get_policy(this, &counters, handle);
+ if (!pol && iptc_get_references(&urefs, this, handle))
+ refs = urefs;
+
+ print_header(format, this, pol, &counters, refs, 0);
+ }
i = iptc_first_rule(this, handle);
num = 0;
@@ -841,29 +485,6 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
return found;
}
-static void print_proto(uint16_t proto, int invert)
-{
- if (proto) {
- unsigned int i;
- const char *invertstr = invert ? " !" : "";
-
- const struct protoent *pent = getprotobynumber(proto);
- if (pent) {
- printf("%s -p %s", invertstr, pent->p_name);
- return;
- }
-
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto) {
- printf("%s -p %s",
- invertstr, xtables_chain_protos[i].name);
- return;
- }
-
- printf("%s -p %u", invertstr, proto);
- }
-}
-
#define IP_PARTS_NATIVE(n) \
(unsigned int)((n)>>24)&0xFF, \
(unsigned int)((n)>>16)&0xFF, \
@@ -872,93 +493,6 @@ static void print_proto(uint16_t proto, int invert)
#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
-/* This assumes that mask is contiguous, and byte-bounded. */
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask,
- int invert)
-{
- unsigned int i;
-
- if (mask[0] == 0)
- return;
-
- printf("%s -%c ", invert ? " !" : "", letter);
-
- for (i = 0; i < IFNAMSIZ; i++) {
- if (mask[i] != 0) {
- if (iface[i] != '\0')
- printf("%c", iface[i]);
- } else {
- /* we can access iface[i-1] here, because
- * a few lines above we make sure that mask[0] != 0 */
- if (iface[i-1] != '\0')
- printf("+");
- break;
- }
- }
-}
-
-static int print_match_save(const struct xt_entry_match *e,
- const struct ipt_ip *ip)
-{
- const char *name = e->u.user.name;
- const int revision = e->u.user.revision;
- struct xtables_match *match, *mt, *mt2;
-
- match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
- if (match) {
- mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
- match, revision);
- if (!mt2)
- mt2 = match;
- printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
-
- /* some matches don't provide a save function */
- if (mt && mt->save)
- mt->save(ip, e);
- else if (match->save)
- printf(unsupported_rev);
- } else {
- if (e->u.match_size) {
- fprintf(stderr,
- "Can't find library for match `%s'\n",
- name);
- exit(1);
- }
- }
- return 0;
-}
-
-/* Print a given ip including mask if necessary. */
-static void print_ip(const char *prefix, uint32_t ip,
- uint32_t mask, int invert)
-{
- uint32_t bits, hmask = ntohl(mask);
- int i;
-
- if (!mask && !ip && !invert)
- return;
-
- printf("%s %s %u.%u.%u.%u",
- invert ? " !" : "",
- prefix,
- IP_PARTS(ip));
-
- if (mask == 0xFFFFFFFFU) {
- printf("/32");
- return;
- }
-
- i = 32;
- bits = 0xFFFFFFFEU;
- while (--i >= 0 && hmask != bits)
- bits <<= 1;
- if (i >= 0)
- printf("/%u", i);
- else
- printf("/%u.%u.%u.%u", IP_PARTS(mask));
-}
-
/* We want this to be readable, so only print out necessary fields.
* Because that's the kind of world I want to live in.
*/
@@ -976,23 +510,15 @@ void print_rule4(const struct ipt_entry *e,
printf("-A %s", chain);
/* Print IP part. */
- print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
- e->ip.invflags & IPT_INV_SRCIP);
+ save_ipv4_addr('s', &e->ip.src, &e->ip.smsk,
+ e->ip.invflags & IPT_INV_SRCIP);
- print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
+ save_ipv4_addr('d', &e->ip.dst, &e->ip.dmsk,
e->ip.invflags & IPT_INV_DSTIP);
- print_iface('i', e->ip.iniface, e->ip.iniface_mask,
- e->ip.invflags & IPT_INV_VIA_IN);
-
- print_iface('o', e->ip.outiface, e->ip.outiface_mask,
- e->ip.invflags & IPT_INV_VIA_OUT);
-
- print_proto(e->ip.proto, e->ip.invflags & XT_INV_PROTO);
-
- if (e->ip.flags & IPT_F_FRAG)
- printf("%s -f",
- e->ip.invflags & IPT_INV_FRAG ? " !" : "");
+ save_rule_details(e->ip.iniface, e->ip.outiface,
+ e->ip.proto, e->ip.flags & IPT_F_FRAG,
+ e->ip.invflags);
/* Print matchinfo part */
if (e->target_offset)
@@ -1133,455 +659,61 @@ generate_entry(const struct ipt_entry *fw,
int do_command4(int argc, char *argv[], char **table,
struct xtc_handle **handle, bool restore)
{
+ struct xt_cmd_parse_ops cmd_parse_ops = {
+ .proto_parse = ipv4_proto_parse,
+ .post_parse = ipv4_post_parse,
+ .option_name = ip46t_option_name,
+ .option_invert = ip46t_option_invert,
+ .command_default = command_default,
+ .print_help = xtables_printhelp,
+ };
+ struct xt_cmd_parse p = {
+ .table = *table,
+ .restore = restore,
+ .line = line,
+ .ops = &cmd_parse_ops,
+ };
struct iptables_command_state cs = {
.jumpto = "",
.argv = argv,
};
+ struct xtables_args args = {
+ .family = AF_INET,
+ };
struct ipt_entry *e = NULL;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in_addr *saddrs = NULL, *smasks = NULL;
struct in_addr *daddrs = NULL, *dmasks = NULL;
- struct timeval wait_interval = {
- .tv_sec = 1,
- };
- bool wait_interval_set = false;
int verbose = 0;
int wait = 0;
const char *chain = NULL;
- const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
const char *policy = NULL, *newname = NULL;
unsigned int rulenum = 0, command = 0;
- const char *pcnt = NULL, *bcnt = NULL;
int ret = 1;
- struct xtables_match *m;
- struct xtables_rule_match *matchp;
- struct xtables_target *t;
- unsigned long long cnt;
- bool table_set = false;
-
- /* re-set optind to 0 in case do_command4 gets called
- * a second time */
- optind = 0;
-
- /* clear mflags in case do_command4 gets called a second time
- * (we clear the global list of all matches for security)*/
- for (m = xtables_matches; m; m = m->next)
- m->mflags = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- opterr = 0;
- opts = xt_params->orig_opts;
- while ((cs.c = getopt_long(argc, argv,
- "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
- opts, NULL)) != -1) {
- switch (cs.c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&command, CMD_APPEND, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'C':
- add_command(&command, CMD_CHECK, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&command, CMD_REPLACE, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&command, CMD_INSERT, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else rulenum = 1;
- break;
-
- case 'L':
- add_command(&command, CMD_LIST,
- CMD_ZERO | CMD_ZERO_NUM, cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'S':
- add_command(&command, CMD_LIST_RULES,
- CMD_ZERO|CMD_ZERO_NUM, cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'F':
- add_command(&command, CMD_FLUSH, CMD_NONE,
- cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES,
- cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_ZERO_NUM;
- }
- break;
-
- case 'N':
- parse_chain(optarg);
- add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
- cs.invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- cs.invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&command, CMD_SET_POLICY, CMD_NONE,
- cs.invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
-
- /* iptables -p icmp -h */
- if (!cs.matches && cs.protocol)
- xtables_find_match(cs.protocol,
- XTF_TRY_LOAD, &cs.matches);
- exit_printhelp(cs.matches);
-
- /*
- * Option selection
- */
- case 'p':
- set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags,
- cs.invert);
-
- /* Canonicalize into lower case */
- for (cs.protocol = optarg; *cs.protocol; cs.protocol++)
- *cs.protocol = tolower(*cs.protocol);
-
- cs.protocol = optarg;
- cs.fw.ip.proto = xtables_parse_protocol(cs.protocol);
-
- if (cs.fw.ip.proto == 0
- && (cs.fw.ip.invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
- break;
-
- case 's':
- set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags,
- cs.invert);
- shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags,
- cs.invert);
- dhostnetworkmask = optarg;
- break;
-
-#ifdef IPT_F_GOTO
- case 'g':
- set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
- cs.invert);
- cs.fw.ip.flags |= IPT_F_GOTO;
- cs.jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
- cs.invert);
- command_jump(&cs, optarg);
- break;
-
-
- case 'i':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags,
- cs.invert);
- xtables_parse_interface(optarg,
- cs.fw.ip.iniface,
- cs.fw.ip.iniface_mask);
- break;
-
- case 'o':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags,
- cs.invert);
- xtables_parse_interface(optarg,
- cs.fw.ip.outiface,
- cs.fw.ip.outiface_mask);
- break;
-
- case 'f':
- set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags,
- cs.invert);
- cs.fw.ip.flags |= IPT_F_FRAG;
- break;
-
- case 'v':
- if (!verbose)
- set_option(&cs.options, OPT_VERBOSE,
- &cs.fw.ip.invflags, cs.invert);
- verbose++;
- break;
-
- case 'w':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-w' from "
- "iptables-restore");
- }
- wait = parse_wait_time(argc, argv);
- break;
-
- case 'W':
- if (restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-W' from "
- "iptables-restore");
- }
- parse_wait_interval(argc, argv, &wait_interval);
- wait_interval_set = true;
- break;
-
- case 'm':
- command_match(&cs);
- break;
-
- case 'n':
- set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags,
- cs.invert);
- break;
-
- case 't':
- if (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- if (restore && table_set)
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- *table = optarg;
- table_set = true;
- break;
-
- case 'x':
- set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags,
- cs.invert);
- break;
-
- case 'V':
- if (cs.invert)
- printf("Not %s ;-)\n", prog_vers);
- else
- printf("%s v%s (legacy)\n",
- prog_name, prog_vers);
- exit(0);
-
- case '0':
- set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags,
- cs.invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
-
- set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags,
- cs.invert);
- pcnt = optarg;
- bcnt = strchr(pcnt + 1, ',');
- if (bcnt)
- bcnt++;
- if (!bcnt && xs_has_arg(argc, argv))
- bcnt = argv[optind++];
- if (!bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(pcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw.counters.pcnt = cnt;
-
- if (sscanf(bcnt, "%llu", &cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
- cs.fw.counters.bcnt = cnt;
- break;
-
- case '4':
- /* This is indeed the IPv4 iptables */
- break;
-
- case '6':
- /* This is not the IPv6 ip6tables */
- if (line != -1)
- return 1; /* success: line ignored */
- fprintf(stderr, "This is the IPv4 version of iptables.\n");
- exit_tryhelp(2);
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- cs.invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(&cs, &iptables_globals) == 1)
- /* cf. ip6tables.c */
- continue;
- break;
- }
- cs.invert = false;
- }
-
- if (!wait && wait_interval_set)
- xtables_error(PARAMETER_PROBLEM,
- "--wait-interval only makes sense with --wait\n");
-
- if (strcmp(*table, "nat") == 0 &&
- ((policy != NULL && strcmp(policy, "DROP") == 0) ||
- (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0)))
- xtables_error(PARAMETER_PROBLEM,
- "\nThe \"nat\" table is not intended for filtering, "
- "the use of DROP is therefore inhibited.\n\n");
-
- for (matchp = cs.matches; matchp; matchp = matchp->next)
- xtables_option_mfcall(matchp->match);
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
-
- /* Fix me: must put inverse options checking here --MN */
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (!command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
- if (cs.invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs.options & OPT_DESTINATION))
- dhostnetworkmask = "0.0.0.0/0";
- if (!(cs.options & OPT_SOURCE))
- shostnetworkmask = "0.0.0.0/0";
- }
-
- if (shostnetworkmask)
- xtables_ipparse_multiple(shostnetworkmask, &saddrs,
- &smasks, &nsaddrs);
-
- if (dhostnetworkmask)
- xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
- &dmasks, &ndaddrs);
-
- if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
- " source or destination IP addresses");
-
- if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- generic_opt_check(command, cs.options);
+ do_parse(argc, argv, &p, &cs, &args);
+
+ command = p.command;
+ chain = p.chain;
+ *table = p.table;
+ rulenum = p.rulenum;
+ policy = p.policy;
+ newname = p.newname;
+ verbose = p.verbose;
+ wait = args.wait;
+ nsaddrs = args.s.naddrs;
+ ndaddrs = args.d.naddrs;
+ saddrs = args.s.addr.v4;
+ daddrs = args.d.addr.v4;
+ smasks = args.s.mask.v4;
+ dmasks = args.d.mask.v4;
+
+ iface_to_mask(cs.fw.ip.iniface, cs.fw.ip.iniface_mask);
+ iface_to_mask(cs.fw.ip.outiface, cs.fw.ip.outiface_mask);
/* Attempt to acquire the xtables lock */
if (!restore)
- xtables_lock_or_exit(wait, &wait_interval);
+ xtables_lock_or_exit(wait);
/* only allocate handle if we weren't called with a handle */
if (!*handle)
@@ -1601,26 +733,6 @@ int do_command4(int argc, char *argv[], char **table,
|| command == CMD_CHECK
|| command == CMD_INSERT
|| command == CMD_REPLACE) {
- if (strcmp(chain, "PREROUTING") == 0
- || strcmp(chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (cs.options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- chain);
- }
-
- if (strcmp(chain, "POSTROUTING") == 0
- || strcmp(chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (cs.options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- chain);
- }
-
if (cs.target && iptc_is_chain(cs.jumpto, *handle)) {
fprintf(stderr,
"Warning: using chain %s, not extension\n",
@@ -1661,13 +773,12 @@ int do_command4(int argc, char *argv[], char **table,
#ifdef IPT_F_GOTO
if (cs.fw.ip.flags & IPT_F_GOTO)
xtables_error(PARAMETER_PROBLEM,
- "goto '%s' is not a chain\n",
- cs.jumpto);
+ "goto '%s' is not a chain",
+ cs.jumpto);
#endif
xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED);
} else {
e = generate_entry(&cs.fw, cs.matches, cs.target->t);
- free(cs.target->t);
}
}
@@ -1758,25 +869,25 @@ int do_command4(int argc, char *argv[], char **table,
case CMD_SET_POLICY:
ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle);
break;
+ case CMD_NONE:
+ /* do_parse ignored the line (eg: -4 with ip6tables-restore) */
+ break;
default:
/* We should never reach this... */
- exit_tryhelp(2);
+ exit_tryhelp(2, line);
}
if (verbose > 1)
dump_entries(*handle);
- xtables_rule_matches_free(&cs.matches);
+ xtables_clear_iptables_command_state(&cs);
if (e != NULL) {
free(e);
e = NULL;
}
- free(saddrs);
- free(smasks);
- free(daddrs);
- free(dmasks);
+ xtables_clear_args(&args);
xtables_free_opts(1);
return ret;
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 5dc38da8..5d66e271 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -18,6 +18,7 @@
#include <xtables.h>
#include <libiptc/libxtc.h>
+#include <arpa/inet.h>
#include <net/if_arp.h>
#include <netinet/if_ether.h>
@@ -25,94 +26,8 @@
#include <linux/netfilter/nf_tables.h>
#include "nft-shared.h"
-#include "nft-arp.h"
#include "nft.h"
-
-/* a few names */
-char *arp_opcodes[] =
-{
- "Request",
- "Reply",
- "Request_Reverse",
- "Reply_Reverse",
- "DRARP_Request",
- "DRARP_Reply",
- "DRARP_Error",
- "InARP_Request",
- "ARP_NAK",
-};
-
-static char *
-addr_to_dotted(const struct in_addr *addrp)
-{
- static char buf[20];
- const unsigned char *bytep;
-
- bytep = (const unsigned char *) &(addrp->s_addr);
- sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
- return buf;
-}
-
-static char *
-addr_to_host(const struct in_addr *addr)
-{
- struct hostent *host;
-
- if ((host = gethostbyaddr((char *) addr,
- sizeof(struct in_addr), AF_INET)) != NULL)
- return (char *) host->h_name;
-
- return (char *) NULL;
-}
-
-static char *
-addr_to_network(const struct in_addr *addr)
-{
- struct netent *net;
-
- if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
- return (char *) net->n_name;
-
- return (char *) NULL;
-}
-
-static char *
-addr_to_anyname(const struct in_addr *addr)
-{
- char *name;
-
- if ((name = addr_to_host(addr)) != NULL ||
- (name = addr_to_network(addr)) != NULL)
- return name;
-
- return addr_to_dotted(addr);
-}
-
-static char *
-mask_to_dotted(const struct in_addr *mask)
-{
- int i;
- static char buf[22];
- u_int32_t maskaddr, bits;
-
- maskaddr = ntohl(mask->s_addr);
-
- if (maskaddr == 0xFFFFFFFFL)
- /* we don't want to see "/32" */
- return "";
-
- i = 32;
- bits = 0xFFFFFFFEL;
- while (--i >= 0 && maskaddr != bits)
- bits <<= 1;
- if (i >= 0)
- sprintf(buf, "/%d", i);
- else
- /* mask was not a decent combination of 1's and 0's */
- snprintf(buf, sizeof(buf), "/%s", addr_to_dotted(mask));
-
- return buf;
-}
+#include "xshared.h"
static bool need_devaddr(struct arpt_devaddr_info *info)
{
@@ -126,59 +41,80 @@ static bool need_devaddr(struct arpt_devaddr_info *info)
return false;
}
-static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
+static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
+ struct nftnl_rule *r, struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct arpt_entry *fw = &cs->arp;
uint32_t op;
int ret = 0;
if (fw->arp.iniface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_IN);
- add_iniface(r, fw->arp.iniface, op);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
+ add_iface(h, r, fw->arp.iniface, NFT_META_IIFNAME, op);
}
if (fw->arp.outiface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_OUT);
- add_outiface(r, fw->arp.outiface, op);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
+ add_iface(h, r, fw->arp.outiface, NFT_META_OIFNAME, op);
}
if (fw->arp.arhrd != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHRD) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHRD);
- add_payload(r, offsetof(struct arphdr, ar_hrd), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u16(r, fw->arp.arhrd, op);
+ fw->arp.arhrd_mask != 0xffff ||
+ fw->arp.invflags & IPT_INV_ARPHRD) {
+ uint8_t reg;
+
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
+ add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ if (fw->arp.arhrd_mask != 0xffff)
+ add_bitwise_u16(h, r, fw->arp.arhrd_mask, 0, reg, &reg);
+ add_cmp_u16(r, fw->arp.arhrd, op, reg);
}
if (fw->arp.arpro != 0 ||
- fw->arp.invflags & ARPT_INV_ARPPRO) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPPRO);
- add_payload(r, offsetof(struct arphdr, ar_pro), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u16(r, fw->arp.arpro, op);
+ fw->arp.arpro_mask != 0xffff ||
+ fw->arp.invflags & IPT_INV_PROTO) {
+ uint8_t reg;
+
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
+ add_payload(h, r, offsetof(struct arphdr, ar_pro), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ if (fw->arp.arpro_mask != 0xffff)
+ add_bitwise_u16(h, r, fw->arp.arpro_mask, 0, reg, &reg);
+ add_cmp_u16(r, fw->arp.arpro, op, reg);
}
if (fw->arp.arhln != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHLN) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHLN);
- add_proto(r, offsetof(struct arphdr, ar_hln), 1,
- fw->arp.arhln, op);
+ fw->arp.arhln_mask != 255 ||
+ fw->arp.invflags & IPT_INV_ARPHLN) {
+ uint8_t reg;
+
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
+ add_payload(h, r, offsetof(struct arphdr, ar_hln), 1,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ if (fw->arp.arhln_mask != 255)
+ add_bitwise(h, r, &fw->arp.arhln_mask, 1, reg, &reg);
+ add_cmp_u8(r, fw->arp.arhln, op, reg);
}
- add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
+ add_proto(h, 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);
- add_payload(r, offsetof(struct arphdr, ar_op), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u16(r, fw->arp.arpop, op);
+ fw->arp.arpop_mask != 0xffff ||
+ fw->arp.invflags & IPT_INV_ARPOP) {
+ uint8_t reg;
+
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
+ add_payload(h, r, offsetof(struct arphdr, ar_op), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ if (fw->arp.arpop_mask != 0xffff)
+ add_bitwise_u16(h, r, fw->arp.arpop_mask, 0, reg, &reg);
+ add_cmp_u16(r, fw->arp.arpop, op, reg);
}
if (need_devaddr(&fw->arp.src_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCDEVADDR);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr),
&fw->arp.src_devaddr.addr,
&fw->arp.src_devaddr.mask,
@@ -188,9 +124,9 @@ 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, NFT_PAYLOAD_NETWORK_HEADER,
+ fw->arp.invflags & IPT_INV_SRCIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
+ add_addr(h, 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);
@@ -198,8 +134,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (need_devaddr(&fw->arp.tgt_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTDEVADDR);
- add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
+ add_addr(h, 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,
@@ -208,9 +144,9 @@ 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, NFT_PAYLOAD_NETWORK_HEADER,
+ fw->arp.invflags & IPT_INV_DSTIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
+ add_addr(h, 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);
@@ -240,173 +176,13 @@ 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)
-{
- struct iptables_command_state *cs = data;
- struct arpt_entry *fw = &cs->arp;
- uint8_t flags = 0;
-
- parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
- fw->arp.outiface, fw->arp.outiface_mask,
- &flags);
-
- fw->arp.invflags |= ipt_to_arpt_flags(flags);
-}
-
-static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-}
-
-static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
-{
- mask->s_addr = ctx->bitwise.mask[0];
-}
-
-static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e,
- struct arpt_devaddr_info *info)
-{
- uint32_t hlen;
- bool inv;
-
- nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen);
-
- if (hlen != ETH_ALEN)
- return false;
-
- get_cmp_data(e, info->addr, ETH_ALEN, &inv);
-
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(info->mask, 0xff,
- min(ctx->payload.len, ETH_ALEN));
- }
-
- return inv;
-}
-
-static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
-{
- struct iptables_command_state *cs = data;
- struct arpt_entry *fw = &cs->arp;
- struct in_addr addr;
- uint16_t ar_hrd, ar_pro, ar_op;
- uint8_t ar_hln;
- bool inv;
-
- switch (ctx->payload.offset) {
- case offsetof(struct arphdr, ar_hrd):
- get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
- fw->arp.arhrd = ar_hrd;
- fw->arp.arhrd_mask = 0xffff;
- if (inv)
- fw->arp.invflags |= ARPT_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;
- 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;
- 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;
- 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;
- } else if (ctx->payload.offset == sizeof(struct arphdr) +
- fw->arp.arhln) {
- get_cmp_data(e, &addr, sizeof(addr), &inv);
- fw->arp.src.s_addr = addr.s_addr;
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- parse_mask_ipv4(ctx, &fw->arp.smsk);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&fw->arp.smsk, 0xff,
- min(ctx->payload.len,
- sizeof(struct in_addr)));
- }
-
- if (inv)
- fw->arp.invflags |= ARPT_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;
- } else if (ctx->payload.offset == sizeof(struct arphdr) +
- fw->arp.arhln +
- sizeof(struct in_addr) +
- fw->arp.arhln) {
- get_cmp_data(e, &addr, sizeof(addr), &inv);
- fw->arp.tgt.s_addr = addr.s_addr;
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- parse_mask_ipv4(ctx, &fw->arp.tmsk);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&fw->arp.tmsk, 0xff,
- min(ctx->payload.len,
- sizeof(struct in_addr)));
- }
-
- if (inv)
- fw->arp.invflags |= ARPT_INV_TGTIP;
- }
- break;
- }
-}
-
static void nft_arp_print_header(unsigned int format, const char *chain,
const char *pol,
const struct xt_counters *counters,
- bool basechain, uint32_t refs,
- uint32_t entries)
+ int refs, uint32_t entries)
{
printf("Chain %s", chain);
- if (basechain && pol) {
+ if (pol) {
printf(" (policy %s", pol);
if (!(format & FMT_NOCOUNTS)) {
fputc(' ', stdout);
@@ -417,7 +193,7 @@ static void nft_arp_print_header(unsigned int format, const char *chain,
}
printf(")\n");
} else {
- printf(" (%u references)\n", refs);
+ printf(" (%d references)\n", refs);
}
}
@@ -425,7 +201,6 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
unsigned int format)
{
const struct arpt_entry *fw = &cs->arp;
- char buf[BUFSIZ];
char iface[IFNAMSIZ+2];
const char *sep = "";
int print_iface = 0;
@@ -448,7 +223,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 = " ";
}
@@ -466,21 +241,16 @@ 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
- ? "! " : "");
- if (format & FMT_NUMERIC)
- sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
- else
- sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src)));
- strncat(buf, mask_to_dotted(&(fw->arp.smsk)),
- sizeof(buf) - strlen(buf) - 1);
- printf("-s %s", buf);
+ printf("%s%s-s %s", sep,
+ fw->arp.invflags & IPT_INV_SRCIP ? "! " : "",
+ ipv4_addr_to_string(&fw->arp.src,
+ &fw->arp.smsk, format));
sep = " ";
}
@@ -489,7 +259,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,
@@ -498,15 +268,10 @@ 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
- ? "! " : "");
- if (format & FMT_NUMERIC)
- sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
- else
- sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt)));
- strncat(buf, mask_to_dotted(&(fw->arp.tmsk)),
- sizeof(buf) - strlen(buf) - 1);
- printf("-d %s", buf);
+ printf("%s%s-d %s", sep,
+ fw->arp.invflags & IPT_INV_DSTIP ? "! " : "",
+ ipv4_addr_to_string(&fw->arp.tgt,
+ &fw->arp.tmsk, format));
sep = " ";
}
@@ -515,7 +280,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,
@@ -524,8 +289,9 @@ after_devsrc:
after_devdst:
- if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHLN
+ if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6 ||
+ fw->arp.invflags & IPT_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)
@@ -536,9 +302,9 @@ 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))
+ if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC))
printf("--opcode %s", arp_opcodes[tmp-1]);
else
printf("--opcode %d", tmp);
@@ -548,42 +314,42 @@ after_devdst:
sep = " ";
}
- if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) {
+ if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1) ||
+ fw->arp.invflags & IPT_INV_ARPHRD) {
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");
else
- printf("--h-type %u", tmp);
+ printf("--h-type 0x%x", tmp);
if (fw->arp.arhrd_mask != 65535)
- printf("/%d", ntohs(fw->arp.arhrd_mask));
+ printf("/0x%x", ntohs(fw->arp.arhrd_mask));
sep = " ";
}
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");
else
printf("--proto-type 0x%x", tmp);
if (fw->arp.arpro_mask != 65535)
- printf("/%x", ntohs(fw->arp.arpro_mask));
+ printf("/0x%x", ntohs(fw->arp.arpro_mask));
sep = " ";
}
}
static void
-nft_arp_save_rule(const void *data, unsigned int format)
+nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format)
{
- const struct iptables_command_state *cs = data;
-
format |= FMT_NUMERIC;
+ printf(" ");
nft_arp_print_rule_details(cs, format);
if (cs->target && cs->target->save)
cs->target->save(&cs->fw, cs->target->t);
@@ -614,14 +380,14 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- nft_clear_iptables_command_state(&cs);
+ xtables_clear_iptables_command_state(&cs);
}
-static bool nft_arp_is_same(const void *data_a,
- const void *data_b)
+static bool nft_arp_is_same(const struct iptables_command_state *cs_a,
+ const struct iptables_command_state *cs_b)
{
- const struct arpt_entry *a = data_a;
- const struct arpt_entry *b = data_b;
+ const struct arpt_entry *a = &cs_a->arp;
+ const struct arpt_entry *b = &cs_b->arp;
if (a->arp.src.s_addr != b->arp.src.s_addr
|| a->arp.tgt.s_addr != b->arp.tgt.s_addr
@@ -651,19 +417,456 @@ static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
printf(":%s %s\n", chain, policy ?: "-");
}
+static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask)
+{
+ char *dup = strdup(from);
+ char *p, *buffer;
+ int i, ret = -1;
+
+ if (!dup)
+ return -1;
+
+ if ( (p = strrchr(dup, '/')) != NULL) {
+ *p = '\0';
+ i = strtol(p+1, &buffer, 10);
+ if (*buffer != '\0' || i < 0 || i > 255)
+ goto out_err;
+ *mask = (uint8_t)i;
+ } else
+ *mask = 255;
+ i = strtol(dup, &buffer, 10);
+ if (*buffer != '\0' || i < 0 || i > 255)
+ goto out_err;
+ *to = (uint8_t)i;
+ ret = 0;
+out_err:
+ free(dup);
+ return ret;
+
+}
+
+static int get16_and_mask(const char *from, uint16_t *to,
+ uint16_t *mask, int base)
+{
+ char *dup = strdup(from);
+ char *p, *buffer;
+ int i, ret = -1;
+
+ if (!dup)
+ return -1;
+
+ if ( (p = strrchr(dup, '/')) != NULL) {
+ *p = '\0';
+ i = strtol(p+1, &buffer, base);
+ if (*buffer != '\0' || i < 0 || i > 65535)
+ goto out_err;
+ *mask = htons((uint16_t)i);
+ } else
+ *mask = 65535;
+ i = strtol(dup, &buffer, base);
+ if (*buffer != '\0' || i < 0 || i > 65535)
+ goto out_err;
+ *to = htons((uint16_t)i);
+ ret = 0;
+out_err:
+ free(dup);
+ return ret;
+}
+
+static void nft_arp_post_parse(int command,
+ struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->arp.arp.invflags = args->invflags;
+
+ memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ);
+ memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ);
+
+ memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ);
+ memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ);
+
+ cs->arp.counters.pcnt = args->pcnt_cnt;
+ cs->arp.counters.bcnt = args->bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs->options & OPT_DESTINATION))
+ args->dhostnetworkmask = "0.0.0.0/0";
+ if (!(cs->options & OPT_SOURCE))
+ args->shostnetworkmask = "0.0.0.0/0";
+ }
+
+ if (args->shostnetworkmask)
+ xtables_ipparse_multiple(args->shostnetworkmask,
+ &args->s.addr.v4, &args->s.mask.v4,
+ &args->s.naddrs);
+ if (args->dhostnetworkmask)
+ xtables_ipparse_multiple(args->dhostnetworkmask,
+ &args->d.addr.v4, &args->d.mask.v4,
+ &args->d.naddrs);
+
+ if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+ (cs->arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+
+ if (args->src_mac &&
+ xtables_parse_mac_and_mask(args->src_mac,
+ cs->arp.arp.src_devaddr.addr,
+ cs->arp.arp.src_devaddr.mask))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified source mac");
+ if (args->dst_mac &&
+ xtables_parse_mac_and_mask(args->dst_mac,
+ cs->arp.arp.tgt_devaddr.addr,
+ cs->arp.arp.tgt_devaddr.mask))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified destination mac");
+ if (args->arp_hlen) {
+ getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln,
+ &cs->arp.arp.arhln_mask);
+
+ if (cs->arp.arp.arhln != 6)
+ xtables_error(PARAMETER_PROBLEM,
+ "Only hardware address length of 6 is supported currently.");
+ }
+ if (args->arp_opcode) {
+ if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop,
+ &cs->arp.arp.arpop_mask, 10)) {
+ int i;
+
+ for (i = 0; i < ARP_NUMOPCODES; i++)
+ if (!strcasecmp(arp_opcodes[i],
+ args->arp_opcode))
+ break;
+ if (i == ARP_NUMOPCODES)
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified opcode");
+ cs->arp.arp.arpop = htons(i+1);
+ }
+ }
+ if (args->arp_htype) {
+ if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd,
+ &cs->arp.arp.arhrd_mask, 16)) {
+ if (strcasecmp(args->arp_htype, "Ethernet"))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified hardware type");
+ cs->arp.arp.arhrd = htons(1);
+ }
+ }
+ if (args->arp_ptype) {
+ if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro,
+ &cs->arp.arp.arpro_mask, 0)) {
+ if (strcasecmp(args->arp_ptype, "ipv4"))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified protocol type");
+ cs->arp.arp.arpro = htons(0x800);
+ }
+ }
+}
+
+static void nft_arp_init_cs(struct iptables_command_state *cs)
+{
+ cs->arp.arp.arhln = 6;
+ cs->arp.arp.arhln_mask = 255;
+ cs->arp.arp.arhrd = htons(ARPHRD_ETHER);
+ cs->arp.arp.arhrd_mask = 65535;
+ cs->arp.arp.arpop_mask = 65535;
+ cs->arp.arp.arpro_mask = 65535;
+}
+
+static int
+nft_arp_add_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+ if (append) {
+ ret = nft_cmd_rule_append(h, chain, table, cs,
+ verbose);
+ } else {
+ ret = nft_cmd_rule_insert(h, chain, table, cs,
+ rulenum, verbose);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_arp_delete_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_arp_check_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+ ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_arp_replace_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum)
+{
+ cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr;
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr;
+
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
+static void nft_arp_xlate_mac_and_mask(const struct arpt_devaddr_info *devaddr,
+ const char *addr,
+ bool invert,
+ struct xt_xlate *xl)
+{
+ unsigned int i;
+
+ for (i = 0; i < 6; ++i) {
+ if (devaddr->mask[i])
+ break;
+ }
+
+ if (i == 6)
+ return;
+
+ xt_xlate_add(xl, "arp %s ether ", addr);
+ if (invert)
+ xt_xlate_add(xl, "!= ");
+
+ xt_xlate_add(xl, "%02x", (uint8_t)devaddr->addr[0]);
+ for (i = 1; i < 6; ++i)
+ xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->addr[i]);
+
+ for (i = 0; i < 6; ++i) {
+ int j;
+
+ if ((uint8_t)devaddr->mask[i] == 0xff)
+ continue;
+
+ xt_xlate_add(xl, "/%02x", (uint8_t)devaddr->mask[0]);
+
+ for (j = 1; j < 6; ++j)
+ xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->mask[j]);
+ return;
+ }
+}
+
+static void nft_arp_xlate16(uint16_t v, uint16_t m, const char *what,
+ bool hex, bool inverse,
+ struct xt_xlate *xl)
+{
+ const char *fmt = hex ? "0x%x " : "%d ";
+
+ if (m) {
+ xt_xlate_add(xl, "arp %s ", what);
+ if (inverse)
+ xt_xlate_add(xl, " !=");
+ if (m != 0xffff) {
+ xt_xlate_add(xl, "& ");
+ xt_xlate_add(xl, fmt, ntohs(m));;
+
+ }
+ xt_xlate_add(xl, fmt, ntohs(v));
+ }
+}
+
+static void nft_arp_xlate_ipv4_addr(const char *what, const struct in_addr *addr,
+ const struct in_addr *mask,
+ bool inv, struct xt_xlate *xl)
+{
+ char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN];
+ const char *op = inv ? "!= " : "";
+ int cidr;
+
+ if (!inv && !addr->s_addr && !mask->s_addr)
+ return;
+
+ inet_ntop(AF_INET, addr, abuf, sizeof(abuf));
+
+ cidr = xtables_ipmask_to_cidr(mask);
+ switch (cidr) {
+ case -1:
+ xt_xlate_add(xl, "arp %s ip & %s %s %s ", what,
+ inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)),
+ inv ? "!=" : "==", abuf);
+ break;
+ case 32:
+ xt_xlate_add(xl, "arp %s ip %s%s ", what, op, abuf);
+ break;
+ default:
+ xt_xlate_add(xl, "arp %s ip %s%s/%d ", what, op, abuf, cidr);
+ }
+}
+
+static int nft_arp_xlate(const struct iptables_command_state *cs,
+ struct xt_xlate *xl)
+{
+ const struct arpt_entry *fw = &cs->arp;
+ int ret;
+
+ xlate_ifname(xl, "iifname", fw->arp.iniface,
+ fw->arp.invflags & IPT_INV_VIA_IN);
+ xlate_ifname(xl, "oifname", fw->arp.outiface,
+ fw->arp.invflags & IPT_INV_VIA_OUT);
+
+ if (fw->arp.arhrd ||
+ fw->arp.arhrd_mask != 0xffff ||
+ fw->arp.invflags & IPT_INV_ARPHRD)
+ nft_arp_xlate16(fw->arp.arhrd, fw->arp.arhrd_mask,
+ "htype", false,
+ fw->arp.invflags & IPT_INV_ARPHRD, xl);
+
+ if (fw->arp.arhln_mask != 255 || fw->arp.arhln ||
+ fw->arp.invflags & IPT_INV_ARPHLN) {
+ xt_xlate_add(xl, "arp hlen ");
+ if (fw->arp.invflags & IPT_INV_ARPHLN)
+ xt_xlate_add(xl, " !=");
+ if (fw->arp.arhln_mask != 255)
+ xt_xlate_add(xl, "& %d ", fw->arp.arhln_mask);
+ xt_xlate_add(xl, "%d ", fw->arp.arhln);
+ }
+
+ /* added implicitly by arptables-nft */
+ xt_xlate_add(xl, "arp plen %d", 4);
+
+ if (fw->arp.arpop_mask != 65535 ||
+ fw->arp.arpop != 0 ||
+ fw->arp.invflags & IPT_INV_ARPOP)
+ nft_arp_xlate16(fw->arp.arpop, fw->arp.arpop_mask,
+ "operation", false,
+ fw->arp.invflags & IPT_INV_ARPOP, xl);
+
+ if (fw->arp.arpro_mask != 65535 ||
+ fw->arp.invflags & IPT_INV_PROTO ||
+ fw->arp.arpro)
+ nft_arp_xlate16(fw->arp.arpro, fw->arp.arpro_mask,
+ "ptype", true,
+ fw->arp.invflags & IPT_INV_PROTO, xl);
+
+ if (fw->arp.smsk.s_addr != 0L)
+ nft_arp_xlate_ipv4_addr("saddr", &fw->arp.src, &fw->arp.smsk,
+ fw->arp.invflags & IPT_INV_SRCIP, xl);
+
+ if (fw->arp.tmsk.s_addr != 0L)
+ nft_arp_xlate_ipv4_addr("daddr", &fw->arp.tgt, &fw->arp.tmsk,
+ fw->arp.invflags & IPT_INV_DSTIP, xl);
+
+ nft_arp_xlate_mac_and_mask(&fw->arp.src_devaddr, "saddr",
+ fw->arp.invflags & IPT_INV_SRCDEVADDR, xl);
+ nft_arp_xlate_mac_and_mask(&fw->arp.tgt_devaddr, "daddr",
+ fw->arp.invflags & IPT_INV_TGTDEVADDR, xl);
+
+ ret = xlate_matches(cs, xl);
+ if (!ret)
+ return ret;
+
+ /* Always add counters per rule, as in iptables */
+ xt_xlate_add(xl, "counter");
+ return xlate_action(cs, false, xl);
+}
+
+static const char *nft_arp_option_name(int option)
+{
+ switch (option) {
+ default: return ip46t_option_name(option);
+ /* different name than iptables */
+ case OPT_SOURCE: return "--source-ip";
+ case OPT_DESTINATION: return "--destination-ip";
+ /* arptables specific ones */
+ case OPT_S_MAC: return "--source-mac";
+ case OPT_D_MAC: return "--destination-mac";
+ case OPT_H_LENGTH: return "--h-length";
+ case OPT_OPCODE: return "--opcode";
+ case OPT_H_TYPE: return "--h-type";
+ case OPT_P_TYPE: return "--proto-type";
+ }
+}
+
+static int nft_arp_option_invert(int option)
+{
+ switch (option) {
+ case OPT_S_MAC: return IPT_INV_SRCDEVADDR;
+ case OPT_D_MAC: return IPT_INV_TGTDEVADDR;
+ case OPT_H_LENGTH: return IPT_INV_ARPHLN;
+ case OPT_OPCODE: return IPT_INV_ARPOP;
+ case OPT_H_TYPE: return IPT_INV_ARPHRD;
+ case OPT_P_TYPE: return IPT_INV_PROTO;
+ default: return ip46t_option_invert(option);
+ }
+}
+
struct nft_family_ops nft_family_ops_arp = {
.add = nft_arp_add,
.is_same = nft_arp_is_same,
.print_payload = NULL,
- .parse_meta = nft_arp_parse_meta,
- .parse_payload = nft_arp_parse_payload,
- .parse_immediate = nft_arp_parse_immediate,
.print_header = nft_arp_print_header,
.print_rule = nft_arp_print_rule,
.save_rule = nft_arp_save_rule,
.save_chain = nft_arp_save_chain,
- .post_parse = NULL,
+ .rule_parse = &nft_ruleparse_ops_arp,
+ .cmd_parse = {
+ .post_parse = nft_arp_post_parse,
+ .option_name = nft_arp_option_name,
+ .option_invert = nft_arp_option_invert,
+ .command_default = command_default,
+ .print_help = xtables_printhelp,
+ },
.rule_to_cs = nft_rule_to_iptables_command_state,
- .clear_cs = nft_clear_iptables_command_state,
- .parse_target = nft_ipv46_parse_target,
+ .init_cs = nft_arp_init_cs,
+ .clear_cs = xtables_clear_iptables_command_state,
+ .xlate = nft_arp_xlate,
+ .add_entry = nft_arp_add_entry,
+ .delete_entry = nft_arp_delete_entry,
+ .check_entry = nft_arp_check_entry,
+ .replace_entry = nft_arp_replace_entry,
};
diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h
deleted file mode 100644
index 3411fc3d..00000000
--- a/iptables/nft-arp.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _NFT_ARP_H_
-#define _NFT_ARP_H_
-
-extern char *arp_opcodes[];
-#define NUMOPCODES 9
-
-#endif
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index c1a2c209..922ce983 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -58,131 +58,137 @@ void ebt_cs_clean(struct iptables_command_state *cs)
}
}
-static void ebt_print_mac(const unsigned char *mac)
+/* 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)
{
- int j;
-
- for (j = 0; j < ETH_ALEN; j++)
- printf("%02x%s", mac[j], (j==ETH_ALEN-1) ? "" : ":");
+ if (xtables_print_well_known_mac_and_mask(mac, mask))
+ xtables_print_mac_and_mask(mac, mask);
}
-static bool mac_all_ones(const unsigned char *mac)
+static int add_meta_broute(struct nftnl_rule *r)
{
- static const char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ struct nftnl_expr *expr;
- return memcmp(mac, hlpmsk, sizeof(hlpmsk)) == 0;
-}
+ expr = nftnl_expr_alloc("immediate");
+ if (expr == NULL)
+ return -1;
-/* 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)
-{
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
+ nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
+ nftnl_rule_add_expr(r, expr);
- 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);
- }
- }
+ expr = nftnl_expr_alloc("meta");
+ if (expr == NULL)
+ return -1;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_BRI_BROUTE);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
+
+ nftnl_rule_add_expr(r, expr);
+ return 0;
}
-static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
+static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
{
- int iface_len;
+ const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
- iface_len = strlen(iface);
+ if (cs->target &&
+ table && strcmp(table, "broute") == 0) {
+ if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) {
+ int ret = add_meta_broute(r);
- add_meta(r, NFT_META_BRI_IIFNAME);
- if (iface[iface_len - 1] == '+')
- add_cmp_ptr(r, op, iface, iface_len - 1);
- else
- add_cmp_ptr(r, op, iface, iface_len + 1);
+ if (ret)
+ return ret;
+
+ cs->jumpto = "ACCEPT";
+ }
+ }
+
+ return add_action(r, cs, false);
}
-static void add_logical_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
+static int
+nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw,
+ struct nft_rule_ctx *ctx, struct nftnl_rule *r,
+ struct xt_entry_match *m)
{
- int iface_len;
+ if (!strcmp(m->u.user.name, "802_3") && !(fw->bitmask & EBT_802_3))
+ xtables_error(PARAMETER_PROBLEM,
+ "For 802.3 DSAP/SSAP filtering the protocol must be LENGTH");
- iface_len = strlen(iface);
+ if (!strcmp(m->u.user.name, "ip") && fw->ethproto != htons(ETH_P_IP))
+ xtables_error(PARAMETER_PROBLEM,
+ "For IP filtering the protocol must be specified as IPv4.");
- add_meta(r, NFT_META_BRI_OIFNAME);
- if (iface[iface_len - 1] == '+')
- add_cmp_ptr(r, op, iface, iface_len - 1);
- else
- add_cmp_ptr(r, op, iface, iface_len + 1);
-}
+ if (!strcmp(m->u.user.name, "ip6") && fw->ethproto != htons(ETH_P_IPV6))
+ xtables_error(PARAMETER_PROBLEM,
+ "For IPv6 filtering the protocol must be specified as IPv6.");
-static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
-{
- return add_action(r, cs, false);
+ return add_match(h, ctx, r, m);
}
-static int nft_bridge_add(struct nft_handle *h,
- struct nftnl_rule *r, void *data)
+static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
+ struct nftnl_rule *r,
+ struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct ebt_match *iter;
struct ebt_entry *fw = &cs->eb;
uint32_t op;
+ if (fw->bitmask & EBT_SOURCEMAC) {
+ op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
+ add_addr(h, r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_source),
+ fw->sourcemac, fw->sourcemsk, ETH_ALEN, op);
+ }
+
+ if (fw->bitmask & EBT_DESTMAC) {
+ op = nft_invflags2cmp(fw->invflags, EBT_IDEST);
+ add_addr(h, r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_dest),
+ fw->destmac, fw->destmsk, ETH_ALEN, op);
+ }
+
if (fw->in[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_IIN);
- add_iniface(r, fw->in, op);
+ add_iface(h, r, fw->in, NFT_META_IIFNAME, op);
}
if (fw->out[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_IOUT);
- add_outiface(r, fw->out, op);
+ add_iface(h, r, fw->out, NFT_META_OIFNAME, op);
}
if (fw->logical_in[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN);
- add_logical_iniface(r, fw->logical_in, op);
+ add_iface(h, r, fw->logical_in, NFT_META_BRI_IIFNAME, op);
}
if (fw->logical_out[0] != '\0') {
op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT);
- add_logical_outiface(r, fw->logical_out, op);
- }
-
- if (fw->bitmask & EBT_ISOURCE) {
- op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
- 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_addr(r, NFT_PAYLOAD_LL_HEADER,
- offsetof(struct ethhdr, h_dest),
- fw->destmac, fw->destmsk, ETH_ALEN, op);
+ add_iface(h, r, fw->logical_out, NFT_META_BRI_OIFNAME, op);
}
if ((fw->bitmask & EBT_NOPROTO) == 0) {
+ uint16_t ethproto = fw->ethproto;
+ uint8_t reg;
+
op = nft_invflags2cmp(fw->invflags, EBT_IPROTO);
- add_payload(r, offsetof(struct ethhdr, h_proto), 2,
- NFT_PAYLOAD_LL_HEADER);
- add_cmp_u16(r, fw->ethproto, op);
+ add_payload(h, r, offsetof(struct ethhdr, h_proto), 2,
+ NFT_PAYLOAD_LL_HEADER, &reg);
+
+ if (fw->bitmask & EBT_802_3) {
+ op = (op == NFT_CMP_EQ ? NFT_CMP_LT : NFT_CMP_GTE);
+ ethproto = htons(0x0600);
+ }
+
+ add_cmp_u16(r, ethproto, op, reg);
}
add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO);
for (iter = cs->match_list; iter; iter = iter->next) {
if (iter->ismatch) {
- if (add_match(h, r, iter->u.match->m))
+ if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m))
break;
} else {
if (add_target(r, iter->u.watcher->t))
@@ -196,371 +202,18 @@ static int nft_bridge_add(struct nft_handle *h,
return _add_action(r, cs);
}
-static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
-{
- struct iptables_command_state *cs = data;
- struct ebt_entry *fw = &cs->eb;
- uint8_t invflags = 0;
- char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {};
-
- parse_meta(e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags);
-
- switch (ctx->meta.key) {
- case NFT_META_BRI_IIFNAME:
- if (invflags & IPT_INV_VIA_IN)
- cs->eb.invflags |= EBT_ILOGICALIN;
- snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname);
- break;
- case NFT_META_IIFNAME:
- if (invflags & IPT_INV_VIA_IN)
- cs->eb.invflags |= EBT_IIN;
- snprintf(fw->in, sizeof(fw->in), "%s", iifname);
- break;
- case NFT_META_BRI_OIFNAME:
- if (invflags & IPT_INV_VIA_OUT)
- cs->eb.invflags |= EBT_ILOGICALOUT;
- snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname);
- break;
- case NFT_META_OIFNAME:
- if (invflags & IPT_INV_VIA_OUT)
- cs->eb.invflags |= EBT_IOUT;
- snprintf(fw->out, sizeof(fw->out), "%s", oifname);
- break;
- default:
- break;
- }
-}
-
-static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
-{
- struct iptables_command_state *cs = data;
- struct ebt_entry *fw = &cs->eb;
- unsigned char addr[ETH_ALEN];
- unsigned short int ethproto;
- bool inv;
- int i;
-
- switch (ctx->payload.offset) {
- case offsetof(struct ethhdr, h_dest):
- get_cmp_data(e, addr, sizeof(addr), &inv);
- for (i = 0; i < ETH_ALEN; i++)
- fw->destmac[i] = addr[i];
- if (inv)
- fw->invflags |= EBT_IDEST;
-
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&fw->destmsk, 0xff,
- min(ctx->payload.len, ETH_ALEN));
- }
- fw->bitmask |= EBT_IDEST;
- break;
- case offsetof(struct ethhdr, h_source):
- get_cmp_data(e, addr, sizeof(addr), &inv);
- for (i = 0; i < ETH_ALEN; i++)
- fw->sourcemac[i] = addr[i];
- if (inv)
- fw->invflags |= EBT_ISOURCE;
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&fw->sourcemsk, 0xff,
- min(ctx->payload.len, ETH_ALEN));
- }
- fw->bitmask |= EBT_ISOURCE;
- break;
- case offsetof(struct ethhdr, h_proto):
- get_cmp_data(e, &ethproto, sizeof(ethproto), &inv);
- fw->ethproto = ethproto;
- if (inv)
- fw->invflags |= EBT_IPROTO;
- fw->bitmask &= ~EBT_NOPROTO;
- break;
- }
-}
-
-static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-}
-
-/* return 0 if saddr, 1 if daddr, -1 on error */
-static int
-lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len)
-{
- if (base != 0 || len != ETH_ALEN)
- return -1;
-
- switch (offset) {
- case offsetof(struct ether_header, ether_dhost):
- return 1;
- case offsetof(struct ether_header, ether_shost):
- return 0;
- default:
- return -1;
- }
-}
-
-/* return 0 if saddr, 1 if daddr, -1 on error */
-static int
-lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len)
-{
- if (base != 1 || len != 4)
- return -1;
-
- switch (offset) {
- case offsetof(struct iphdr, daddr):
- return 1;
- case offsetof(struct iphdr, saddr):
- return 0;
- default:
- return -1;
- }
-}
-
-/* Make sure previous payload expression(s) is/are consistent and extract if
- * matching on source or destination address and if matching on MAC and IP or
- * only MAC address. */
-static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx,
- bool *dst, bool *ip)
-{
- int val, val2 = -1;
-
- if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) {
- val = lookup_check_ether_payload(ctx->prev_payload.base,
- ctx->prev_payload.offset,
- ctx->prev_payload.len);
- if (val < 0) {
- DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
- ctx->prev_payload.base, ctx->prev_payload.offset,
- ctx->prev_payload.len);
- return -1;
- }
- if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) {
- DEBUGP("Previous but no current payload?\n");
- return -1;
- }
- val2 = lookup_check_iphdr_payload(ctx->payload.base,
- ctx->payload.offset,
- ctx->payload.len);
- if (val2 < 0) {
- DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
- ctx->payload.base, ctx->payload.offset,
- ctx->payload.len);
- return -1;
- } else if (val != val2) {
- DEBUGP("mismatching payload match offsets\n");
- return -1;
- }
- } else if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
- val = lookup_check_ether_payload(ctx->payload.base,
- ctx->payload.offset,
- ctx->payload.len);
- if (val < 0) {
- DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
- ctx->payload.base, ctx->payload.offset,
- ctx->payload.len);
- return -1;
- }
- } else {
- DEBUGP("unknown LHS of lookup expression\n");
- return -1;
- }
-
- if (dst)
- *dst = (val == 1);
- if (ip)
- *ip = (val2 != -1);
- return 0;
-}
-
-static int set_elems_to_among_pairs(struct nft_among_pair *pairs,
- const struct nftnl_set *s, int cnt)
-{
- struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s);
- struct nftnl_set_elem *elem;
- size_t tmpcnt = 0;
- const void *data;
- uint32_t datalen;
- int ret = -1;
-
- if (!iter) {
- fprintf(stderr, "BUG: set elems iter allocation failed\n");
- return ret;
- }
-
- while ((elem = nftnl_set_elems_iter_next(iter))) {
- data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen);
- if (!data) {
- fprintf(stderr, "BUG: set elem without key\n");
- goto err;
- }
- if (datalen > sizeof(*pairs)) {
- fprintf(stderr, "BUG: overlong set elem\n");
- goto err;
- }
- nft_among_insert_pair(pairs, &tmpcnt, data);
- }
- ret = 0;
-err:
- nftnl_set_elems_iter_destroy(iter);
- return ret;
-}
-
-static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx,
- const struct nftnl_expr *e)
-{
- const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
- uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID);
- struct nftnl_set_list *slist;
- struct nftnl_set *set;
-
- slist = nft_set_list_get(ctx->h, ctx->table, set_name);
- if (slist) {
- set = nftnl_set_list_lookup_byname(slist, set_name);
- if (set)
- return set;
-
- set = nft_set_batch_lookup_byid(ctx->h, set_id);
- if (set)
- return set;
- }
-
- return NULL;
-}
-
-static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
-{
- struct xtables_match *match = NULL;
- struct nft_among_data *among_data;
- bool is_dst, have_ip, inv;
- struct ebt_match *ematch;
- struct nftnl_set *s;
- size_t poff, size;
- uint32_t cnt;
-
- if (lookup_analyze_payloads(ctx, &is_dst, &have_ip))
- return;
-
- s = set_from_lookup_expr(ctx, e);
- if (!s)
- xtables_error(OTHER_PROBLEM,
- "BUG: lookup expression references unknown set");
-
- cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE);
-
- for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) {
- if (!ematch->ismatch || strcmp(ematch->u.match->name, "among"))
- continue;
-
- match = ematch->u.match;
- among_data = (struct nft_among_data *)match->m->data;
-
- size = cnt + among_data->src.cnt + among_data->dst.cnt;
- size *= sizeof(struct nft_among_pair);
-
- size += XT_ALIGN(sizeof(struct xt_entry_match)) +
- sizeof(struct nft_among_data);
-
- match->m = xtables_realloc(match->m, size);
- break;
- }
- if (!match) {
- match = xtables_find_match("among", XTF_TRY_LOAD,
- &ctx->cs->matches);
-
- size = cnt * sizeof(struct nft_among_pair);
- size += XT_ALIGN(sizeof(struct xt_entry_match)) +
- sizeof(struct nft_among_data);
-
- match->m = xtables_calloc(1, size);
- strcpy(match->m->u.user.name, match->name);
- match->m->u.user.revision = match->revision;
- xs_init_match(match);
-
- if (ctx->h->ops->parse_match != NULL)
- ctx->h->ops->parse_match(match, ctx->cs);
- }
- if (!match)
- return;
-
- match->m->u.match_size = size;
-
- inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) &
- NFT_LOOKUP_F_INV);
-
- among_data = (struct nft_among_data *)match->m->data;
- poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip);
- if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt))
- xtables_error(OTHER_PROBLEM,
- "ebtables among pair parsing failed");
-
- ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD);
-}
-
-static void parse_watcher(void *object, struct ebt_match **match_list,
- bool ismatch)
-{
- struct ebt_match *m;
-
- m = calloc(1, sizeof(struct ebt_match));
- if (m == NULL)
- xtables_error(OTHER_PROBLEM, "Can't allocate memory");
-
- if (ismatch)
- m->u.match = object;
- else
- m->u.watcher = object;
-
- m->ismatch = ismatch;
- if (*match_list == NULL)
- *match_list = m;
- else
- (*match_list)->next = m;
-}
-
-static void nft_bridge_parse_match(struct xtables_match *m, void *data)
-{
- struct iptables_command_state *cs = data;
-
- parse_watcher(m, &cs->match_list, true);
-}
-
-static void nft_bridge_parse_target(struct xtables_target *t, void *data)
-{
- struct iptables_command_state *cs = data;
-
- /* harcoded names :-( */
- if (strcmp(t->name, "log") == 0 ||
- strcmp(t->name, "nflog") == 0) {
- parse_watcher(t, &cs->match_list, false);
- return;
- }
-
- cs->target = t;
-}
-
-static void nft_rule_to_ebtables_command_state(struct nft_handle *h,
+static bool nft_rule_to_ebtables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
struct iptables_command_state *cs)
{
cs->eb.bitmask = EBT_NOPROTO;
- nft_rule_to_iptables_command_state(h, r, cs);
+ return nft_rule_to_iptables_command_state(h, r, cs);
}
static void print_iface(const char *option, const char *name, bool invert)
{
if (*name)
- printf("%s%s %s ", option, invert ? " !" : "", name);
+ printf("%s%s %s ", invert ? "! " : "", option, name);
}
static void nft_bridge_print_table_header(const char *tablename)
@@ -571,7 +224,7 @@ static void nft_bridge_print_table_header(const char *tablename)
static void nft_bridge_print_header(unsigned int format, const char *chain,
const char *pol,
const struct xt_counters *counters,
- bool basechain, uint32_t refs, uint32_t entries)
+ int refs, uint32_t entries)
{
printf("Bridge chain: %s, entries: %u, policy: %s\n",
chain, entries, pol ?: "RETURN");
@@ -605,9 +258,7 @@ static void print_mac(char option, const unsigned char *mac,
const unsigned char *mask,
bool invert)
{
- printf("-%c ", option);
- if (invert)
- printf("! ");
+ printf("%s-%c ", invert ? "! " : "", option);
ebt_print_mac_and_mask(mac, mask);
printf(" ");
}
@@ -622,12 +273,10 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
if (bitmask & EBT_NOPROTO)
return;
- printf("-p ");
- if (invert)
- printf("! ");
+ printf("%s-p ", invert ? "! " : "");
if (bitmask & EBT_802_3) {
- printf("length ");
+ printf("Length ");
return;
}
@@ -638,11 +287,10 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
printf("%s ", ent->e_name);
}
-static void nft_bridge_save_rule(const void *data, unsigned int format)
+static void __nft_bridge_save_rule(const struct iptables_command_state *cs,
+ unsigned int format)
{
- const struct iptables_command_state *cs = data;
-
- if (cs->eb.ethproto)
+ if (!(cs->eb.bitmask & EBT_NOPROTO))
print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO,
cs->eb.bitmask);
if (cs->eb.bitmask & EBT_ISOURCE)
@@ -689,16 +337,23 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
fputc('\n', stdout);
}
+static void nft_bridge_save_rule(const struct iptables_command_state *cs,
+ unsigned int format)
+{
+ printf(" ");
+ __nft_bridge_save_rule(cs, format);
+}
+
static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format)
{
struct iptables_command_state cs = {};
if (format & FMT_LINENUMBERS)
- printf("%d ", num);
+ printf("%d. ", num);
nft_rule_to_ebtables_command_state(h, r, &cs);
- nft_bridge_save_rule(&cs, format);
+ __nft_bridge_save_rule(&cs, format);
ebt_cs_clean(&cs);
}
@@ -710,10 +365,11 @@ static void nft_bridge_save_chain(const struct nftnl_chain *c,
printf(":%s %s\n", chain, policy ?: "ACCEPT");
}
-static bool nft_bridge_is_same(const void *data_a, const void *data_b)
+static bool nft_bridge_is_same(const struct iptables_command_state *cs_a,
+ const struct iptables_command_state *cs_b)
{
- const struct ebt_entry *a = data_a;
- const struct ebt_entry *b = data_b;
+ const struct ebt_entry *a = &cs_a->eb;
+ const struct ebt_entry *b = &cs_b->eb;
int i;
if (a->ethproto != b->ethproto ||
@@ -765,7 +421,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl
struct xt_xlate_mt_params mt_params = {
.ip = (const void *)&cs->eb,
.numeric = numeric,
- .escape_quotes = false,
.match = matchp->m,
};
@@ -778,7 +433,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl
struct xt_xlate_tg_params wt_params = {
.ip = (const void *)&cs->eb,
.numeric = numeric,
- .escape_quotes = false,
.target = watcherp->t,
};
@@ -809,7 +463,6 @@ static int xlate_ebaction(const struct iptables_command_state *cs, struct xt_xla
else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
xt_xlate_add(xl, " return");
else if (cs->target->xlate) {
- xt_xlate_add(xl, " ");
struct xt_xlate_tg_params params = {
.ip = (const void *)&cs->eb,
.target = cs->target->t,
@@ -843,25 +496,23 @@ static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool inv
xt_xlate_add(xl, "ether %s %s", type, invert ? "!= " : "");
- xlate_mac(xl, mac);
-
if (memcmp(mask, one_msk, ETH_ALEN)) {
int i;
- xt_xlate_add(xl, " and ");
+ xt_xlate_add(xl, "and");
xlate_mac(xl, mask);
xt_xlate_add(xl, " == %02x", mac[0] & mask[0]);
for (i=1; i < ETH_ALEN; i++)
xt_xlate_add(xl, ":%02x", mac[i] & mask[i]);
+ } else {
+ xlate_mac(xl, mac);
}
-
- xt_xlate_add(xl, " ");
}
-static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
+static int nft_bridge_xlate(const struct iptables_command_state *cs,
+ struct xt_xlate *xl)
{
- const struct iptables_command_state *cs = data;
int ret;
xlate_ifname(xl, "iifname", cs->eb.in,
@@ -873,7 +524,10 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
xlate_ifname(xl, "meta obrname", cs->eb.logical_out,
cs->eb.invflags & EBT_ILOGICALOUT);
- if ((cs->eb.bitmask & EBT_NOPROTO) == 0) {
+ if (cs->eb.bitmask & EBT_802_3) {
+ xt_xlate_add(xl, "ether type %s 0x0600 ",
+ cs->eb.invflags & EBT_IPROTO ? ">=" : "<");
+ } else if ((cs->eb.bitmask & EBT_NOPROTO) == 0) {
const char *implicit = NULL;
switch (ntohs(cs->eb.ethproto)) {
@@ -896,9 +550,6 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
ntohs(cs->eb.ethproto));
}
- if (cs->eb.bitmask & EBT_802_3)
- return 0;
-
if (cs->eb.bitmask & EBT_ISOURCE)
nft_bridge_xlate_mac(xl, "saddr", cs->eb.invflags & EBT_ISOURCE,
cs->eb.sourcemac, cs->eb.sourcemsk);
@@ -916,22 +567,137 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
return ret;
}
+static const char *nft_bridge_option_name(int option)
+{
+ switch (option) {
+ /* ebtables specific ones */
+ case OPT_LOGICALIN: return "--logical-in";
+ case OPT_LOGICALOUT: return "--logical-out";
+ case OPT_LINENUMBERS: return "--Ln";
+ case OPT_LIST_C: return "--Lc";
+ case OPT_LIST_X: return "--Lx";
+ case OPT_LIST_MAC2: return "--Lmac2";
+ default: return ip46t_option_name(option);
+ }
+}
+
+static int nft_bridge_option_invert(int option)
+{
+ switch (option) {
+ case OPT_SOURCE: return EBT_ISOURCE;
+ case OPT_DESTINATION: return EBT_IDEST;
+ case OPT_PROTOCOL: return EBT_IPROTO;
+ case OPT_VIANAMEIN: return EBT_IIN;
+ case OPT_VIANAMEOUT: return EBT_IOUT;
+ case OPT_LOGICALIN: return EBT_ILOGICALIN;
+ case OPT_LOGICALOUT: return EBT_ILOGICALOUT;
+ default: return -1;
+ }
+}
+
+static void nft_bridge_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ char *buffer;
+ int i;
+
+ cs->eb.bitmask &= ~((unsigned int)EBT_NOPROTO);
+
+ i = strtol(cs->protocol, &buffer, 16);
+ if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with the specified protocol");
+ if (*buffer != '\0') {
+ struct xt_ethertypeent *ent;
+
+ if (!strcmp(cs->protocol, "length")) {
+ cs->eb.bitmask |= EBT_802_3;
+ return;
+ }
+ ent = xtables_getethertypebyname(cs->protocol);
+ if (!ent)
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing",
+ cs->protocol);
+ cs->eb.ethproto = ent->e_ethertype;
+ } else
+ cs->eb.ethproto = i;
+
+ if (cs->eb.ethproto < 0x0600)
+ xtables_error(PARAMETER_PROBLEM,
+ "Sorry, protocols have values above or equal to 0x0600");
+}
+
+static void nft_bridge_post_parse(int command,
+ struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ struct ebt_match *match;
+
+ cs->eb.invflags = args->invflags;
+
+ memcpy(cs->eb.in, args->iniface, IFNAMSIZ);
+ memcpy(cs->eb.out, args->outiface, IFNAMSIZ);
+ memcpy(cs->eb.logical_in, args->bri_iniface, IFNAMSIZ);
+ memcpy(cs->eb.logical_out, args->bri_outiface, IFNAMSIZ);
+
+ cs->counters.pcnt = args->pcnt_cnt;
+ cs->counters.bcnt = args->bcnt_cnt;
+
+ if (args->shostnetworkmask) {
+ if (xtables_parse_mac_and_mask(args->shostnetworkmask,
+ cs->eb.sourcemac,
+ cs->eb.sourcemsk))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified source mac '%s'",
+ args->shostnetworkmask);
+ cs->eb.bitmask |= EBT_SOURCEMAC;
+ }
+ if (args->dhostnetworkmask) {
+ if (xtables_parse_mac_and_mask(args->dhostnetworkmask,
+ cs->eb.destmac,
+ cs->eb.destmsk))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified destination mac '%s'",
+ args->dhostnetworkmask);
+ cs->eb.bitmask |= EBT_DESTMAC;
+ }
+
+ if ((cs->options & (OPT_LIST_X | OPT_LINENUMBERS)) ==
+ (OPT_LIST_X | OPT_LINENUMBERS))
+ xtables_error(PARAMETER_PROBLEM,
+ "--Lx is not compatible with --Ln");
+
+ /* So, the extensions can work with the host endian.
+ * The kernel does not have to do this of course */
+ cs->eb.ethproto = htons(cs->eb.ethproto);
+
+ for (match = cs->match_list; match; match = match->next) {
+ if (match->ismatch)
+ continue;
+
+ xtables_option_tfcall(match->u.watcher);
+ }
+}
+
struct nft_family_ops nft_family_ops_bridge = {
.add = nft_bridge_add,
.is_same = nft_bridge_is_same,
.print_payload = NULL,
- .parse_meta = nft_bridge_parse_meta,
- .parse_payload = nft_bridge_parse_payload,
- .parse_immediate = nft_bridge_parse_immediate,
- .parse_lookup = nft_bridge_parse_lookup,
- .parse_match = nft_bridge_parse_match,
- .parse_target = nft_bridge_parse_target,
+ .rule_parse = &nft_ruleparse_ops_bridge,
+ .cmd_parse = {
+ .proto_parse = nft_bridge_proto_parse,
+ .post_parse = nft_bridge_post_parse,
+ .option_name = nft_bridge_option_name,
+ .option_invert = nft_bridge_option_invert,
+ .command_default = ebt_command_default,
+ .print_help = nft_bridge_print_help,
+ },
.print_table_header = nft_bridge_print_table_header,
.print_header = nft_bridge_print_header,
.print_rule = nft_bridge_print_rule,
.save_rule = nft_bridge_save_rule,
.save_chain = nft_bridge_save_chain,
- .post_parse = NULL,
.rule_to_cs = nft_rule_to_ebtables_command_state,
.clear_cs = ebt_cs_clean,
.xlate = nft_bridge_xlate,
diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h
index eb1b3928..13b077fc 100644
--- a/iptables/nft-bridge.h
+++ b/iptables/nft-bridge.h
@@ -8,13 +8,6 @@
#include <net/ethernet.h>
#include <libiptc/libxtc.h>
-/* We use replace->flags, so we can't use the following values:
- * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */
-#define LIST_N 0x04
-#define LIST_C 0x08
-#define LIST_X 0x10
-#define LIST_MAC2 0x20
-
extern unsigned char eb_mac_type_unicast[ETH_ALEN];
extern unsigned char eb_msk_type_unicast[ETH_ALEN];
extern unsigned char eb_mac_type_multicast[ETH_ALEN];
@@ -115,12 +108,12 @@ static inline const char *ebt_target_name(unsigned int verdict)
}) \
void ebt_cs_clean(struct iptables_command_state *cs);
-void ebt_load_match_extensions(void);
void ebt_add_match(struct xtables_match *m,
struct iptables_command_state *cs);
void ebt_add_watcher(struct xtables_target *watcher,
struct iptables_command_state *cs);
-int ebt_command_default(struct iptables_command_state *cs);
+int ebt_command_default(struct iptables_command_state *cs,
+ struct xtables_globals *unused, bool ebt_invert);
struct nft_among_pair {
struct ether_addr ether;
@@ -178,4 +171,7 @@ nft_among_insert_pair(struct nft_among_pair *pairs,
(*pcount)++;
}
+/* from xtables-eb.c */
+void nft_bridge_print_help(struct iptables_command_state *cs);
+
#endif
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index 32cfd6cf..91d29670 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -24,6 +24,15 @@
#include "nft.h"
#include "nft-cache.h"
+#include "nft-chain.h"
+
+/* users may define NDEBUG */
+static void assert_nft_restart(struct nft_handle *h)
+{
+ int rc = nft_restart(h);
+
+ assert(rc >= 0);
+}
static void cache_chain_list_insert(struct list_head *list, const char *name)
{
@@ -39,7 +48,7 @@ static void cache_chain_list_insert(struct list_head *list, const char *name)
}
new = xtables_malloc(sizeof(*new));
- new->name = strdup(name);
+ new->name = xtables_strdup(name);
list_add_tail(&new->head, pos ? &pos->head : list);
}
@@ -55,7 +64,7 @@ void nft_cache_level_set(struct nft_handle *h, int level,
return;
if (!req->table)
- req->table = strdup(cmd->table);
+ req->table = xtables_strdup(cmd->table);
else
assert(!strcmp(req->table, cmd->table));
@@ -104,7 +113,8 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
return;
xtables_error(RESOURCE_PROBLEM,
- "Could not fetch rule set generation id: %s\n", nft_strerror(errno));
+ "Could not fetch rule set generation id: %s",
+ nft_strerror(errno));
}
static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
@@ -140,12 +150,12 @@ static int fetch_table_cache(struct nft_handle *h)
char buf[16536];
int i, ret;
- nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
- NLM_F_DUMP, h->seq);
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
+ NLM_F_DUMP, h->seq);
ret = mnl_talk(h, nlh, nftnl_table_list_cb, h);
if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
+ assert_nft_restart(h);
for (i = 0; i < NFT_TABLE_MAX; i++) {
enum nft_table_type type = h->tables[i].type;
@@ -153,9 +163,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 +173,152 @@ 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;
+}
+
+static int
+nft_cache_add_base_chain(struct nft_handle *h, const struct builtin_table *t,
+ struct nft_chain *nc)
+{
+ uint32_t hooknum = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_HOOKNUM);
+ const char *name = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_NAME);
+ const char *type = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_TYPE);
+ uint32_t prio = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_PRIO);
+ const struct builtin_chain *bc = NULL;
+ int i;
+
+ for (i = 0; i < NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) {
+ if (hooknum == t->chains[i].hook) {
+ bc = &t->chains[i];
+ break;
+ }
+ }
+
+ if (!bc ||
+ prio != bc->prio ||
+ strcmp(name, bc->name) ||
+ strcmp(type, bc->type))
+ return -EINVAL;
+
+ nc->base_slot = &h->cache->table[t->type].base_chains[hooknum];
+ if (*nc->base_slot)
+ return -EEXIST;
+
+ *nc->base_slot = nc;
+ return 0;
+}
+
+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);
+ int ret;
+
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
+ ret = nft_cache_add_base_chain(h, t, nc);
+ if (ret) {
+ h->cache->table[t->type].tainted = true;
+ nft_chain_free(nc);
+ return ret;
+ }
+ } else {
+ list_add_tail(&nc->head,
+ &h->cache->table[t->type].chains->list);
+ }
+ hlist_add_head(&nc->hnode, chain_name_hlist(h, t, cname));
+ return 0;
+}
+
+static void __nft_chain_list_sort(struct list_head *list,
+ int (*cmp)(struct nft_chain *a,
+ struct nft_chain *b))
+{
+ struct nft_chain *pivot, *cur, *sav;
+ LIST_HEAD(sublist);
+
+ if (list_empty(list))
+ return;
+
+ /* grab first item as pivot (dividing) value */
+ pivot = list_entry(list->next, struct nft_chain, head);
+ list_del(&pivot->head);
+
+ /* move any smaller value into sublist */
+ list_for_each_entry_safe(cur, sav, list, head) {
+ if (cmp(pivot, cur) > 0) {
+ list_del(&cur->head);
+ list_add_tail(&cur->head, &sublist);
+ }
+ }
+ /* conquer divided */
+ __nft_chain_list_sort(&sublist, cmp);
+ __nft_chain_list_sort(list, cmp);
+
+ /* merge divided and pivot again */
+ list_add_tail(&pivot->head, &sublist);
+ list_splice(&sublist, list);
+}
+
+static int nft_chain_cmp_byname(struct nft_chain *a, struct nft_chain *b)
+{
+ const char *aname = nftnl_chain_get_str(a->nftnl, NFTNL_CHAIN_NAME);
+ const char *bname = nftnl_chain_get_str(b->nftnl, NFTNL_CHAIN_NAME);
+
+ return strcmp(aname, bname);
+}
+
+int nft_cache_sort_chains(struct nft_handle *h, const char *table)
+{
+ const struct builtin_table *t = nft_table_builtin_find(h, table);
+
+ if (!t)
+ return -1;
+
+ if (h->cache->table[t->type].sorted)
+ return 0;
+
+ __nft_chain_list_sort(&h->cache->table[t->type].chains->list,
+ nft_chain_cmp_byname);
+ h->cache->table[t->type].sorted = true;
+ return 0;
+}
+
struct nftnl_chain_list_cb_data {
struct nft_handle *h;
const struct builtin_table *t;
@@ -174,7 +328,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,9 +349,7 @@ 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);
-
+ nft_cache_add_chain(h, t, c);
return MNL_CB_OK;
out:
nftnl_chain_free(c);
@@ -274,6 +425,7 @@ static int set_fetch_elem_cb(struct nftnl_set *s, void *data)
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nft_handle *h = data;
struct nlmsghdr *nlh;
+ int ret;
if (set_has_elements(s))
return 0;
@@ -282,7 +434,14 @@ static int set_fetch_elem_cb(struct nftnl_set *s, void *data)
NLM_F_DUMP, h->seq);
nftnl_set_elems_nlmsg_build_payload(nlh, s);
- return mnl_talk(h, nlh, set_elem_cb, s);
+ ret = mnl_talk(h, nlh, set_elem_cb, s);
+
+ if (!ret && h->verbose > 1) {
+ fprintf(stdout, "set ");
+ nftnl_set_fprintf(stdout, s, 0, 0);
+ fprintf(stdout, "\n");
+ }
+ return ret;
}
static int fetch_set_cache(struct nft_handle *h,
@@ -311,8 +470,8 @@ static int fetch_set_cache(struct nft_handle *h,
}
}
- nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
- h->family, flags, h->seq);
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
+ h->family, flags, h->seq);
if (s) {
nftnl_set_nlmsg_build_payload(nlh, s);
@@ -321,7 +480,7 @@ static int fetch_set_cache(struct nft_handle *h,
ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d);
if (ret < 0 && errno == EINTR) {
- assert(nft_restart(h) >= 0);
+ assert_nft_restart(h);
return ret;
}
@@ -354,14 +513,14 @@ static int __fetch_chain_cache(struct nft_handle *h,
struct nlmsghdr *nlh;
int ret;
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
- c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
+ c ? NLM_F_ACK : NLM_F_DUMP, h->seq);
if (c)
nftnl_chain_nlmsg_build_payload(nlh, c);
ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d);
if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
+ assert_nft_restart(h);
return ret;
}
@@ -396,9 +555,15 @@ static int fetch_chain_cache(struct nft_handle *h,
return ret;
}
+struct rule_list_cb_data {
+ struct nftnl_chain *chain;
+ int verbose;
+};
+
static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
{
- struct nftnl_chain *c = data;
+ struct rule_list_cb_data *rld = data;
+ struct nftnl_chain *c = rld->chain;
struct nftnl_rule *r;
r = nftnl_rule_alloc();
@@ -410,13 +575,22 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
+ if (rld->verbose > 1) {
+ nftnl_rule_fprintf(stdout, r, 0, 0);
+ fprintf(stdout, "\n");
+ }
nftnl_chain_rule_add_tail(r, c);
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;
+ struct rule_list_cb_data rld = {
+ .chain = c,
+ .verbose = h->verbose,
+ };
char buf[16536];
struct nlmsghdr *nlh;
struct nftnl_rule *rule;
@@ -434,13 +608,13 @@ static int nft_rule_list_update(struct nftnl_chain *c, void *data)
nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN,
nftnl_chain_get_str(c, NFTNL_CHAIN_NAME));
- nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
- NLM_F_DUMP, h->seq);
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
+ NLM_F_DUMP, h->seq);
nftnl_rule_nlmsg_build_payload(nlh, rule);
- ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c);
+ ret = mnl_talk(h, nlh, nftnl_rule_list_cb, &rld);
if (ret < 0 && errno == EINTR)
- assert(nft_restart(h) >= 0);
+ assert_nft_restart(h);
nftnl_rule_free(rule);
@@ -455,21 +629,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 +704,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 +735,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 +758,11 @@ 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);
+ c->table[table->type].sorted = false;
+
if (c->table[table->type].sets)
nftnl_set_list_foreach(c->table[table->type].sets,
__flush_set_cache, NULL);
@@ -595,10 +773,13 @@ 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;
+ c->table[i].sorted = false;
}
+
if (c->table[i].sets) {
nftnl_set_list_free(c->table[i].sets);
c->table[i].sets = NULL;
@@ -689,16 +870,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..29ec6b5c 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -1,8 +1,12 @@
#ifndef _NFT_CACHE_H_
#define _NFT_CACHE_H_
+#include <libnftnl/chain.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 +14,15 @@ 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);
+int nft_cache_sort_chains(struct nft_handle *h, const char *table);
+
+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..9adf1738
--- /dev/null
+++ b/iptables/nft-chain.h
@@ -0,0 +1,30 @@
+#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 nft_chain **base_slot;
+ 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-cmd.c b/iptables/nft-cmd.c
index 5d33f1f0..b38da9bd 100644
--- a/iptables/nft-cmd.c
+++ b/iptables/nft-cmd.c
@@ -11,37 +11,42 @@
#include <stdlib.h>
#include <string.h>
+#include <xtables.h>
#include "nft.h"
#include "nft-cmd.h"
+#include <libnftnl/set.h>
struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
const char *table, const char *chain,
struct iptables_command_state *state,
int rulenum, bool verbose)
{
+ struct nft_rule_ctx ctx = {
+ .command = command,
+ };
struct nftnl_rule *rule;
struct nft_cmd *cmd;
- cmd = calloc(1, sizeof(struct nft_cmd));
- if (!cmd)
- return NULL;
-
+ cmd = xtables_calloc(1, sizeof(struct nft_cmd));
+ cmd->error.lineno = h->error.lineno;
cmd->command = command;
- cmd->table = strdup(table);
+ cmd->table = xtables_strdup(table);
if (chain)
- cmd->chain = strdup(chain);
+ cmd->chain = xtables_strdup(chain);
cmd->rulenum = rulenum;
cmd->verbose = verbose;
if (state) {
- rule = nft_rule_new(h, chain, table, state);
- if (!rule)
+ rule = nft_rule_new(h, &ctx, chain, table, state);
+ if (!rule) {
+ nft_cmd_free(cmd);
return NULL;
+ }
cmd->obj.rule = rule;
if (!state->target && strlen(state->jumpto) > 0)
- cmd->jumpto = strdup(state->jumpto);
+ cmd->jumpto = xtables_strdup(state->jumpto);
}
list_add_tail(&cmd->head, &h->cmd_list);
@@ -60,6 +65,7 @@ void nft_cmd_free(struct nft_cmd *cmd)
switch (cmd->command) {
case NFT_COMPAT_RULE_CHECK:
case NFT_COMPAT_RULE_DELETE:
+ case NFT_COMPAT_RULE_CHANGE_COUNTERS:
if (cmd->obj.rule)
nftnl_rule_free(cmd->obj.rule);
break;
@@ -91,7 +97,7 @@ static void nft_cmd_rule_bridge(struct nft_handle *h, const struct nft_cmd *cmd)
int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
- void *ref, bool verbose)
+ bool verbose)
{
struct nft_cmd *cmd;
@@ -167,7 +173,9 @@ int nft_cmd_rule_flush(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- if (chain || verbose)
+ if (h->family == NFPROTO_BRIDGE)
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+ else if (chain || verbose)
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
else
nft_cache_level_set(h, NFT_CL_TABLES, cmd);
@@ -185,7 +193,7 @@ int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
@@ -205,12 +213,12 @@ int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
return 1;
}
-int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
- const char *table, bool verbose)
+int nft_cmd_chain_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
{
struct nft_cmd *cmd;
- cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_USER_DEL, table, chain, NULL, -1,
+ cmd = nft_cmd_new(h, NFT_COMPAT_CHAIN_DEL, table, chain, NULL, -1,
verbose);
if (!cmd)
return 0;
@@ -218,7 +226,7 @@ int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
/* This triggers nft_bridge_chain_postprocess() when fetching the
* rule cache.
*/
- if (h->family == NFPROTO_BRIDGE)
+ if (h->family == NFPROTO_BRIDGE || !chain)
nft_cache_level_set(h, NFT_CL_RULES, cmd);
else
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
@@ -236,7 +244,7 @@ int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain,
if (!cmd)
return 0;
- cmd->rename = strdup(newname);
+ cmd->rename = xtables_strdup(newname);
nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
@@ -302,7 +310,7 @@ int nft_cmd_chain_set(struct nft_handle *h, const char *table,
if (!cmd)
return 0;
- cmd->policy = strdup(policy);
+ cmd->policy = xtables_strdup(policy);
if (counters)
cmd->counters = *counters;
@@ -317,7 +325,7 @@ int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose)
if (verbose) {
return nft_cmd_rule_flush(h, NULL, table, verbose) &&
- nft_cmd_chain_user_del(h, NULL, table, verbose);
+ nft_cmd_chain_del(h, NULL, table, verbose);
}
cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1,
@@ -387,7 +395,27 @@ int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
if (!cmd)
return 0;
- cmd->policy = strdup(policy);
+ cmd->policy = xtables_strdup(policy);
+
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
+
+ return 1;
+}
+
+int nft_cmd_rule_change_counters(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ int rule_nr, uint8_t counter_op, bool verbose)
+{
+ struct nft_cmd *cmd;
+
+ cmd = nft_cmd_new(h, NFT_COMPAT_RULE_CHANGE_COUNTERS, table, chain,
+ rule_nr == -1 ? cs : NULL, rule_nr, verbose);
+ if (!cmd)
+ return 0;
+
+ cmd->counter_op = counter_op;
+ cmd->counters = cs->counters;
nft_cache_level_set(h, NFT_CL_RULES, cmd);
diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h
index ecf7655a..00ecc802 100644
--- a/iptables/nft-cmd.h
+++ b/iptables/nft-cmd.h
@@ -22,8 +22,12 @@ struct nft_cmd {
} obj;
const char *policy;
struct xt_counters counters;
+ uint8_t counter_op;
const char *rename;
int counters_save;
+ struct {
+ unsigned int lineno;
+ } error;
};
struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
@@ -34,7 +38,7 @@ void nft_cmd_free(struct nft_cmd *cmd);
int nft_cmd_rule_append(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
- void *ref, bool verbose);
+ bool verbose);
int nft_cmd_rule_insert(struct nft_handle *h, const char *chain,
const char *table, struct iptables_command_state *state,
int rulenum, bool verbose);
@@ -49,8 +53,8 @@ int nft_cmd_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_chain_user_add(struct nft_handle *h, const char *chain,
const char *table);
-int nft_cmd_chain_user_del(struct nft_handle *h, const char *chain,
- const char *table, bool verbose);
+int nft_cmd_chain_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose);
int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
const char *table, bool verbose);
int nft_cmd_rule_list(struct nft_handle *h, const char *chain,
@@ -74,6 +78,10 @@ int nft_cmd_rule_list_save(struct nft_handle *h, const char *chain,
const char *table, int rulenum, int counters);
int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy);
+int nft_cmd_rule_change_counters(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ int rule_nr, uint8_t counter_op, bool verbose);
void nft_cmd_table_new(struct nft_handle *h, const char *table);
#endif /* _NFT_CMD_H_ */
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index fdc15c6f..0ce8477f 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -26,60 +26,65 @@
#include "nft.h"
#include "nft-shared.h"
-static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
+static int nft_ipv4_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
+ struct nftnl_rule *r, struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp;
uint32_t op;
int ret;
- if (cs->fw.ip.iniface[0] != '\0') {
- op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_IN);
- add_iniface(r, cs->fw.ip.iniface, op);
- }
-
- if (cs->fw.ip.outiface[0] != '\0') {
- op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_OUT);
- add_outiface(r, cs->fw.ip.outiface, op);
- }
-
- if (cs->fw.ip.proto != 0) {
- op = nft_invflags2cmp(cs->fw.ip.invflags, XT_INV_PROTO);
- add_l4proto(r, cs->fw.ip.proto, op);
- }
-
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, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, 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, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, 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);
}
+
+ if (cs->fw.ip.iniface[0] != '\0') {
+ op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_IN);
+ add_iface(h, r, cs->fw.ip.iniface, NFT_META_IIFNAME, op);
+ }
+
+ if (cs->fw.ip.outiface[0] != '\0') {
+ op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_VIA_OUT);
+ add_iface(h, r, cs->fw.ip.outiface, NFT_META_OIFNAME, op);
+ }
+
+ if (cs->fw.ip.proto != 0) {
+ op = nft_invflags2cmp(cs->fw.ip.invflags, XT_INV_PROTO);
+ add_proto(h, r, offsetof(struct iphdr, protocol),
+ sizeof(uint8_t), cs->fw.ip.proto, op);
+ }
+
if (cs->fw.ip.flags & IPT_F_FRAG) {
- add_payload(r, offsetof(struct iphdr, frag_off), 2,
- NFT_PAYLOAD_NETWORK_HEADER);
+ uint8_t reg;
+
+ add_payload(h, r, offsetof(struct iphdr, frag_off), 2,
+ NFT_PAYLOAD_NETWORK_HEADER, &reg);
/* get the 13 bits that contain the fragment offset */
- add_bitwise_u16(r, htons(0x1fff), 0);
+ add_bitwise_u16(h, r, htons(0x1fff), 0, reg, &reg);
/* if offset is non-zero, this is a fragment */
op = NFT_CMP_NEQ;
if (cs->fw.ip.invflags & IPT_INV_FRAG)
op = NFT_CMP_EQ;
- add_cmp_u16(r, 0, op);
+ add_cmp_u16(r, 0, op, reg);
}
add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) {
- ret = add_match(h, r, matchp->match->m);
+ ret = add_match(h, ctx, r, matchp->match->m);
if (ret < 0)
return ret;
}
@@ -93,12 +98,9 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
return add_action(r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO));
}
-static bool nft_ipv4_is_same(const void *data_a,
- const void *data_b)
+static bool nft_ipv4_is_same(const struct iptables_command_state *a,
+ const struct iptables_command_state *b)
{
- const struct iptables_command_state *a = data_a;
- const struct iptables_command_state *b = data_b;
-
if (a->fw.ip.src.s_addr != b->fw.ip.src.s_addr
|| a->fw.ip.dst.s_addr != b->fw.ip.dst.s_addr
|| a->fw.ip.smsk.s_addr != b->fw.ip.smsk.s_addr
@@ -116,153 +118,9 @@ static bool nft_ipv4_is_same(const void *data_a,
b->fw.ip.iniface_mask, b->fw.ip.outiface_mask);
}
-static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv)
-{
- uint8_t op;
-
- /* we assume correct mask and xor */
- if (!(ctx->flags & NFT_XT_CTX_BITWISE))
- return;
-
- /* we assume correct data */
- op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
- if (op == NFT_CMP_EQ)
- *inv = true;
- else
- *inv = false;
-
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
-}
-
-static const char *mask_to_str(uint32_t mask)
-{
- static char mask_str[sizeof("255.255.255.255")];
- uint32_t bits, hmask = ntohl(mask);
- struct in_addr mask_addr = {
- .s_addr = mask,
- };
- int i;
-
- if (mask == 0xFFFFFFFFU) {
- sprintf(mask_str, "32");
- return mask_str;
- }
-
- i = 32;
- bits = 0xFFFFFFFEU;
- while (--i >= 0 && hmask != bits)
- bits <<= 1;
- if (i >= 0)
- sprintf(mask_str, "%u", i);
- else
- sprintf(mask_str, "%s", inet_ntoa(mask_addr));
-
- return mask_str;
-}
-
-static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data)
+static void nft_ipv4_set_goto_flag(struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
- switch (ctx->meta.key) {
- case NFT_META_L4PROTO:
- cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
- if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
- cs->fw.ip.invflags |= XT_INV_PROTO;
- return;
- default:
- break;
- }
-
- parse_meta(e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
- cs->fw.ip.outiface, cs->fw.ip.outiface_mask,
- &cs->fw.ip.invflags);
-}
-
-static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
-{
- mask->s_addr = ctx->bitwise.mask[0];
-}
-
-static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
-{
- struct iptables_command_state *cs = data;
- struct in_addr addr;
- uint8_t proto;
- bool inv;
-
- switch(ctx->payload.offset) {
- case offsetof(struct iphdr, saddr):
- get_cmp_data(e, &addr, sizeof(addr), &inv);
- cs->fw.ip.src.s_addr = addr.s_addr;
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- parse_mask_ipv4(ctx, &cs->fw.ip.smsk);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&cs->fw.ip.smsk, 0xff,
- min(ctx->payload.len, sizeof(struct in_addr)));
- }
-
- if (inv)
- cs->fw.ip.invflags |= IPT_INV_SRCIP;
- break;
- case offsetof(struct iphdr, daddr):
- get_cmp_data(e, &addr, sizeof(addr), &inv);
- cs->fw.ip.dst.s_addr = addr.s_addr;
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- parse_mask_ipv4(ctx, &cs->fw.ip.dmsk);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&cs->fw.ip.dmsk, 0xff,
- min(ctx->payload.len, sizeof(struct in_addr)));
- }
-
- if (inv)
- cs->fw.ip.invflags |= IPT_INV_DSTIP;
- break;
- case offsetof(struct iphdr, protocol):
- get_cmp_data(e, &proto, sizeof(proto), &inv);
- cs->fw.ip.proto = proto;
- if (inv)
- cs->fw.ip.invflags |= IPT_INV_PROTO;
- break;
- case offsetof(struct iphdr, frag_off):
- cs->fw.ip.flags |= IPT_F_FRAG;
- inv = false;
- get_frag(ctx, e, &inv);
- if (inv)
- cs->fw.ip.invflags |= IPT_INV_FRAG;
- break;
- default:
- DEBUGP("unknown payload offset %d\n", ctx->payload.offset);
- break;
- }
-}
-
-static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-
- if (nft_goto)
- cs->fw.ip.flags |= IPT_F_GOTO;
-}
-
-static void print_fragment(unsigned int flags, unsigned int invflags,
- unsigned int format)
-{
- if (!(format & FMT_OPTIONS))
- return;
-
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout);
- fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
- fputc(' ', stdout);
+ cs->fw.ip.flags |= IPT_F_GOTO;
}
static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
@@ -272,9 +130,9 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_to_iptables_command_state(h, r, &cs);
- print_rule_details(&cs, cs.jumpto, cs.fw.ip.flags,
- cs.fw.ip.invflags, cs.fw.ip.proto, num, format);
- print_fragment(cs.fw.ip.flags, cs.fw.ip.invflags, format);
+ print_rule_details(num, &cs.counters, cs.jumpto, cs.fw.ip.proto,
+ cs.fw.ip.flags, cs.fw.ip.invflags, format);
+ print_fragment(cs.fw.ip.flags, cs.fw.ip.invflags, format, false);
print_ifaces(cs.fw.ip.iniface, cs.fw.ip.outiface, cs.fw.ip.invflags,
format);
print_ipv4_addresses(&cs.fw, format);
@@ -292,100 +150,56 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- nft_clear_iptables_command_state(&cs);
+ xtables_clear_iptables_command_state(&cs);
}
-static void save_ipv4_addr(char letter, const struct in_addr *addr,
- uint32_t mask, int invert)
+static void nft_ipv4_save_rule(const struct iptables_command_state *cs,
+ unsigned int format)
{
- if (!mask && !invert && !addr->s_addr)
- return;
-
- printf("%s-%c %s/%s ", invert ? "! " : "", letter, inet_ntoa(*addr),
- mask_to_str(mask));
-}
-
-static void nft_ipv4_save_rule(const void *data, unsigned int format)
-{
- const struct iptables_command_state *cs = data;
-
- save_ipv4_addr('s', &cs->fw.ip.src, cs->fw.ip.smsk.s_addr,
+ save_ipv4_addr('s', &cs->fw.ip.src, &cs->fw.ip.smsk,
cs->fw.ip.invflags & IPT_INV_SRCIP);
- save_ipv4_addr('d', &cs->fw.ip.dst, cs->fw.ip.dmsk.s_addr,
+ save_ipv4_addr('d', &cs->fw.ip.dst, &cs->fw.ip.dmsk,
cs->fw.ip.invflags & IPT_INV_DSTIP);
- save_rule_details(cs, cs->fw.ip.invflags, cs->fw.ip.proto,
- cs->fw.ip.iniface, cs->fw.ip.iniface_mask,
- cs->fw.ip.outiface, cs->fw.ip.outiface_mask);
-
- if (cs->fw.ip.flags & IPT_F_FRAG) {
- if (cs->fw.ip.invflags & IPT_INV_FRAG)
- printf("! ");
- printf("-f ");
- }
+ save_rule_details(cs->fw.ip.iniface, cs->fw.ip.outiface,
+ cs->fw.ip.proto, cs->fw.ip.flags & IPT_F_FRAG,
+ cs->fw.ip.invflags);
save_matches_and_target(cs, cs->fw.ip.flags & IPT_F_GOTO,
&cs->fw, format);
}
-static void nft_ipv4_proto_parse(struct iptables_command_state *cs,
- struct xtables_args *args)
+static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr,
+ const struct in_addr *mask,
+ bool inv, struct xt_xlate *xl)
{
- cs->fw.ip.proto = args->proto;
- cs->fw.ip.invflags = args->invflags;
-}
+ char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN];
+ const char *op = inv ? "!= " : "";
+ int cidr;
-static void nft_ipv4_post_parse(int command,
- struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- cs->fw.ip.flags = args->flags;
- /* We already set invflags in proto_parse, but we need to refresh it
- * to include new parsed options.
- */
- cs->fw.ip.invflags = args->invflags;
-
- strncpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ);
- memcpy(cs->fw.ip.iniface_mask,
- args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- strncpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ);
- memcpy(cs->fw.ip.outiface_mask,
- args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- if (args->goto_set)
- cs->fw.ip.flags |= IPT_F_GOTO;
+ if (!inv && !addr->s_addr && !mask->s_addr)
+ return;
- cs->counters.pcnt = args->pcnt_cnt;
- cs->counters.bcnt = args->bcnt_cnt;
+ inet_ntop(AF_INET, addr, abuf, sizeof(abuf));
- if (command & (CMD_REPLACE | CMD_INSERT |
- CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs->options & OPT_DESTINATION))
- args->dhostnetworkmask = "0.0.0.0/0";
- if (!(cs->options & OPT_SOURCE))
- args->shostnetworkmask = "0.0.0.0/0";
+ cidr = xtables_ipmask_to_cidr(mask);
+ switch (cidr) {
+ case -1:
+ xt_xlate_add(xl, "%s & %s %s %s ", selector,
+ inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)),
+ inv ? "!=" : "==", abuf);
+ break;
+ case 32:
+ xt_xlate_add(xl, "%s %s%s ", selector, op, abuf);
+ break;
+ default:
+ xt_xlate_add(xl, "%s %s%s/%d ", selector, op, abuf, cidr);
}
-
- if (args->shostnetworkmask)
- xtables_ipparse_multiple(args->shostnetworkmask,
- &args->s.addr.v4, &args->s.mask.v4,
- &args->s.naddrs);
- if (args->dhostnetworkmask)
- xtables_ipparse_multiple(args->dhostnetworkmask,
- &args->d.addr.v4, &args->d.mask.v4,
- &args->d.naddrs);
-
- if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
- (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM,
- "! not allowed with multiple"
- " source or destination IP addresses");
}
-static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
+static int nft_ipv4_xlate(const struct iptables_command_state *cs,
+ struct xt_xlate *xl)
{
- const struct iptables_command_state *cs = data;
const char *comment;
int ret;
@@ -400,35 +214,23 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
}
if (cs->fw.ip.proto != 0) {
- const struct protoent *pent =
- getprotobynumber(cs->fw.ip.proto);
- char protonum[sizeof("65535")];
- const char *name = protonum;
-
- snprintf(protonum, sizeof(protonum), "%u",
- cs->fw.ip.proto);
-
- if (!pent || !xlate_find_match(cs, pent->p_name)) {
- if (pent)
- name = pent->p_name;
- xt_xlate_add(xl, "ip protocol %s%s ",
- cs->fw.ip.invflags & IPT_INV_PROTO ?
- "!= " : "", name);
+ const char *pname = proto_to_name(cs->fw.ip.proto, 0);
+
+ if (!pname || !xlate_find_match(cs, pname)) {
+ xt_xlate_add(xl, "ip protocol");
+ if (cs->fw.ip.invflags & IPT_INV_PROTO)
+ xt_xlate_add(xl, " !=");
+ if (pname)
+ xt_xlate_add(xl, "%s", pname);
+ else
+ xt_xlate_add(xl, "%hu", cs->fw.ip.proto);
}
}
- if (cs->fw.ip.src.s_addr != 0) {
- xt_xlate_add(xl, "ip saddr %s%s%s ",
- cs->fw.ip.invflags & IPT_INV_SRCIP ? "!= " : "",
- inet_ntoa(cs->fw.ip.src),
- xtables_ipmask_to_numeric(&cs->fw.ip.smsk));
- }
- if (cs->fw.ip.dst.s_addr != 0) {
- xt_xlate_add(xl, "ip daddr %s%s%s ",
- cs->fw.ip.invflags & IPT_INV_DSTIP ? "!= " : "",
- inet_ntoa(cs->fw.ip.dst),
- xtables_ipmask_to_numeric(&cs->fw.ip.dmsk));
- }
+ xlate_ipv4_addr("ip saddr", &cs->fw.ip.src, &cs->fw.ip.smsk,
+ cs->fw.ip.invflags & IPT_INV_SRCIP, xl);
+ xlate_ipv4_addr("ip daddr", &cs->fw.ip.dst, &cs->fw.ip.dmsk,
+ cs->fw.ip.invflags & IPT_INV_DSTIP, xl);
ret = xlate_matches(cs, xl);
if (!ret)
@@ -445,20 +247,117 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
return ret;
}
+static int
+nft_ipv4_add_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr;
+ cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr;
+
+ if (append) {
+ ret = nft_cmd_rule_append(h, chain, table,
+ cs, verbose);
+ } else {
+ ret = nft_cmd_rule_insert(h, chain, table,
+ cs, rulenum, verbose);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv4_delete_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr;
+ cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr;
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv4_check_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr;
+ cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr;
+ ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv4_replace_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum)
+{
+ cs->fw.ip.src.s_addr = args->s.addr.v4->s_addr;
+ cs->fw.ip.dst.s_addr = args->d.addr.v4->s_addr;
+ cs->fw.ip.smsk.s_addr = args->s.mask.v4->s_addr;
+ cs->fw.ip.dmsk.s_addr = args->d.mask.v4->s_addr;
+
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
struct nft_family_ops nft_family_ops_ipv4 = {
.add = nft_ipv4_add,
.is_same = nft_ipv4_is_same,
- .parse_meta = nft_ipv4_parse_meta,
- .parse_payload = nft_ipv4_parse_payload,
- .parse_immediate = nft_ipv4_parse_immediate,
+ .set_goto_flag = nft_ipv4_set_goto_flag,
.print_header = print_header,
.print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule,
.save_chain = nft_ipv46_save_chain,
- .proto_parse = nft_ipv4_proto_parse,
- .post_parse = nft_ipv4_post_parse,
- .parse_target = nft_ipv46_parse_target,
+ .rule_parse = &nft_ruleparse_ops_ipv4,
+ .cmd_parse = {
+ .proto_parse = ipv4_proto_parse,
+ .post_parse = ipv4_post_parse,
+ .option_name = ip46t_option_name,
+ .option_invert = ip46t_option_invert,
+ .command_default = command_default,
+ .print_help = xtables_printhelp,
+ },
.rule_to_cs = nft_rule_to_iptables_command_state,
- .clear_cs = nft_clear_iptables_command_state,
+ .clear_cs = xtables_clear_iptables_command_state,
.xlate = nft_ipv4_xlate,
+ .add_entry = nft_ipv4_add_entry,
+ .delete_entry = nft_ipv4_delete_entry,
+ .check_entry = nft_ipv4_check_entry,
+ .replace_entry = nft_ipv4_replace_entry,
};
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index 130ad3e6..c371ba8c 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -25,50 +25,52 @@
#include "nft.h"
#include "nft-shared.h"
-static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
+static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
+ struct nftnl_rule *r, struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
struct xtables_rule_match *matchp;
uint32_t op;
int ret;
- if (cs->fw6.ipv6.iniface[0] != '\0') {
- op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN);
- add_iniface(r, cs->fw6.ipv6.iniface, op);
- }
-
- if (cs->fw6.ipv6.outiface[0] != '\0') {
- op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT);
- add_outiface(r, cs->fw6.ipv6.outiface, op);
- }
-
- if (cs->fw6.ipv6.proto != 0) {
- op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO);
- add_l4proto(r, cs->fw6.ipv6.proto, op);
- }
-
if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src) ||
!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, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct ip6_hdr, ip6_src),
&cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
sizeof(struct in6_addr), op);
}
+
if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst) ||
!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, NFT_PAYLOAD_NETWORK_HEADER,
+ add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
offsetof(struct ip6_hdr, ip6_dst),
&cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
sizeof(struct in6_addr), op);
}
+
+ if (cs->fw6.ipv6.iniface[0] != '\0') {
+ op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN);
+ add_iface(h, r, cs->fw6.ipv6.iniface, NFT_META_IIFNAME, op);
+ }
+
+ if (cs->fw6.ipv6.outiface[0] != '\0') {
+ op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT);
+ add_iface(h, r, cs->fw6.ipv6.outiface, NFT_META_OIFNAME, op);
+ }
+
+ if (cs->fw6.ipv6.proto != 0) {
+ op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO);
+ add_l4proto(h, r, cs->fw6.ipv6.proto, op);
+ }
+
add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO);
for (matchp = cs->matches; matchp; matchp = matchp->next) {
- ret = add_match(h, r, matchp->match->m);
+ ret = add_match(h, ctx, r, matchp->match->m);
if (ret < 0)
return ret;
}
@@ -82,12 +84,9 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
return add_action(r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO));
}
-static bool nft_ipv6_is_same(const void *data_a,
- const void *data_b)
+static bool nft_ipv6_is_same(const struct iptables_command_state *a,
+ const struct iptables_command_state *b)
{
- const struct iptables_command_state *a = data_a;
- const struct iptables_command_state *b = data_b;
-
if (memcmp(a->fw6.ipv6.src.s6_addr, b->fw6.ipv6.src.s6_addr,
sizeof(struct in6_addr)) != 0
|| memcmp(a->fw6.ipv6.dst.s6_addr, b->fw6.ipv6.dst.s6_addr,
@@ -107,88 +106,9 @@ static bool nft_ipv6_is_same(const void *data_a,
b->fw6.ipv6.outiface_mask);
}
-static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data)
+static void nft_ipv6_set_goto_flag(struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
- switch (ctx->meta.key) {
- case NFT_META_L4PROTO:
- cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
- if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
- cs->fw6.ipv6.invflags |= XT_INV_PROTO;
- return;
- default:
- break;
- }
-
- parse_meta(e, ctx->meta.key, cs->fw6.ipv6.iniface,
- cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface,
- cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags);
-}
-
-static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask)
-{
- memcpy(mask, ctx->bitwise.mask, sizeof(struct in6_addr));
-}
-
-static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
-{
- struct iptables_command_state *cs = data;
- struct in6_addr addr;
- uint8_t proto;
- bool inv;
-
- switch (ctx->payload.offset) {
- case offsetof(struct ip6_hdr, ip6_src):
- get_cmp_data(e, &addr, sizeof(addr), &inv);
- memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&cs->fw6.ipv6.smsk, 0xff,
- min(ctx->payload.len, sizeof(struct in6_addr)));
- }
-
- if (inv)
- cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP;
- break;
- case offsetof(struct ip6_hdr, ip6_dst):
- get_cmp_data(e, &addr, sizeof(addr), &inv);
- memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
- if (ctx->flags & NFT_XT_CTX_BITWISE) {
- parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk);
- ctx->flags &= ~NFT_XT_CTX_BITWISE;
- } else {
- memset(&cs->fw6.ipv6.dmsk, 0xff,
- min(ctx->payload.len, sizeof(struct in6_addr)));
- }
-
- if (inv)
- cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP;
- break;
- case offsetof(struct ip6_hdr, ip6_nxt):
- get_cmp_data(e, &proto, sizeof(proto), &inv);
- cs->fw6.ipv6.proto = proto;
- if (inv)
- cs->fw6.ipv6.invflags |= IP6T_INV_PROTO;
- default:
- DEBUGP("unknown payload offset %d\n", ctx->payload.offset);
- break;
- }
-}
-
-static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-
- if (nft_goto)
- cs->fw6.ipv6.flags |= IP6T_F_GOTO;
+ cs->fw6.ipv6.flags |= IP6T_F_GOTO;
}
static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
@@ -198,14 +118,9 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_to_iptables_command_state(h, r, &cs);
- print_rule_details(&cs, cs.jumpto, cs.fw6.ipv6.flags,
- cs.fw6.ipv6.invflags, cs.fw6.ipv6.proto,
- num, format);
- if (format & FMT_OPTIONS) {
- if (format & FMT_NOTABLE)
- fputs("opt ", stdout);
- fputs(" ", stdout);
- }
+ print_rule_details(num, &cs.counters, cs.jumpto, cs.fw6.ipv6.proto,
+ cs.fw6.ipv6.flags, cs.fw6.ipv6.invflags, format);
+ print_fragment(cs.fw6.ipv6.flags, cs.fw6.ipv6.invflags, format, true);
print_ifaces(cs.fw6.ipv6.iniface, cs.fw6.ipv6.outiface,
cs.fw6.ipv6.invflags, format);
print_ipv6_addresses(&cs.fw6, format);
@@ -221,135 +136,54 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
- nft_clear_iptables_command_state(&cs);
-}
-
-static void save_ipv6_addr(char letter, const struct in6_addr *addr,
- const struct in6_addr *mask,
- int invert)
-{
- char addr_str[INET6_ADDRSTRLEN];
- int l = xtables_ip6mask_to_cidr(mask);
-
- if (!invert && l == 0)
- return;
-
- printf("%s-%c %s",
- invert ? "! " : "", letter,
- inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str)));
-
- if (l == -1)
- printf("/%s ", inet_ntop(AF_INET6, mask, addr_str, sizeof(addr_str)));
- else
- printf("/%d ", l);
+ xtables_clear_iptables_command_state(&cs);
}
-static void nft_ipv6_save_rule(const void *data, unsigned int format)
+static void nft_ipv6_save_rule(const struct iptables_command_state *cs,
+ unsigned int format)
{
- const struct iptables_command_state *cs = data;
-
save_ipv6_addr('s', &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
cs->fw6.ipv6.invflags & IP6T_INV_SRCIP);
save_ipv6_addr('d', &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
cs->fw6.ipv6.invflags & IP6T_INV_DSTIP);
- save_rule_details(cs, cs->fw6.ipv6.invflags, cs->fw6.ipv6.proto,
- cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask,
- cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask);
+ save_rule_details(cs->fw6.ipv6.iniface, cs->fw6.ipv6.outiface,
+ cs->fw6.ipv6.proto, 0, cs->fw6.ipv6.invflags);
save_matches_and_target(cs, cs->fw6.ipv6.flags & IP6T_F_GOTO,
&cs->fw6, format);
}
-/* These are invalid numbers as upper layer protocol */
-static int is_exthdr(uint16_t proto)
-{
- return (proto == IPPROTO_ROUTING ||
- proto == IPPROTO_FRAGMENT ||
- proto == IPPROTO_AH ||
- proto == IPPROTO_DSTOPTS);
-}
-
-static void nft_ipv6_proto_parse(struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- cs->fw6.ipv6.proto = args->proto;
- cs->fw6.ipv6.invflags = args->invflags;
-
- if (is_exthdr(cs->fw6.ipv6.proto)
- && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0)
- fprintf(stderr,
- "Warning: never matched protocol: %s. "
- "use extension match instead.\n",
- cs->protocol);
-}
-
-static void nft_ipv6_post_parse(int command, struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- cs->fw6.ipv6.flags = args->flags;
- /* We already set invflags in proto_parse, but we need to refresh it
- * to include new parsed options.
- */
- cs->fw6.ipv6.invflags = args->invflags;
-
- strncpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ);
- memcpy(cs->fw6.ipv6.iniface_mask,
- args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- strncpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ);
- memcpy(cs->fw6.ipv6.outiface_mask,
- args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
-
- if (args->goto_set)
- cs->fw6.ipv6.flags |= IP6T_F_GOTO;
-
- cs->fw6.counters.pcnt = args->pcnt_cnt;
- cs->fw6.counters.bcnt = args->bcnt_cnt;
-
- if (command & (CMD_REPLACE | CMD_INSERT |
- CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs->options & OPT_DESTINATION))
- args->dhostnetworkmask = "::0/0";
- if (!(cs->options & OPT_SOURCE))
- args->shostnetworkmask = "::0/0";
- }
-
- if (args->shostnetworkmask)
- xtables_ip6parse_multiple(args->shostnetworkmask,
- &args->s.addr.v6,
- &args->s.mask.v6,
- &args->s.naddrs);
- if (args->dhostnetworkmask)
- xtables_ip6parse_multiple(args->dhostnetworkmask,
- &args->d.addr.v6,
- &args->d.mask.v6,
- &args->d.naddrs);
-
- if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
- (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM,
- "! not allowed with multiple"
- " source or destination IP addresses");
-}
-
static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr,
const struct in6_addr *mask,
int invert, struct xt_xlate *xl)
{
+ const char *op = invert ? "!= " : "";
char addr_str[INET6_ADDRSTRLEN];
+ int cidr;
- if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr))
+ if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr) && IN6_IS_ADDR_UNSPECIFIED(mask))
return;
inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
- xt_xlate_add(xl, "%s %s%s%s ", selector, invert ? "!= " : "", addr_str,
- xtables_ip6mask_to_numeric(mask));
+ cidr = xtables_ip6mask_to_cidr(mask);
+ switch (cidr) {
+ case -1:
+ xt_xlate_add(xl, "%s & %s %s %s ", selector,
+ xtables_ip6addr_to_numeric(mask),
+ invert ? "!=" : "==", addr_str);
+ break;
+ case 128:
+ xt_xlate_add(xl, "%s %s%s ", selector, op, addr_str);
+ break;
+ default:
+ xt_xlate_add(xl, "%s %s%s/%d ", selector, op, addr_str, cidr);
+ }
}
-static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
+static int nft_ipv6_xlate(const struct iptables_command_state *cs,
+ struct xt_xlate *xl)
{
- const struct iptables_command_state *cs = data;
const char *comment;
int ret;
@@ -359,22 +193,17 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
cs->fw6.ipv6.invflags & IP6T_INV_VIA_OUT);
if (cs->fw6.ipv6.proto != 0) {
- const struct protoent *pent =
- getprotobynumber(cs->fw6.ipv6.proto);
- char protonum[sizeof("65535")];
- const char *name = protonum;
-
- snprintf(protonum, sizeof(protonum), "%u",
- cs->fw6.ipv6.proto);
-
- if (!pent || !xlate_find_match(cs, pent->p_name)) {
- if (pent)
- name = pent->p_name;
- xt_xlate_add(xl, "meta l4proto %s%s ",
- cs->fw6.ipv6.invflags & IP6T_INV_PROTO ?
- "!= " : "", name);
+ const char *pname = proto_to_name(cs->fw6.ipv6.proto, 0);
+
+ if (!pname || !xlate_find_match(cs, pname)) {
+ xt_xlate_add(xl, "meta l4proto");
+ if (cs->fw6.ipv6.invflags & IP6T_INV_PROTO)
+ xt_xlate_add(xl, " !=");
+ if (pname)
+ xt_xlate_add(xl, "%s", pname);
+ else
+ xt_xlate_add(xl, "%hu", cs->fw6.ipv6.proto);
}
-
}
xlate_ipv6_addr("ip6 saddr", &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
@@ -397,20 +226,128 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
return ret;
}
+static int
+nft_ipv6_add_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ memcpy(&cs->fw6.ipv6.src,
+ &args->s.addr.v6[i], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk,
+ &args->s.mask.v6[i], sizeof(struct in6_addr));
+ for (j = 0; j < args->d.naddrs; j++) {
+ memcpy(&cs->fw6.ipv6.dst,
+ &args->d.addr.v6[j], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk,
+ &args->d.mask.v6[j], sizeof(struct in6_addr));
+ if (append) {
+ ret = nft_cmd_rule_append(h, chain, table,
+ cs, verbose);
+ } else {
+ ret = nft_cmd_rule_insert(h, chain, table,
+ cs, rulenum, verbose);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv6_delete_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ memcpy(&cs->fw6.ipv6.src,
+ &args->s.addr.v6[i], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk,
+ &args->s.mask.v6[i], sizeof(struct in6_addr));
+ for (j = 0; j < args->d.naddrs; j++) {
+ memcpy(&cs->fw6.ipv6.dst,
+ &args->d.addr.v6[j], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk,
+ &args->d.mask.v6[j], sizeof(struct in6_addr));
+ ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv6_check_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose)
+{
+ unsigned int i, j;
+ int ret = 1;
+
+ for (i = 0; i < args->s.naddrs; i++) {
+ memcpy(&cs->fw6.ipv6.src,
+ &args->s.addr.v6[i], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk,
+ &args->s.mask.v6[i], sizeof(struct in6_addr));
+ for (j = 0; j < args->d.naddrs; j++) {
+ memcpy(&cs->fw6.ipv6.dst,
+ &args->d.addr.v6[j], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk,
+ &args->d.mask.v6[j], sizeof(struct in6_addr));
+ ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nft_ipv6_replace_entry(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum)
+{
+ memcpy(&cs->fw6.ipv6.src, args->s.addr.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dst, args->d.addr.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk, args->s.mask.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk, args->d.mask.v6, sizeof(struct in6_addr));
+
+ return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
struct nft_family_ops nft_family_ops_ipv6 = {
.add = nft_ipv6_add,
.is_same = nft_ipv6_is_same,
- .parse_meta = nft_ipv6_parse_meta,
- .parse_payload = nft_ipv6_parse_payload,
- .parse_immediate = nft_ipv6_parse_immediate,
+ .set_goto_flag = nft_ipv6_set_goto_flag,
.print_header = print_header,
.print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule,
.save_chain = nft_ipv46_save_chain,
- .proto_parse = nft_ipv6_proto_parse,
- .post_parse = nft_ipv6_post_parse,
- .parse_target = nft_ipv46_parse_target,
+ .rule_parse = &nft_ruleparse_ops_ipv6,
+ .cmd_parse = {
+ .proto_parse = ipv6_proto_parse,
+ .post_parse = ipv6_post_parse,
+ .option_name = ip46t_option_name,
+ .option_invert = ip46t_option_invert,
+ .command_default = command_default,
+ .print_help = xtables_printhelp,
+ },
.rule_to_cs = nft_rule_to_iptables_command_state,
- .clear_cs = nft_clear_iptables_command_state,
+ .clear_cs = xtables_clear_iptables_command_state,
.xlate = nft_ipv6_xlate,
+ .add_entry = nft_ipv6_add_entry,
+ .delete_entry = nft_ipv6_delete_entry,
+ .check_entry = nft_ipv6_check_entry,
+ .replace_entry = nft_ipv6_replace_entry,
};
diff --git a/iptables/nft-ruleparse-arp.c b/iptables/nft-ruleparse-arp.c
new file mode 100644
index 00000000..b0671cb0
--- /dev/null
+++ b/iptables/nft-ruleparse-arp.c
@@ -0,0 +1,174 @@
+/*
+ * (C) 2013 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2013 by Giuseppe Longo <giuseppelng@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/if_ether.h>
+
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+#include "nft-shared.h"
+#include "nft-ruleparse.h"
+#include "xshared.h"
+
+static void nft_arp_parse_meta(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct arpt_entry *fw = &cs->arp;
+ uint8_t flags = 0;
+
+ if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface,
+ fw->arp.outiface, &flags) == 0) {
+ fw->arp.invflags |= flags;
+ return;
+ }
+
+ ctx->errmsg = "Unknown arp meta key";
+}
+
+static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask)
+{
+ mask->s_addr = reg->bitwise.mask[0];
+}
+
+static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct arpt_devaddr_info *info)
+{
+ uint32_t hlen;
+ bool inv;
+
+ nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen);
+
+ if (hlen != ETH_ALEN)
+ return false;
+
+ get_cmp_data(e, info->addr, ETH_ALEN, &inv);
+
+ if (reg->bitwise.set)
+ memcpy(info->mask, reg->bitwise.mask, ETH_ALEN);
+ else
+ memset(info->mask, 0xff,
+ min(reg->payload.len, ETH_ALEN));
+
+ return inv;
+}
+
+static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct arpt_entry *fw = &cs->arp;
+ struct in_addr addr;
+ uint16_t ar_hrd, ar_pro, ar_op;
+ uint8_t ar_hln, ar_pln;
+ bool inv;
+
+ switch (reg->payload.offset) {
+ case offsetof(struct arphdr, ar_hrd):
+ get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
+ fw->arp.arhrd = ar_hrd;
+ fw->arp.arhrd_mask = 0xffff;
+ if (inv)
+ fw->arp.invflags |= IPT_INV_ARPHRD;
+ if (reg->bitwise.set)
+ fw->arp.arhrd_mask = reg->bitwise.mask[0];
+ 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 |= IPT_INV_PROTO;
+ if (reg->bitwise.set)
+ fw->arp.arpro_mask = reg->bitwise.mask[0];
+ 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 |= IPT_INV_ARPOP;
+ if (reg->bitwise.set)
+ fw->arp.arpop_mask = reg->bitwise.mask[0];
+ 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 |= IPT_INV_ARPHLN;
+ if (reg->bitwise.set)
+ fw->arp.arhln_mask = reg->bitwise.mask[0];
+ break;
+ case offsetof(struct arphdr, ar_pln):
+ get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv);
+ if (ar_pln != 4 || inv)
+ ctx->errmsg = "unexpected ARP protocol length match";
+ break;
+ default:
+ if (reg->payload.offset == sizeof(struct arphdr)) {
+ if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr))
+ fw->arp.invflags |= IPT_INV_SRCDEVADDR;
+ } else if (reg->payload.offset == sizeof(struct arphdr) +
+ fw->arp.arhln) {
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
+ fw->arp.src.s_addr = addr.s_addr;
+ if (reg->bitwise.set)
+ parse_mask_ipv4(reg, &fw->arp.smsk);
+ else
+ memset(&fw->arp.smsk, 0xff,
+ min(reg->payload.len,
+ sizeof(struct in_addr)));
+
+ if (inv)
+ fw->arp.invflags |= IPT_INV_SRCIP;
+ } else if (reg->payload.offset == sizeof(struct arphdr) +
+ fw->arp.arhln +
+ sizeof(struct in_addr)) {
+ if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr))
+ fw->arp.invflags |= IPT_INV_TGTDEVADDR;
+ } else if (reg->payload.offset == sizeof(struct arphdr) +
+ fw->arp.arhln +
+ sizeof(struct in_addr) +
+ fw->arp.arhln) {
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
+ fw->arp.tgt.s_addr = addr.s_addr;
+ if (reg->bitwise.set)
+ parse_mask_ipv4(reg, &fw->arp.tmsk);
+ else
+ memset(&fw->arp.tmsk, 0xff,
+ min(reg->payload.len,
+ sizeof(struct in_addr)));
+
+ if (inv)
+ fw->arp.invflags |= IPT_INV_DSTIP;
+ } else {
+ ctx->errmsg = "unknown payload offset";
+ }
+ break;
+ }
+}
+
+struct nft_ruleparse_ops nft_ruleparse_ops_arp = {
+ .meta = nft_arp_parse_meta,
+ .payload = nft_arp_parse_payload,
+};
diff --git a/iptables/nft-ruleparse-bridge.c b/iptables/nft-ruleparse-bridge.c
new file mode 100644
index 00000000..aee08b13
--- /dev/null
+++ b/iptables/nft-ruleparse-bridge.c
@@ -0,0 +1,422 @@
+/*
+ * (C) 2014 by Giuseppe Longo <giuseppelng@gmail.com>
+ *
+ * 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 <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <net/if.h>
+//#include <net/if_arp.h>
+#include <netinet/if_ether.h>
+
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/set.h>
+
+#include <xtables.h>
+
+#include "nft.h" /* just for nft_set_batch_lookup_byid? */
+#include "nft-bridge.h"
+#include "nft-cache.h"
+#include "nft-shared.h"
+#include "nft-ruleparse.h"
+#include "xshared.h"
+
+static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct ebt_entry *fw = &cs->eb;
+ uint8_t invflags = 0;
+ char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {};
+
+ switch (reg->meta_dreg.key) {
+ case NFT_META_PROTOCOL:
+ return;
+ }
+
+ if (parse_meta(ctx, e, reg->meta_dreg.key,
+ iifname, oifname, &invflags) < 0) {
+ ctx->errmsg = "unknown meta key";
+ return;
+ }
+
+ switch (reg->meta_dreg.key) {
+ case NFT_META_BRI_IIFNAME:
+ if (invflags & IPT_INV_VIA_IN)
+ cs->eb.invflags |= EBT_ILOGICALIN;
+ snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname);
+ break;
+ case NFT_META_IIFNAME:
+ if (invflags & IPT_INV_VIA_IN)
+ cs->eb.invflags |= EBT_IIN;
+ snprintf(fw->in, sizeof(fw->in), "%s", iifname);
+ break;
+ case NFT_META_BRI_OIFNAME:
+ if (invflags & IPT_INV_VIA_OUT)
+ cs->eb.invflags |= EBT_ILOGICALOUT;
+ snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname);
+ break;
+ case NFT_META_OIFNAME:
+ if (invflags & IPT_INV_VIA_OUT)
+ cs->eb.invflags |= EBT_IOUT;
+ snprintf(fw->out, sizeof(fw->out), "%s", oifname);
+ break;
+ default:
+ ctx->errmsg = "unknown bridge meta key";
+ break;
+ }
+}
+
+static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct ebt_entry *fw = &cs->eb;
+ unsigned char addr[ETH_ALEN];
+ unsigned short int ethproto;
+ uint8_t op;
+ bool inv;
+ int i;
+
+ switch (reg->payload.offset) {
+ case offsetof(struct ethhdr, h_dest):
+ get_cmp_data(e, addr, sizeof(addr), &inv);
+ for (i = 0; i < ETH_ALEN; i++)
+ fw->destmac[i] = addr[i];
+ if (inv)
+ fw->invflags |= EBT_IDEST;
+
+ if (reg->bitwise.set)
+ memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN);
+ else
+ memset(&fw->destmsk, 0xff,
+ min(reg->payload.len, ETH_ALEN));
+ fw->bitmask |= EBT_IDEST;
+ break;
+ case offsetof(struct ethhdr, h_source):
+ get_cmp_data(e, addr, sizeof(addr), &inv);
+ for (i = 0; i < ETH_ALEN; i++)
+ fw->sourcemac[i] = addr[i];
+ if (inv)
+ fw->invflags |= EBT_ISOURCE;
+ if (reg->bitwise.set)
+ memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN);
+ else
+ memset(&fw->sourcemsk, 0xff,
+ min(reg->payload.len, ETH_ALEN));
+ fw->bitmask |= EBT_ISOURCE;
+ break;
+ case offsetof(struct ethhdr, h_proto):
+ __get_cmp_data(e, &ethproto, sizeof(ethproto), &op);
+ if (ethproto == htons(0x0600)) {
+ fw->bitmask |= EBT_802_3;
+ inv = (op == NFT_CMP_GTE);
+ } else {
+ fw->ethproto = ethproto;
+ inv = (op == NFT_CMP_NEQ);
+ }
+ if (inv)
+ fw->invflags |= EBT_IPROTO;
+ fw->bitmask &= ~EBT_NOPROTO;
+ break;
+ default:
+ DEBUGP("unknown payload offset %d\n", reg->payload.offset);
+ ctx->errmsg = "unknown payload offset";
+ break;
+ }
+}
+
+/* return 0 if saddr, 1 if daddr, -1 on error */
+static int
+lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len)
+{
+ if (base != 0 || len != ETH_ALEN)
+ return -1;
+
+ switch (offset) {
+ case offsetof(struct ether_header, ether_dhost):
+ return 1;
+ case offsetof(struct ether_header, ether_shost):
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/* return 0 if saddr, 1 if daddr, -1 on error */
+static int
+lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len)
+{
+ if (base != 1 || len != 4)
+ return -1;
+
+ switch (offset) {
+ case offsetof(struct iphdr, daddr):
+ return 1;
+ case offsetof(struct iphdr, saddr):
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/* Make sure previous payload expression(s) is/are consistent and extract if
+ * matching on source or destination address and if matching on MAC and IP or
+ * only MAC address. */
+static int lookup_analyze_payloads(struct nft_xt_ctx *ctx,
+ enum nft_registers sreg,
+ uint32_t key_len,
+ bool *dst, bool *ip)
+{
+ const struct nft_xt_ctx_reg *reg;
+ int val, val2 = -1;
+
+ reg = nft_xt_ctx_get_sreg(ctx, sreg);
+ if (!reg)
+ return -1;
+
+ if (reg->type != NFT_XT_REG_PAYLOAD) {
+ ctx->errmsg = "lookup reg is not payload type";
+ return -1;
+ }
+
+ switch (key_len) {
+ case 12: /* ether + ipv4addr */
+ val = lookup_check_ether_payload(reg->payload.base,
+ reg->payload.offset,
+ reg->payload.len);
+ if (val < 0) {
+ DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ reg->payload.base, reg->payload.offset,
+ reg->payload.len);
+ return -1;
+ }
+
+ sreg = nft_get_next_reg(sreg, ETH_ALEN);
+
+ reg = nft_xt_ctx_get_sreg(ctx, sreg);
+ if (!reg) {
+ ctx->errmsg = "next lookup register is invalid";
+ return -1;
+ }
+
+ if (reg->type != NFT_XT_REG_PAYLOAD) {
+ ctx->errmsg = "next lookup reg is not payload type";
+ return -1;
+ }
+
+ val2 = lookup_check_iphdr_payload(reg->payload.base,
+ reg->payload.offset,
+ reg->payload.len);
+ if (val2 < 0) {
+ DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ reg->payload.base, reg->payload.offset,
+ reg->payload.len);
+ return -1;
+ } else if (val != val2) {
+ DEBUGP("mismatching payload match offsets\n");
+ return -1;
+ }
+ break;
+ case 6: /* ether */
+ val = lookup_check_ether_payload(reg->payload.base,
+ reg->payload.offset,
+ reg->payload.len);
+ if (val < 0) {
+ DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
+ reg->payload.base, reg->payload.offset,
+ reg->payload.len);
+ return -1;
+ }
+ break;
+ default:
+ ctx->errmsg = "unsupported lookup key length";
+ return -1;
+ }
+
+ if (dst)
+ *dst = (val == 1);
+ if (ip)
+ *ip = (val2 != -1);
+ return 0;
+}
+
+static int set_elems_to_among_pairs(struct nft_among_pair *pairs,
+ const struct nftnl_set *s, int cnt)
+{
+ struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s);
+ struct nftnl_set_elem *elem;
+ size_t tmpcnt = 0;
+ const void *data;
+ uint32_t datalen;
+ int ret = -1;
+
+ if (!iter) {
+ fprintf(stderr, "BUG: set elems iter allocation failed\n");
+ return ret;
+ }
+
+ while ((elem = nftnl_set_elems_iter_next(iter))) {
+ data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen);
+ if (!data) {
+ fprintf(stderr, "BUG: set elem without key\n");
+ goto err;
+ }
+ if (datalen > sizeof(*pairs)) {
+ fprintf(stderr, "BUG: overlong set elem\n");
+ goto err;
+ }
+ nft_among_insert_pair(pairs, &tmpcnt, data);
+ }
+ ret = 0;
+err:
+ nftnl_set_elems_iter_destroy(iter);
+ return ret;
+}
+
+static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx,
+ const struct nftnl_expr *e)
+{
+ const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
+ uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID);
+ struct nftnl_set_list *slist;
+ struct nftnl_set *set;
+
+ slist = nft_set_list_get(ctx->h, ctx->table, set_name);
+ if (slist) {
+ set = nftnl_set_list_lookup_byname(slist, set_name);
+ if (set)
+ return set;
+
+ set = nft_set_batch_lookup_byid(ctx->h, set_id);
+ if (set)
+ return set;
+ }
+
+ return NULL;
+}
+
+static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e)
+{
+ struct xtables_match *match = NULL;
+ struct nft_among_data *among_data;
+ bool is_dst, have_ip, inv;
+ struct ebt_match *ematch;
+ struct nftnl_set *s;
+ size_t poff, size;
+ uint32_t cnt;
+
+ s = set_from_lookup_expr(ctx, e);
+ if (!s)
+ xtables_error(OTHER_PROBLEM,
+ "BUG: lookup expression references unknown set");
+
+ if (lookup_analyze_payloads(ctx,
+ nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG),
+ nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN),
+ &is_dst, &have_ip))
+ return;
+
+ cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE);
+
+ for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) {
+ if (!ematch->ismatch || strcmp(ematch->u.match->name, "among"))
+ continue;
+
+ match = ematch->u.match;
+ among_data = (struct nft_among_data *)match->m->data;
+
+ size = cnt + among_data->src.cnt + among_data->dst.cnt;
+ size *= sizeof(struct nft_among_pair);
+
+ size += XT_ALIGN(sizeof(struct xt_entry_match)) +
+ sizeof(struct nft_among_data);
+
+ match->m = xtables_realloc(match->m, size);
+ break;
+ }
+ if (!match) {
+ match = xtables_find_match("among", XTF_TRY_LOAD,
+ &ctx->cs->matches);
+
+ size = cnt * sizeof(struct nft_among_pair);
+ size += XT_ALIGN(sizeof(struct xt_entry_match)) +
+ sizeof(struct nft_among_data);
+
+ match->m = xtables_calloc(1, size);
+ strcpy(match->m->u.user.name, match->name);
+ match->m->u.user.revision = match->revision;
+ xs_init_match(match);
+
+ if (ctx->h->ops->rule_parse->match != NULL)
+ ctx->h->ops->rule_parse->match(match, ctx->cs);
+ }
+ if (!match)
+ return;
+
+ match->m->u.match_size = size;
+
+ inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) &
+ NFT_LOOKUP_F_INV);
+
+ among_data = (struct nft_among_data *)match->m->data;
+ poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip);
+ if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt))
+ xtables_error(OTHER_PROBLEM,
+ "ebtables among pair parsing failed");
+}
+
+static void parse_watcher(void *object, struct ebt_match **match_list,
+ bool ismatch)
+{
+ struct ebt_match *m = xtables_calloc(1, sizeof(struct ebt_match));
+
+ if (ismatch)
+ m->u.match = object;
+ else
+ m->u.watcher = object;
+
+ m->ismatch = ismatch;
+ if (*match_list == NULL)
+ *match_list = m;
+ else
+ (*match_list)->next = m;
+}
+
+static void nft_bridge_parse_match(struct xtables_match *m,
+ struct iptables_command_state *cs)
+{
+ parse_watcher(m, &cs->match_list, true);
+}
+
+static void nft_bridge_parse_target(struct xtables_target *t,
+ struct iptables_command_state *cs)
+{
+ /* harcoded names :-( */
+ if (strcmp(t->name, "log") == 0 ||
+ strcmp(t->name, "nflog") == 0) {
+ parse_watcher(t, &cs->match_list, false);
+ cs->jumpto = NULL;
+ cs->target = NULL;
+ return;
+ }
+}
+
+struct nft_ruleparse_ops nft_ruleparse_ops_bridge = {
+ .meta = nft_bridge_parse_meta,
+ .payload = nft_bridge_parse_payload,
+ .lookup = nft_bridge_parse_lookup,
+ .match = nft_bridge_parse_match,
+ .target = nft_bridge_parse_target,
+};
diff --git a/iptables/nft-ruleparse-ipv4.c b/iptables/nft-ruleparse-ipv4.c
new file mode 100644
index 00000000..fe65b33c
--- /dev/null
+++ b/iptables/nft-ruleparse-ipv4.c
@@ -0,0 +1,133 @@
+/*
+ * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+#include "nft-shared.h"
+#include "nft-ruleparse.h"
+#include "xshared.h"
+
+static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ switch (reg->meta_dreg.key) {
+ case NFT_META_L4PROTO:
+ cs->fw.ip.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ cs->fw.ip.invflags |= XT_INV_PROTO;
+ return;
+ default:
+ break;
+ }
+
+ if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface,
+ cs->fw.ip.outiface, &cs->fw.ip.invflags) == 0)
+ return;
+
+ ctx->errmsg = "unknown ipv4 meta key";
+}
+
+static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask)
+{
+ mask->s_addr = sreg->bitwise.mask[0];
+}
+
+static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e)
+{
+ uint8_t op;
+
+ /* we assume correct mask and xor */
+ if (!reg->bitwise.set)
+ return false;
+
+ /* we assume correct data */
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+ if (op == NFT_CMP_EQ)
+ return true;
+
+ return false;
+}
+
+static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *sreg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct in_addr addr;
+ uint8_t proto;
+ bool inv;
+
+ switch (sreg->payload.offset) {
+ case offsetof(struct iphdr, saddr):
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
+ cs->fw.ip.src.s_addr = addr.s_addr;
+ if (sreg->bitwise.set) {
+ parse_mask_ipv4(sreg, &cs->fw.ip.smsk);
+ } else {
+ memset(&cs->fw.ip.smsk, 0xff,
+ min(sreg->payload.len, sizeof(struct in_addr)));
+ }
+
+ if (inv)
+ cs->fw.ip.invflags |= IPT_INV_SRCIP;
+ break;
+ case offsetof(struct iphdr, daddr):
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
+ cs->fw.ip.dst.s_addr = addr.s_addr;
+ if (sreg->bitwise.set)
+ parse_mask_ipv4(sreg, &cs->fw.ip.dmsk);
+ else
+ memset(&cs->fw.ip.dmsk, 0xff,
+ min(sreg->payload.len, sizeof(struct in_addr)));
+
+ if (inv)
+ cs->fw.ip.invflags |= IPT_INV_DSTIP;
+ break;
+ case offsetof(struct iphdr, protocol):
+ get_cmp_data(e, &proto, sizeof(proto), &inv);
+ cs->fw.ip.proto = proto;
+ if (inv)
+ cs->fw.ip.invflags |= IPT_INV_PROTO;
+ break;
+ case offsetof(struct iphdr, frag_off):
+ cs->fw.ip.flags |= IPT_F_FRAG;
+ inv = get_frag(sreg, e);
+ if (inv)
+ cs->fw.ip.invflags |= IPT_INV_FRAG;
+ break;
+ case offsetof(struct iphdr, ttl):
+ if (nft_parse_hl(ctx, e, cs) < 0)
+ ctx->errmsg = "invalid ttl field match";
+ break;
+ default:
+ DEBUGP("unknown payload offset %d\n", sreg->payload.offset);
+ ctx->errmsg = "unknown payload offset";
+ break;
+ }
+}
+
+struct nft_ruleparse_ops nft_ruleparse_ops_ipv4 = {
+ .meta = nft_ipv4_parse_meta,
+ .payload = nft_ipv4_parse_payload,
+};
diff --git a/iptables/nft-ruleparse-ipv6.c b/iptables/nft-ruleparse-ipv6.c
new file mode 100644
index 00000000..29b08580
--- /dev/null
+++ b/iptables/nft-ruleparse-ipv6.c
@@ -0,0 +1,110 @@
+/*
+ * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip6.h>
+
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+#include "nft-shared.h"
+#include "nft-ruleparse.h"
+#include "xshared.h"
+
+static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ switch (reg->meta_dreg.key) {
+ case NFT_META_L4PROTO:
+ cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ cs->fw6.ipv6.invflags |= XT_INV_PROTO;
+ return;
+ default:
+ break;
+ }
+
+ if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface,
+ cs->fw6.ipv6.outiface, &cs->fw6.ipv6.invflags) == 0)
+ return;
+
+ ctx->errmsg = "unknown ipv6 meta key";
+}
+
+static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg,
+ struct in6_addr *mask)
+{
+ memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr));
+}
+
+static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *reg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct in6_addr addr;
+ uint8_t proto;
+ bool inv;
+
+ switch (reg->payload.offset) {
+ case offsetof(struct ip6_hdr, ip6_src):
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
+ memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
+ if (reg->bitwise.set)
+ parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk);
+ else
+ memset(&cs->fw6.ipv6.smsk, 0xff,
+ min(reg->payload.len, sizeof(struct in6_addr)));
+
+ if (inv)
+ cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP;
+ break;
+ case offsetof(struct ip6_hdr, ip6_dst):
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
+ memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
+ if (reg->bitwise.set)
+ parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk);
+ else
+ memset(&cs->fw6.ipv6.dmsk, 0xff,
+ min(reg->payload.len, sizeof(struct in6_addr)));
+
+ if (inv)
+ cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP;
+ break;
+ case offsetof(struct ip6_hdr, ip6_nxt):
+ get_cmp_data(e, &proto, sizeof(proto), &inv);
+ cs->fw6.ipv6.proto = proto;
+ if (inv)
+ cs->fw6.ipv6.invflags |= IP6T_INV_PROTO;
+ case offsetof(struct ip6_hdr, ip6_hlim):
+ if (nft_parse_hl(ctx, e, cs) < 0)
+ ctx->errmsg = "invalid ttl field match";
+ break;
+ default:
+ DEBUGP("unknown payload offset %d\n", reg->payload.offset);
+ ctx->errmsg = "unknown payload offset";
+ break;
+ }
+}
+
+struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = {
+ .meta = nft_ipv6_parse_meta,
+ .payload = nft_ipv6_parse_payload,
+};
diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c
new file mode 100644
index 00000000..3b1cbe4f
--- /dev/null
+++ b/iptables/nft-ruleparse.c
@@ -0,0 +1,1177 @@
+/*
+ * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/xt_limit.h>
+#include <linux/netfilter/xt_mark.h>
+#include <linux/netfilter/xt_NFLOG.h>
+#include <linux/netfilter/xt_pkttype.h>
+
+#include <linux/netfilter_ipv6/ip6t_hl.h>
+
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+#include <xtables.h>
+
+#include "nft-ruleparse.h"
+#include "nft.h"
+
+static struct xtables_match *
+nft_find_match_in_cs(struct iptables_command_state *cs, const char *name)
+{
+ struct xtables_rule_match *rm;
+ struct ebt_match *ebm;
+
+ for (ebm = cs->match_list; ebm; ebm = ebm->next) {
+ if (ebm->ismatch &&
+ !strcmp(ebm->u.match->m->u.user.name, name))
+ return ebm->u.match;
+ }
+ for (rm = cs->matches; rm; rm = rm->next) {
+ if (!strcmp(rm->match->m->u.user.name, name))
+ return rm->match;
+ }
+ return NULL;
+}
+
+void *
+nft_create_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ const char *name, bool reuse)
+{
+ struct xtables_match *match;
+ struct xt_entry_match *m;
+ unsigned int size;
+
+ if (reuse) {
+ match = nft_find_match_in_cs(cs, name);
+ if (match)
+ return match->m->data;
+ }
+
+ match = xtables_find_match(name, XTF_TRY_LOAD,
+ &cs->matches);
+ if (!match)
+ return NULL;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size;
+ m = xtables_calloc(1, size);
+ m->u.match_size = size;
+ m->u.user.revision = match->revision;
+
+ strcpy(m->u.user.name, match->name);
+ match->m = m;
+
+ xs_init_match(match);
+
+ if (ctx->h->ops->rule_parse->match)
+ ctx->h->ops->rule_parse->match(match, cs);
+
+ return match->m->data;
+}
+
+static void *
+__nft_create_target(struct nft_xt_ctx *ctx, const char *name, size_t tgsize)
+{
+ struct xtables_target *target;
+ size_t size;
+
+ target = xtables_find_target(name, XTF_TRY_LOAD);
+ if (!target)
+ return NULL;
+
+ size = XT_ALIGN(sizeof(*target->t)) + (tgsize ?: target->size);
+
+ target->t = xtables_calloc(1, size);
+ target->t->u.target_size = size;
+ target->t->u.user.revision = target->revision;
+ strcpy(target->t->u.user.name, name);
+
+ xs_init_target(target);
+
+ ctx->cs->jumpto = name;
+ ctx->cs->target = target;
+
+ if (ctx->h->ops->rule_parse->target)
+ ctx->h->ops->rule_parse->target(target, ctx->cs);
+
+ return target->t->data;
+}
+
+void *
+nft_create_target(struct nft_xt_ctx *ctx, const char *name)
+{
+ return __nft_create_target(ctx, name, 0);
+}
+
+static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters)
+{
+ counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS);
+ counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES);
+}
+
+static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ enum nft_registers regnum = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
+ struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_dreg(ctx, regnum);
+
+ if (!reg)
+ return;
+
+ reg->type = NFT_XT_REG_PAYLOAD;
+ reg->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
+ reg->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
+ reg->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
+}
+
+static bool nft_parse_meta_set_common(struct nft_xt_ctx* ctx,
+ struct nft_xt_ctx_reg *sreg)
+{
+ if ((sreg->type != NFT_XT_REG_IMMEDIATE)) {
+ ctx->errmsg = "meta sreg is not an immediate";
+ return false;
+ }
+
+ return true;
+}
+
+static void nft_parse_meta_set(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e)
+{
+ struct nft_xt_ctx_reg *sreg;
+ enum nft_registers sregnum;
+
+ sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG);
+ sreg = nft_xt_ctx_get_sreg(ctx, sregnum);
+ if (!sreg)
+ return;
+
+ switch (nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY)) {
+ case NFT_META_NFTRACE:
+ if (!nft_parse_meta_set_common(ctx, sreg))
+ return;
+
+ if (sreg->immediate.data[0] == 0) {
+ ctx->errmsg = "meta sreg immediate is 0";
+ return;
+ }
+
+ if (!nft_create_target(ctx, "TRACE"))
+ ctx->errmsg = "target TRACE not found";
+ break;
+ case NFT_META_BRI_BROUTE:
+ if (!nft_parse_meta_set_common(ctx, sreg))
+ return;
+
+ ctx->cs->jumpto = "DROP";
+ break;
+ case NFT_META_MARK: {
+ struct xt_mark_tginfo2 *mt;
+
+ if (!nft_parse_meta_set_common(ctx, sreg))
+ return;
+
+ mt = nft_create_target(ctx, "MARK");
+ if (!mt) {
+ ctx->errmsg = "target MARK not found";
+ return;
+ }
+
+ mt->mark = sreg->immediate.data[0];
+ if (sreg->bitwise.set)
+ mt->mask = sreg->bitwise.mask[0];
+ else
+ mt->mask = ~0u;
+ break;
+ }
+ default:
+ ctx->errmsg = "meta sreg key not supported";
+ break;
+ }
+}
+
+static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ struct nft_xt_ctx_reg *reg;
+
+ if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG)) {
+ nft_parse_meta_set(ctx, e);
+ return;
+ }
+
+ reg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG));
+ if (!reg)
+ return;
+
+ reg->meta_dreg.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY);
+ reg->type = NFT_XT_REG_META_DREG;
+}
+
+static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ enum nft_registers sregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG);
+ enum nft_registers dregnum = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG);
+ struct nft_xt_ctx_reg *sreg = nft_xt_ctx_get_sreg(ctx, sregnum);
+ struct nft_xt_ctx_reg *dreg = sreg;
+ const void *data;
+ uint32_t len;
+
+ if (!sreg)
+ return;
+
+ if (sregnum != dregnum) {
+ dreg = nft_xt_ctx_get_sreg(ctx, dregnum); /* sreg, do NOT clear ... */
+ if (!dreg)
+ return;
+
+ *dreg = *sreg; /* .. and copy content instead */
+ }
+
+ data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len);
+
+ if (len > sizeof(dreg->bitwise.xor)) {
+ ctx->errmsg = "bitwise xor too large";
+ return;
+ }
+
+ memcpy(dreg->bitwise.xor, data, len);
+
+ data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len);
+
+ if (len > sizeof(dreg->bitwise.mask)) {
+ ctx->errmsg = "bitwise mask too large";
+ return;
+ }
+
+ memcpy(dreg->bitwise.mask, data, len);
+
+ dreg->bitwise.set = true;
+}
+
+static void nft_parse_icmp(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ struct nft_xt_ctx_reg *sreg,
+ uint8_t op, const char *data, size_t dlen)
+{
+ struct ipt_icmp icmp = {
+ .type = UINT8_MAX,
+ .code = { 0, UINT8_MAX },
+ }, *icmpp;
+
+ if (dlen < 1)
+ goto out_err_len;
+
+ switch (sreg->payload.offset) {
+ case 0:
+ icmp.type = data[0];
+ if (dlen == 1)
+ break;
+ dlen--;
+ data++;
+ /* fall through */
+ case 1:
+ if (dlen > 1)
+ goto out_err_len;
+ icmp.code[0] = icmp.code[1] = data[0];
+ break;
+ default:
+ ctx->errmsg = "unexpected payload offset";
+ return;
+ }
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ icmpp = nft_create_match(ctx, cs, "icmp", false);
+ break;
+ case NFPROTO_IPV6:
+ if (icmp.type == UINT8_MAX) {
+ ctx->errmsg = "icmp6 code with any type match not supported";
+ return;
+ }
+ icmpp = nft_create_match(ctx, cs, "icmp6", false);
+ break;
+ default:
+ ctx->errmsg = "unexpected family for icmp match";
+ return;
+ }
+
+ if (!icmpp) {
+ ctx->errmsg = "icmp match extension not found";
+ return;
+ }
+ memcpy(icmpp, &icmp, sizeof(icmp));
+ return;
+
+out_err_len:
+ ctx->errmsg = "unexpected RHS data length";
+}
+
+static void port_match_single_to_range(__u16 *ports, __u8 *invflags,
+ uint8_t op, int port, __u8 invflag)
+{
+ if (port < 0)
+ return;
+
+ switch (op) {
+ case NFT_CMP_NEQ:
+ *invflags |= invflag;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ ports[0] = port;
+ ports[1] = port;
+ break;
+ case NFT_CMP_LT:
+ ports[1] = max(port - 1, 1);
+ break;
+ case NFT_CMP_LTE:
+ ports[1] = port;
+ break;
+ case NFT_CMP_GT:
+ ports[0] = min(port + 1, UINT16_MAX);
+ break;
+ case NFT_CMP_GTE:
+ ports[0] = port;
+ break;
+ }
+}
+
+static void nft_parse_udp(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport, int dport,
+ uint8_t op)
+{
+ struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true);
+
+ if (!udp) {
+ ctx->errmsg = "udp match extension not found";
+ return;
+ }
+
+ port_match_single_to_range(udp->spts, &udp->invflags,
+ op, sport, XT_UDP_INV_SRCPT);
+ port_match_single_to_range(udp->dpts, &udp->invflags,
+ op, dport, XT_UDP_INV_DSTPT);
+}
+
+static void nft_parse_tcp(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport, int dport,
+ uint8_t op)
+{
+ struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true);
+
+ if (!tcp) {
+ ctx->errmsg = "tcp match extension not found";
+ return;
+ }
+
+ port_match_single_to_range(tcp->spts, &tcp->invflags,
+ op, sport, XT_TCP_INV_SRCPT);
+ port_match_single_to_range(tcp->dpts, &tcp->invflags,
+ op, dport, XT_TCP_INV_DSTPT);
+}
+
+static void nft_parse_th_port(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t proto,
+ int sport, int dport, uint8_t op)
+{
+ switch (proto) {
+ case IPPROTO_UDP:
+ nft_parse_udp(ctx, cs, sport, dport, op);
+ break;
+ case IPPROTO_TCP:
+ nft_parse_tcp(ctx, cs, sport, dport, op);
+ break;
+ default:
+ ctx->errmsg = "unknown layer 4 protocol for TH match";
+ }
+}
+
+static void nft_parse_tcp_flags(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t op, uint8_t flags, uint8_t mask)
+{
+ struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true);
+
+ if (!tcp) {
+ ctx->errmsg = "tcp match extension not found";
+ return;
+ }
+
+ if (op == NFT_CMP_NEQ)
+ tcp->invflags |= XT_TCP_INV_FLAGS;
+ tcp->flg_cmp = flags;
+ tcp->flg_mask = mask;
+}
+
+static void nft_parse_transport(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct nft_xt_ctx_reg *sreg;
+ enum nft_registers reg;
+ uint32_t sdport;
+ uint16_t port;
+ uint8_t proto, op;
+ unsigned int len;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ proto = ctx->cs->fw.ip.proto;
+ break;
+ case NFPROTO_IPV6:
+ proto = ctx->cs->fw6.ipv6.proto;
+ break;
+ default:
+ ctx->errmsg = "invalid family for TH match";
+ return;
+ }
+
+ nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
+ sreg = nft_xt_ctx_get_sreg(ctx, reg);
+ if (!sreg)
+ return;
+
+ if (sreg->type != NFT_XT_REG_PAYLOAD) {
+ ctx->errmsg = "sgreg not payload";
+ return;
+ }
+
+ switch (proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ break;
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ nft_parse_icmp(ctx, cs, sreg, op,
+ nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len),
+ len);
+ return;
+ default:
+ ctx->errmsg = "unsupported layer 4 protocol value";
+ return;
+ }
+
+ switch(sreg->payload.offset) {
+ case 0: /* th->sport */
+ switch (len) {
+ case 2: /* load sport only */
+ port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
+ nft_parse_th_port(ctx, cs, proto, port, -1, op);
+ return;
+ case 4: /* load both src and dst port */
+ sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA));
+ nft_parse_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op);
+ return;
+ }
+ break;
+ case 2: /* th->dport */
+ switch (len) {
+ case 2:
+ port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
+ nft_parse_th_port(ctx, cs, proto, -1, port, op);
+ return;
+ }
+ break;
+ case 13: /* th->flags */
+ if (len == 1 && proto == IPPROTO_TCP) {
+ uint8_t flags = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ uint8_t mask = ~0;
+
+ if (sreg->bitwise.set)
+ memcpy(&mask, &sreg->bitwise.mask, sizeof(mask));
+
+ nft_parse_tcp_flags(ctx, cs, op, flags, mask);
+ }
+ return;
+ }
+}
+
+static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ struct nft_xt_ctx_reg *sreg;
+ uint32_t reg;
+
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
+
+ sreg = nft_xt_ctx_get_sreg(ctx, reg);
+ if (!sreg)
+ return;
+
+ switch (sreg->type) {
+ case NFT_XT_REG_UNDEF:
+ ctx->errmsg = "cmp sreg undef";
+ break;
+ case NFT_XT_REG_META_DREG:
+ ctx->h->ops->rule_parse->meta(ctx, sreg, e, ctx->cs);
+ break;
+ case NFT_XT_REG_PAYLOAD:
+ switch (sreg->payload.base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ if (ctx->h->family == NFPROTO_BRIDGE)
+ ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs);
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ ctx->h->ops->rule_parse->payload(ctx, sreg, e, ctx->cs);
+ break;
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ nft_parse_transport(ctx, e, ctx->cs);
+ break;
+ }
+
+ break;
+ default:
+ ctx->errmsg = "cmp sreg has unknown type";
+ break;
+ }
+}
+
+static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
+ struct iptables_command_state *cs = ctx->cs;
+ int verdict;
+
+ if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
+ struct nft_xt_ctx_reg *dreg;
+ const void *imm_data;
+ uint32_t len;
+
+ imm_data = nftnl_expr_get(e, NFTNL_EXPR_IMM_DATA, &len);
+ dreg = nft_xt_ctx_get_dreg(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG));
+ if (!dreg)
+ return;
+
+ if (len > sizeof(dreg->immediate.data)) {
+ ctx->errmsg = "oversized immediate data";
+ return;
+ }
+
+ memcpy(dreg->immediate.data, imm_data, len);
+ dreg->immediate.len = len;
+ dreg->type = NFT_XT_REG_IMMEDIATE;
+
+ return;
+ }
+
+ verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT);
+ /* Standard target? */
+ switch(verdict) {
+ case NF_ACCEPT:
+ if (cs->jumpto && strcmp(ctx->table, "broute") == 0)
+ break;
+ cs->jumpto = "ACCEPT";
+ break;
+ case NF_DROP:
+ cs->jumpto = "DROP";
+ break;
+ case NFT_RETURN:
+ cs->jumpto = "RETURN";
+ break;;
+ case NFT_GOTO:
+ if (ctx->h->ops->set_goto_flag)
+ ctx->h->ops->set_goto_flag(cs);
+ /* fall through */
+ case NFT_JUMP:
+ cs->jumpto = chain;
+ /* fall through */
+ default:
+ return;
+ }
+
+ if (!nft_create_target(ctx, cs->jumpto))
+ ctx->errmsg = "verdict extension not found";
+}
+
+static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ uint32_t mt_len;
+ const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME);
+ const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len);
+ struct xtables_match *match;
+ struct xtables_rule_match **matches;
+ struct xt_entry_match *m;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_BRIDGE:
+ matches = &ctx->cs->matches;
+ break;
+ default:
+ fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
+ ctx->h->family);
+ exit(EXIT_FAILURE);
+ }
+
+ match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches);
+ if (match == NULL) {
+ ctx->errmsg = "match extension not found";
+ return;
+ }
+
+ m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len);
+ memcpy(&m->data, mt_info, mt_len);
+ m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match));
+ m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV);
+ strcpy(m->u.user.name, match->name);
+
+ match->m = m;
+
+ if (ctx->h->ops->rule_parse->match != NULL)
+ ctx->h->ops->rule_parse->match(match, ctx->cs);
+}
+
+static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ uint32_t tg_len;
+ const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME);
+ const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len);
+ void *data;
+
+ data = __nft_create_target(ctx, targname, tg_len);
+ if (!data)
+ ctx->errmsg = "target extension not found";
+ else
+ memcpy(data, targinfo, tg_len);
+}
+
+static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST);
+ __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT);
+ __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE);
+ struct xt_rateinfo *rinfo;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_BRIDGE:
+ break;
+ default:
+ fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n",
+ ctx->h->family);
+ exit(EXIT_FAILURE);
+ }
+
+ rinfo = nft_create_match(ctx, ctx->cs, "limit", false);
+ if (!rinfo) {
+ ctx->errmsg = "limit match extension not found";
+ return;
+ }
+
+ rinfo->avg = XT_LIMIT_SCALE * unit / rate;
+ rinfo->burst = burst;
+}
+
+static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h,
+ struct nftnl_expr *e)
+{
+ if (ctx->h->ops->rule_parse->lookup)
+ ctx->h->ops->rule_parse->lookup(ctx, e);
+}
+
+static void nft_parse_log(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ /*
+ * In order to handle the longer log-prefix supported by nft, instead of
+ * using struct xt_nflog_info, we use a struct with a compatible layout, but
+ * a larger buffer for the prefix.
+ */
+ struct xt_nflog_info_nft {
+ __u32 len;
+ __u16 group;
+ __u16 threshold;
+ __u16 flags;
+ __u16 pad;
+ char prefix[NF_LOG_PREFIXLEN];
+ } info = {
+ .group = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_GROUP),
+ .threshold = nftnl_expr_get_u16(e, NFTNL_EXPR_LOG_QTHRESHOLD),
+ };
+ void *data;
+
+ if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_SNAPLEN)) {
+ info.len = nftnl_expr_get_u32(e, NFTNL_EXPR_LOG_SNAPLEN);
+ info.flags = XT_NFLOG_F_COPY_LEN;
+ }
+ if (nftnl_expr_is_set(e, NFTNL_EXPR_LOG_PREFIX))
+ snprintf(info.prefix, sizeof(info.prefix), "%s",
+ nftnl_expr_get_str(e, NFTNL_EXPR_LOG_PREFIX));
+
+ data = __nft_create_target(ctx, "NFLOG",
+ XT_ALIGN(sizeof(struct xt_nflog_info_nft)));
+ if (!data)
+ ctx->errmsg = "NFLOG target extension not found";
+ else
+ memcpy(data, &info, sizeof(info));
+}
+
+static void nft_parse_udp_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to,
+ uint8_t op)
+{
+ struct xt_udp *udp = nft_create_match(ctx, cs, "udp", true);
+
+ if (!udp) {
+ ctx->errmsg = "udp match extension not found";
+ return;
+ }
+
+ if (sport_from >= 0) {
+ switch (op) {
+ case NFT_RANGE_NEQ:
+ udp->invflags |= XT_UDP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_RANGE_EQ:
+ udp->spts[0] = sport_from;
+ udp->spts[1] = sport_to;
+ break;
+ }
+ }
+
+ if (dport_to >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ udp->invflags |= XT_UDP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ udp->dpts[0] = dport_from;
+ udp->dpts[1] = dport_to;
+ break;
+ }
+ }
+}
+
+static void nft_parse_tcp_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to,
+ uint8_t op)
+{
+ struct xt_tcp *tcp = nft_create_match(ctx, cs, "tcp", true);
+
+ if (!tcp) {
+ ctx->errmsg = "tcp match extension not found";
+ return;
+ }
+
+ if (sport_from >= 0) {
+ switch (op) {
+ case NFT_RANGE_NEQ:
+ tcp->invflags |= XT_TCP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_RANGE_EQ:
+ tcp->spts[0] = sport_from;
+ tcp->spts[1] = sport_to;
+ break;
+ }
+ }
+
+ if (dport_to >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ tcp->invflags |= XT_TCP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ tcp->dpts[0] = dport_from;
+ tcp->dpts[1] = dport_to;
+ break;
+ }
+ }
+}
+
+static void nft_parse_th_port_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t proto,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to, uint8_t op)
+{
+ switch (proto) {
+ case IPPROTO_UDP:
+ nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
+ break;
+ case IPPROTO_TCP:
+ nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
+ break;
+ }
+}
+
+static void nft_parse_transport_range(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *sreg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ unsigned int len_from, len_to;
+ uint8_t proto, op;
+ uint16_t from, to;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ proto = ctx->cs->fw.ip.proto;
+ break;
+ case NFPROTO_IPV6:
+ proto = ctx->cs->fw6.ipv6.proto;
+ break;
+ default:
+ proto = 0;
+ break;
+ }
+
+ nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from);
+ nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to);
+ if (len_to != len_from || len_to != 2)
+ return;
+
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP);
+
+ from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA));
+ to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
+
+ switch (sreg->payload.offset) {
+ case 0:
+ nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op);
+ return;
+ case 2:
+ to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
+ nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op);
+ return;
+ }
+}
+
+static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ struct nft_xt_ctx_reg *sreg;
+ uint32_t reg;
+
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG);
+ sreg = nft_xt_ctx_get_sreg(ctx, reg);
+
+ switch (sreg->type) {
+ case NFT_XT_REG_UNDEF:
+ ctx->errmsg = "range sreg undef";
+ break;
+ case NFT_XT_REG_PAYLOAD:
+ switch (sreg->payload.base) {
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ nft_parse_transport_range(ctx, sreg, e, ctx->cs);
+ break;
+ default:
+ ctx->errmsg = "range with unknown payload base";
+ break;
+ }
+ break;
+ default:
+ ctx->errmsg = "range sreg type unsupported";
+ break;
+ }
+}
+
+bool nft_rule_to_iptables_command_state(struct nft_handle *h,
+ const struct nftnl_rule *r,
+ struct iptables_command_state *cs)
+{
+ struct nftnl_expr_iter *iter;
+ struct nftnl_expr *expr;
+ struct nft_xt_ctx ctx = {
+ .cs = cs,
+ .h = h,
+ .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE),
+ };
+ bool ret = true;
+
+ iter = nftnl_expr_iter_create(r);
+ if (iter == NULL)
+ return false;
+
+ ctx.iter = iter;
+ expr = nftnl_expr_iter_next(iter);
+ while (expr != NULL) {
+ const char *name =
+ nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
+
+ if (strcmp(name, "counter") == 0)
+ nft_parse_counter(expr, &ctx.cs->counters);
+ else if (strcmp(name, "payload") == 0)
+ nft_parse_payload(&ctx, expr);
+ else if (strcmp(name, "meta") == 0)
+ nft_parse_meta(&ctx, expr);
+ else if (strcmp(name, "bitwise") == 0)
+ nft_parse_bitwise(&ctx, expr);
+ else if (strcmp(name, "cmp") == 0)
+ nft_parse_cmp(&ctx, expr);
+ else if (strcmp(name, "immediate") == 0)
+ nft_parse_immediate(&ctx, expr);
+ else if (strcmp(name, "match") == 0)
+ nft_parse_match(&ctx, expr);
+ else if (strcmp(name, "target") == 0)
+ nft_parse_target(&ctx, expr);
+ else if (strcmp(name, "limit") == 0)
+ nft_parse_limit(&ctx, expr);
+ else if (strcmp(name, "lookup") == 0)
+ nft_parse_lookup(&ctx, h, expr);
+ else if (strcmp(name, "log") == 0)
+ nft_parse_log(&ctx, expr);
+ else if (strcmp(name, "range") == 0)
+ nft_parse_range(&ctx, expr);
+
+ if (ctx.errmsg) {
+ fprintf(stderr, "Error: %s\n", ctx.errmsg);
+ ctx.errmsg = NULL;
+ ret = false;
+ }
+
+ expr = nftnl_expr_iter_next(iter);
+ }
+
+ nftnl_expr_iter_destroy(iter);
+
+ if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) {
+ const void *data;
+ uint32_t len, size;
+ const char *comment;
+
+ data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
+ comment = get_comment(data, len);
+ if (comment) {
+ struct xtables_match *match;
+ struct xt_entry_match *m;
+
+ match = xtables_find_match("comment", XTF_TRY_LOAD,
+ &cs->matches);
+ if (match == NULL)
+ return false;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_match))
+ + match->size;
+ m = xtables_calloc(1, size);
+
+ strncpy((char *)m->data, comment, match->size - 1);
+ m->u.match_size = size;
+ m->u.user.revision = 0;
+ strcpy(m->u.user.name, match->name);
+
+ match->m = m;
+ }
+ }
+
+ if (!cs->jumpto)
+ cs->jumpto = "";
+
+ if (!ret)
+ xtables_error(VERSION_PROBLEM, "Parsing nftables rule failed");
+ return ret;
+}
+
+static void parse_ifname(const char *name, unsigned int len, char *dst)
+{
+ if (len == 0)
+ return;
+
+ memcpy(dst, name, len);
+ if (name[len - 1] == '\0')
+ return;
+
+ if (len >= IFNAMSIZ)
+ return;
+
+ /* wildcard */
+ dst[len++] = '+';
+ if (len >= IFNAMSIZ)
+ return;
+ dst[len++] = 0;
+}
+
+static void parse_invalid_iface(char *iface, uint8_t *invflags, uint8_t invbit)
+{
+ if (*invflags & invbit || strcmp(iface, "INVAL/D"))
+ return;
+
+ /* nft's poor "! -o +" excuse */
+ *invflags |= invbit;
+ iface[0] = '+';
+ iface[1] = '\0';
+}
+
+static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg)
+{
+ struct nft_xt_ctx_reg *reg = nft_xt_ctx_get_sreg(ctx, sreg);
+
+ if (reg->bitwise.set)
+ return reg->bitwise.mask[0];
+
+ return ~0u;
+}
+
+static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ struct xt_mark_mtinfo1 *mark;
+ uint32_t value;
+
+ mark = nft_create_match(ctx, ctx->cs, "mark", false);
+ if (!mark)
+ return -1;
+
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ mark->invert = 1;
+
+ value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
+ mark->mark = value;
+ mark->mask = get_meta_mask(ctx, nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG));
+
+ return 0;
+}
+
+static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ struct xt_pkttype_info *pkttype;
+ uint8_t value;
+
+ pkttype = nft_create_match(ctx, ctx->cs, "pkttype", false);
+ if (!pkttype)
+ return -1;
+
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ pkttype->invert = 1;
+
+ value = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ pkttype->pkttype = value;
+
+ return 0;
+}
+
+int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key,
+ char *iniface, char *outiface, uint8_t *invflags)
+{
+ uint32_t value;
+ const void *ifname;
+ uint32_t len;
+
+ switch(key) {
+ case NFT_META_IIF:
+ value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ *invflags |= IPT_INV_VIA_IN;
+
+ if_indextoname(value, iniface);
+ break;
+ case NFT_META_OIF:
+ value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ *invflags |= IPT_INV_VIA_OUT;
+
+ if_indextoname(value, outiface);
+ break;
+ case NFT_META_BRI_IIFNAME:
+ case NFT_META_IIFNAME:
+ ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ *invflags |= IPT_INV_VIA_IN;
+
+ parse_ifname(ifname, len, iniface);
+ parse_invalid_iface(iniface, invflags, IPT_INV_VIA_IN);
+ break;
+ case NFT_META_BRI_OIFNAME:
+ case NFT_META_OIFNAME:
+ ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
+ if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
+ *invflags |= IPT_INV_VIA_OUT;
+
+ parse_ifname(ifname, len, outiface);
+ parse_invalid_iface(outiface, invflags, IPT_INV_VIA_OUT);
+ break;
+ case NFT_META_MARK:
+ parse_meta_mark(ctx, e);
+ break;
+ case NFT_META_PKTTYPE:
+ parse_meta_pkttype(ctx, e);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ struct ip6t_hl_info *info;
+ uint8_t hl, mode;
+ int op;
+
+ hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+
+ switch (op) {
+ case NFT_CMP_NEQ:
+ mode = IP6T_HL_NE;
+ break;
+ case NFT_CMP_EQ:
+ mode = IP6T_HL_EQ;
+ break;
+ case NFT_CMP_LT:
+ mode = IP6T_HL_LT;
+ break;
+ case NFT_CMP_GT:
+ mode = IP6T_HL_GT;
+ break;
+ case NFT_CMP_LTE:
+ mode = IP6T_HL_LT;
+ if (hl == 255)
+ return -1;
+ hl++;
+ break;
+ case NFT_CMP_GTE:
+ mode = IP6T_HL_GT;
+ if (hl == 0)
+ return -1;
+ hl--;
+ break;
+ default:
+ return -1;
+ }
+
+ /* ipt_ttl_info and ip6t_hl_info have same layout,
+ * IPT_TTL_x and IP6T_HL_x are aliases as well, so
+ * just use HL for both ipv4 and ipv6.
+ */
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ info = nft_create_match(ctx, ctx->cs, "ttl", false);
+ break;
+ case NFPROTO_IPV6:
+ info = nft_create_match(ctx, ctx->cs, "hl", false);
+ break;
+ default:
+ return -1;
+ }
+
+ if (!info)
+ return -1;
+
+ info->hop_limit = hl;
+ info->mode = mode;
+
+ return 0;
+}
diff --git a/iptables/nft-ruleparse.h b/iptables/nft-ruleparse.h
new file mode 100644
index 00000000..62c9160d
--- /dev/null
+++ b/iptables/nft-ruleparse.h
@@ -0,0 +1,136 @@
+#ifndef _NFT_RULEPARSE_H_
+#define _NFT_RULEPARSE_H_
+
+#include <linux/netfilter/nf_tables.h>
+
+#include <libnftnl/expr.h>
+
+#include "xshared.h"
+
+enum nft_ctx_reg_type {
+ NFT_XT_REG_UNDEF,
+ NFT_XT_REG_PAYLOAD,
+ NFT_XT_REG_IMMEDIATE,
+ NFT_XT_REG_META_DREG,
+};
+
+struct nft_xt_ctx_reg {
+ enum nft_ctx_reg_type type:8;
+
+ union {
+ struct {
+ uint32_t base;
+ uint32_t offset;
+ uint32_t len;
+ } payload;
+ struct {
+ uint32_t data[4];
+ uint8_t len;
+ } immediate;
+ struct {
+ uint32_t key;
+ } meta_dreg;
+ struct {
+ uint32_t key;
+ } meta_sreg;
+ };
+
+ struct {
+ uint32_t mask[4];
+ uint32_t xor[4];
+ bool set;
+ } bitwise;
+};
+
+struct nft_xt_ctx {
+ struct iptables_command_state *cs;
+ struct nftnl_expr_iter *iter;
+ struct nft_handle *h;
+ uint32_t flags;
+ const char *table;
+
+ struct nft_xt_ctx_reg regs[1 + 16];
+
+ const char *errmsg;
+};
+
+static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_sreg(struct nft_xt_ctx *ctx, enum nft_registers reg)
+{
+ switch (reg) {
+ case NFT_REG_VERDICT:
+ return &ctx->regs[0];
+ case NFT_REG_1:
+ return &ctx->regs[1];
+ case NFT_REG_2:
+ return &ctx->regs[5];
+ case NFT_REG_3:
+ return &ctx->regs[9];
+ case NFT_REG_4:
+ return &ctx->regs[13];
+ case NFT_REG32_00...NFT_REG32_15:
+ return &ctx->regs[reg - NFT_REG32_00];
+ default:
+ ctx->errmsg = "Unknown register requested";
+ break;
+ }
+
+ return NULL;
+}
+
+static inline void nft_xt_reg_clear(struct nft_xt_ctx_reg *r)
+{
+ r->type = 0;
+ r->bitwise.set = false;
+}
+
+static inline struct nft_xt_ctx_reg *nft_xt_ctx_get_dreg(struct nft_xt_ctx *ctx, enum nft_registers reg)
+{
+ struct nft_xt_ctx_reg *r = nft_xt_ctx_get_sreg(ctx, reg);
+
+ if (r)
+ nft_xt_reg_clear(r);
+
+ return r;
+}
+
+struct nft_ruleparse_ops {
+ void (*meta)(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *sreg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs);
+ void (*payload)(struct nft_xt_ctx *ctx,
+ const struct nft_xt_ctx_reg *sreg,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs);
+ void (*lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
+ void (*match)(struct xtables_match *m,
+ struct iptables_command_state *cs);
+ void (*target)(struct xtables_target *t,
+ struct iptables_command_state *cs);
+};
+
+extern struct nft_ruleparse_ops nft_ruleparse_ops_arp;
+extern struct nft_ruleparse_ops nft_ruleparse_ops_bridge;
+extern struct nft_ruleparse_ops nft_ruleparse_ops_ipv4;
+extern struct nft_ruleparse_ops nft_ruleparse_ops_ipv6;
+
+void *nft_create_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ const char *name, bool reuse);
+void *nft_create_target(struct nft_xt_ctx *ctx, const char *name);
+
+
+bool nft_rule_to_iptables_command_state(struct nft_handle *h,
+ const struct nftnl_rule *r,
+ struct iptables_command_state *cs);
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key,
+ char *iniface, char *outiface, uint8_t *invflags);
+
+int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
+ struct iptables_command_state *cs);
+
+#endif /* _NFT_RULEPARSE_H_ */
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 10553ab2..6775578b 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -10,6 +10,7 @@
* This code has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
+#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -20,9 +21,6 @@
#include <xtables.h>
-#include <linux/netfilter/xt_comment.h>
-#include <linux/netfilter/xt_limit.h>
-
#include <libmnl/libmnl.h>
#include <libnftnl/rule.h>
#include <libnftnl/expr.h>
@@ -37,136 +35,151 @@ extern struct nft_family_ops nft_family_ops_ipv6;
extern struct nft_family_ops nft_family_ops_arp;
extern struct nft_family_ops nft_family_ops_bridge;
-void add_meta(struct nftnl_rule *r, uint32_t key)
+static struct nftnl_expr *xt_nftnl_expr_alloc(const char *name)
+{
+ struct nftnl_expr *expr = nftnl_expr_alloc(name);
+
+ if (expr)
+ return expr;
+
+ xtables_error(RESOURCE_PROBLEM,
+ "Failed to allocate nftnl expression '%s'", name);
+}
+
+void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key,
+ uint8_t *dreg)
{
struct nftnl_expr *expr;
+ uint8_t reg;
- expr = nftnl_expr_alloc("meta");
- if (expr == NULL)
- return;
+ expr = xt_nftnl_expr_alloc("meta");
+ reg = NFT_REG_1;
nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
-
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, reg);
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
-void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base)
+void add_payload(struct nft_handle *h, struct nftnl_rule *r,
+ int offset, int len, uint32_t base, uint8_t *dreg)
{
struct nftnl_expr *expr;
+ uint8_t reg;
- expr = nftnl_expr_alloc("payload");
- if (expr == NULL)
- return;
+ expr = xt_nftnl_expr_alloc("payload");
+ reg = NFT_REG_1;
nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, reg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len);
-
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
/* bitwise operation is = sreg & mask ^ xor */
-void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor)
+void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r,
+ uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg)
{
struct nftnl_expr *expr;
+ uint8_t reg;
- expr = nftnl_expr_alloc("bitwise");
- if (expr == NULL)
- return;
+ expr = xt_nftnl_expr_alloc("bitwise");
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1);
+ reg = NFT_REG_1;
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, sizeof(uint16_t));
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t));
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t));
-
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
-void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len)
+void add_bitwise(struct nft_handle *h, struct nftnl_rule *r,
+ uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg)
{
struct nftnl_expr *expr;
uint32_t xor[4] = { 0 };
+ uint8_t reg = *dreg;
- expr = nftnl_expr_alloc("bitwise");
- if (expr == NULL)
- return;
+ expr = xt_nftnl_expr_alloc("bitwise");
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1);
- nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len);
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len);
nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, len);
-
nftnl_rule_add_expr(r, expr);
+
+ *dreg = reg;
}
-void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len)
+void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len,
+ uint8_t sreg)
{
struct nftnl_expr *expr;
- expr = nftnl_expr_alloc("cmp");
- if (expr == NULL)
- return;
+ expr = xt_nftnl_expr_alloc("cmp");
- nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, NFT_REG_1);
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg);
nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op);
nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, len);
-
nftnl_rule_add_expr(r, expr);
}
-void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op)
+void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg)
{
- add_cmp_ptr(r, op, &val, sizeof(val));
+ add_cmp_ptr(r, op, &val, sizeof(val), sreg);
}
-void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op)
+void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg)
{
- add_cmp_ptr(r, op, &val, sizeof(val));
+ add_cmp_ptr(r, op, &val, sizeof(val), sreg);
}
-void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op)
+void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg)
{
- add_cmp_ptr(r, op, &val, sizeof(val));
+ add_cmp_ptr(r, op, &val, sizeof(val), sreg);
}
-void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
+void add_iface(struct nft_handle *h, struct nftnl_rule *r,
+ char *iface, uint32_t key, uint32_t op)
{
- int iface_len;
+ int iface_len = strlen(iface);
+ uint8_t reg;
- iface_len = strlen(iface);
- add_meta(r, NFT_META_IIFNAME);
if (iface[iface_len - 1] == '+') {
- if (iface_len > 1)
- add_cmp_ptr(r, op, iface, iface_len - 1);
- } else
- add_cmp_ptr(r, op, iface, iface_len + 1);
-}
-
-void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
-{
- int iface_len;
-
- iface_len = strlen(iface);
+ if (iface_len > 1) {
+ iface_len -= 1;
+ } else if (op != NFT_CMP_EQ) {
+ op = NFT_CMP_EQ;
+ iface = "INVAL/D";
+ iface_len = strlen(iface) + 1;
+ } else {
+ return; /* -o + */
+ }
+ } else {
+ iface_len += 1;
+ }
- add_meta(r, NFT_META_OIFNAME);
- if (iface[iface_len - 1] == '+') {
- if (iface_len > 1)
- add_cmp_ptr(r, op, iface, iface_len - 1);
- } else
- add_cmp_ptr(r, op, iface, iface_len + 1);
+ add_meta(h, r, key, &reg);
+ add_cmp_ptr(r, op, iface, iface_len, reg);
}
-void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
+void add_addr(struct nft_handle *h, 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;
+ uint8_t reg;
+ int i, j;
for (i = 0; i < len; i++) {
if (m[i] != 0xff) {
@@ -174,29 +187,36 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
break;
}
}
+ for (j = i + 1; !bitwise && j < len; j++)
+ bitwise = !!m[j];
if (!bitwise)
len = i;
- add_payload(r, offset, len, base);
+ add_payload(h, r, offset, len, base, &reg);
if (bitwise)
- add_bitwise(r, mask, len);
+ add_bitwise(h, r, mask, len, reg, &reg);
- add_cmp_ptr(r, op, data, len);
+ add_cmp_ptr(r, op, data, len, reg);
}
-void add_proto(struct nftnl_rule *r, int offset, size_t len,
- uint8_t proto, uint32_t op)
+void add_proto(struct nft_handle *h, struct nftnl_rule *r,
+ int offset, size_t len, uint8_t proto, uint32_t op)
{
- add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
- add_cmp_u8(r, proto, op);
+ uint8_t reg;
+
+ add_payload(h, r, offset, len, NFT_PAYLOAD_NETWORK_HEADER, &reg);
+ add_cmp_u8(r, proto, op, reg);
}
-void add_l4proto(struct nftnl_rule *r, uint8_t proto, uint32_t op)
+void add_l4proto(struct nft_handle *h, struct nftnl_rule *r,
+ uint8_t proto, uint32_t op)
{
- add_meta(r, NFT_META_L4PROTO);
- add_cmp_u8(r, proto, op);
+ uint8_t reg;
+
+ add_meta(h, r, NFT_META_L4PROTO, &reg);
+ add_cmp_u8(r, proto, op, reg);
}
bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
@@ -233,607 +253,20 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
return true;
}
-static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned char *mask)
+void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op)
{
- if (len == 0)
- return;
-
- memcpy(dst, name, len);
- if (name[len - 1] == '\0') {
- if (mask)
- memset(mask, 0xff, len);
- return;
- }
-
- if (len >= IFNAMSIZ)
- return;
-
- /* wildcard */
- dst[len++] = '+';
- if (len >= IFNAMSIZ)
- return;
- dst[len++] = 0;
- if (mask)
- memset(mask, 0xff, len - 2);
-}
-
-int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
- unsigned char *iniface_mask, char *outiface,
- unsigned char *outiface_mask, uint8_t *invflags)
-{
- uint32_t value;
- const void *ifname;
uint32_t len;
- switch(key) {
- case NFT_META_IIF:
- value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
- if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
- *invflags |= IPT_INV_VIA_IN;
-
- if_indextoname(value, iniface);
-
- memset(iniface_mask, 0xff, strlen(iniface)+1);
- break;
- case NFT_META_OIF:
- value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA);
- if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
- *invflags |= IPT_INV_VIA_OUT;
-
- if_indextoname(value, outiface);
-
- memset(outiface_mask, 0xff, strlen(outiface)+1);
- break;
- case NFT_META_BRI_IIFNAME:
- case NFT_META_IIFNAME:
- ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
- if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
- *invflags |= IPT_INV_VIA_IN;
-
- parse_ifname(ifname, len, iniface, iniface_mask);
- break;
- case NFT_META_BRI_OIFNAME:
- case NFT_META_OIFNAME:
- ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
- if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
- *invflags |= IPT_INV_VIA_OUT;
-
- parse_ifname(ifname, len, outiface, outiface_mask);
- break;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- uint32_t tg_len;
- const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME);
- const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len);
- struct xtables_target *target;
- struct xt_entry_target *t;
- size_t size;
- void *data = ctx->cs;
-
- target = xtables_find_target(targname, XTF_TRY_LOAD);
- if (target == NULL)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len;
-
- t = xtables_calloc(1, size);
- memcpy(&t->data, targinfo, tg_len);
- t->u.target_size = size;
- t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV);
- strcpy(t->u.user.name, target->name);
-
- target->t = t;
-
- ctx->h->ops->parse_target(target, data);
-}
-
-static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- uint32_t mt_len;
- const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME);
- const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len);
- struct xtables_match *match;
- struct xtables_rule_match **matches;
- struct xt_entry_match *m;
-
- switch (ctx->h->family) {
- case NFPROTO_IPV4:
- case NFPROTO_IPV6:
- case NFPROTO_BRIDGE:
- matches = &ctx->cs->matches;
- break;
- default:
- fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n",
- ctx->h->family);
- exit(EXIT_FAILURE);
- }
-
- match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches);
- if (match == NULL)
- return;
-
- m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len);
- memcpy(&m->data, mt_info, mt_len);
- m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match));
- m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV);
- strcpy(m->u.user.name, match->name);
-
- match->m = m;
-
- if (ctx->h->ops->parse_match != NULL)
- ctx->h->ops->parse_match(match, ctx->cs);
-}
-
-void print_proto(uint16_t proto, int invert)
-{
- const struct protoent *pent = getprotobynumber(proto);
-
- if (invert)
- printf("! ");
-
- if (pent) {
- printf("-p %s ", pent->p_name);
- return;
- }
-
- printf("-p %u ", proto);
+ memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen);
+ *op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
}
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
{
- uint32_t len;
uint8_t op;
- memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen);
- op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
- if (op == NFT_CMP_NEQ)
- *inv = true;
- else
- *inv = false;
-}
-
-static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
-{
- struct xtables_target *target;
- struct xt_entry_target *t;
- unsigned int size;
- const char *targname;
-
- switch (ctx->meta.key) {
- case NFT_META_NFTRACE:
- if (ctx->immediate.data[0] == 0)
- return;
- targname = "TRACE";
- break;
- default:
- return;
- }
-
- target = xtables_find_target(targname, XTF_TRY_LOAD);
- if (target == NULL)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size;
-
- t = xtables_calloc(1, size);
- t->u.target_size = size;
- t->u.user.revision = target->revision;
- strcpy(t->u.user.name, targname);
-
- target->t = t;
-
- ctx->h->ops->parse_target(target, ctx->cs);
-}
-
-static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY);
-
- if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG) &&
- (ctx->flags & NFT_XT_CTX_IMMEDIATE) &&
- nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG) == ctx->immediate.reg) {
- ctx->flags &= ~NFT_XT_CTX_IMMEDIATE;
- nft_meta_set_to_target(ctx);
- return;
- }
-
- ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
- ctx->flags |= NFT_XT_CTX_META;
-}
-
-static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
- memcpy(&ctx->prev_payload, &ctx->payload,
- sizeof(ctx->prev_payload));
- ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD;
- }
-
- ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
- ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
- ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET);
- ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN);
- ctx->flags |= NFT_XT_CTX_PAYLOAD;
-}
-
-static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- uint32_t reg, len;
- const void *data;
-
- reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG);
- if (ctx->reg && reg != ctx->reg)
- return;
-
- data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len);
- memcpy(ctx->bitwise.xor, data, len);
- data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len);
- memcpy(ctx->bitwise.mask, data, len);
- ctx->flags |= NFT_XT_CTX_BITWISE;
-}
-
-static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- void *data = ctx->cs;
- uint32_t reg;
-
- reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
- if (ctx->reg && reg != ctx->reg)
- return;
-
- if (ctx->flags & NFT_XT_CTX_META) {
- ctx->h->ops->parse_meta(ctx, e, data);
- ctx->flags &= ~NFT_XT_CTX_META;
- }
- /* bitwise context is interpreted from payload */
- if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
- ctx->h->ops->parse_payload(ctx, e, data);
- ctx->flags &= ~NFT_XT_CTX_PAYLOAD;
- }
-}
-
-static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters)
-{
- counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS);
- counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES);
-}
-
-static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
- const char *jumpto = NULL;
- bool nft_goto = false;
- void *data = ctx->cs;
- int verdict;
-
- if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
- const void *imm_data;
- uint32_t len;
-
- imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len);
-
- if (len > sizeof(ctx->immediate.data))
- return;
-
- memcpy(ctx->immediate.data, imm_data, len);
- ctx->immediate.len = len;
- ctx->immediate.reg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG);
- ctx->flags |= NFT_XT_CTX_IMMEDIATE;
- return;
- }
-
- verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT);
- /* Standard target? */
- switch(verdict) {
- case NF_ACCEPT:
- jumpto = "ACCEPT";
- break;
- case NF_DROP:
- jumpto = "DROP";
- break;
- case NFT_RETURN:
- jumpto = "RETURN";
- break;;
- case NFT_GOTO:
- nft_goto = true;
- /* fall through */
- case NFT_JUMP:
- jumpto = chain;
- break;
- }
-
- ctx->h->ops->parse_immediate(jumpto, nft_goto, data);
-}
-
-static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
-{
- __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST);
- __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT);
- __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE);
- struct xtables_rule_match **matches;
- struct xtables_match *match;
- struct xt_rateinfo *rinfo;
- size_t size;
-
- switch (ctx->h->family) {
- case NFPROTO_IPV4:
- case NFPROTO_IPV6:
- case NFPROTO_BRIDGE:
- matches = &ctx->cs->matches;
- break;
- default:
- fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n",
- ctx->h->family);
- exit(EXIT_FAILURE);
- }
-
- match = xtables_find_match("limit", XTF_TRY_LOAD, matches);
- if (match == NULL)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size;
- match->m = xtables_calloc(1, size);
- match->m->u.match_size = size;
- strcpy(match->m->u.user.name, match->name);
- match->m->u.user.revision = match->revision;
- xs_init_match(match);
-
- rinfo = (void *)match->m->data;
- rinfo->avg = XT_LIMIT_SCALE * unit / rate;
- rinfo->burst = burst;
-
- if (ctx->h->ops->parse_match != NULL)
- ctx->h->ops->parse_match(match, ctx->cs);
-}
-
-static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h,
- struct nftnl_expr *e)
-{
- if (ctx->h->ops->parse_lookup)
- ctx->h->ops->parse_lookup(ctx, e, NULL);
-}
-
-void nft_rule_to_iptables_command_state(struct nft_handle *h,
- const struct nftnl_rule *r,
- struct iptables_command_state *cs)
-{
- struct nftnl_expr_iter *iter;
- struct nftnl_expr *expr;
- struct nft_xt_ctx ctx = {
- .cs = cs,
- .h = h,
- .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE),
- };
-
- iter = nftnl_expr_iter_create(r);
- if (iter == NULL)
- return;
-
- ctx.iter = iter;
- expr = nftnl_expr_iter_next(iter);
- while (expr != NULL) {
- const char *name =
- nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
-
- if (strcmp(name, "counter") == 0)
- nft_parse_counter(expr, &ctx.cs->counters);
- else if (strcmp(name, "payload") == 0)
- nft_parse_payload(&ctx, expr);
- else if (strcmp(name, "meta") == 0)
- nft_parse_meta(&ctx, expr);
- else if (strcmp(name, "bitwise") == 0)
- nft_parse_bitwise(&ctx, expr);
- else if (strcmp(name, "cmp") == 0)
- nft_parse_cmp(&ctx, expr);
- else if (strcmp(name, "immediate") == 0)
- nft_parse_immediate(&ctx, expr);
- else if (strcmp(name, "match") == 0)
- nft_parse_match(&ctx, expr);
- else if (strcmp(name, "target") == 0)
- nft_parse_target(&ctx, expr);
- else if (strcmp(name, "limit") == 0)
- nft_parse_limit(&ctx, expr);
- else if (strcmp(name, "lookup") == 0)
- nft_parse_lookup(&ctx, h, expr);
-
- expr = nftnl_expr_iter_next(iter);
- }
-
- nftnl_expr_iter_destroy(iter);
-
- if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) {
- const void *data;
- uint32_t len, size;
- const char *comment;
-
- data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len);
- comment = get_comment(data, len);
- if (comment) {
- struct xtables_match *match;
- struct xt_entry_match *m;
-
- match = xtables_find_match("comment", XTF_TRY_LOAD,
- &cs->matches);
- if (match == NULL)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_match))
- + match->size;
- m = xtables_calloc(1, size);
-
- strncpy((char *)m->data, comment, match->size - 1);
- m->u.match_size = size;
- m->u.user.revision = 0;
- strcpy(m->u.user.name, match->name);
-
- match->m = m;
- }
- }
-
- if (cs->target != NULL) {
- cs->jumpto = cs->target->name;
- } else if (cs->jumpto != NULL) {
- struct xt_entry_target *t;
- uint32_t size;
-
- cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
- if (!cs->target)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
- t = xtables_calloc(1, size);
- t->u.target_size = size;
- t->u.user.revision = cs->target->revision;
- strcpy(t->u.user.name, cs->jumpto);
- cs->target->t = t;
- } else {
- cs->jumpto = "";
- }
-}
-
-void nft_clear_iptables_command_state(struct iptables_command_state *cs)
-{
- xtables_rule_matches_free(&cs->matches);
- if (cs->target) {
- free(cs->target->t);
- cs->target->t = NULL;
-
- if (cs->target == cs->target->next) {
- free(cs->target);
- cs->target = NULL;
- }
- }
-}
-
-void print_header(unsigned int format, const char *chain, const char *pol,
- const struct xt_counters *counters, bool basechain,
- uint32_t refs, uint32_t entries)
-{
- printf("Chain %s", chain);
- if (basechain) {
- printf(" (policy %s", pol);
- if (!(format & FMT_NOCOUNTS)) {
- fputc(' ', stdout);
- xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
- fputs("packets, ", stdout);
- xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
- fputs("bytes", stdout);
- }
- printf(")\n");
- } else {
- printf(" (%u references)\n", refs);
- }
-
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4s ", "%s "), "num");
- if (!(format & FMT_NOCOUNTS)) {
- if (format & FMT_KILOMEGAGIGA) {
- printf(FMT("%5s ","%s "), "pkts");
- printf(FMT("%5s ","%s "), "bytes");
- } else {
- printf(FMT("%8s ","%s "), "pkts");
- printf(FMT("%10s ","%s "), "bytes");
- }
- }
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ","%s "), "target");
- fputs(" prot ", stdout);
- if (format & FMT_OPTIONS)
- fputs("opt", stdout);
- if (format & FMT_VIA) {
- printf(FMT(" %-6s ","%s "), "in");
- printf(FMT("%-6s ","%s "), "out");
- }
- printf(FMT(" %-19s ","%s "), "source");
- printf(FMT(" %-19s "," %s "), "destination");
- printf("\n");
-}
-
-void print_rule_details(const struct iptables_command_state *cs,
- const char *targname, uint8_t flags,
- uint8_t invflags, uint8_t proto,
- unsigned int num, unsigned int format)
-{
- if (format & FMT_LINENUMBERS)
- printf(FMT("%-4u ", "%u "), num);
-
- if (!(format & FMT_NOCOUNTS)) {
- xtables_print_num(cs->counters.pcnt, format);
- xtables_print_num(cs->counters.bcnt, format);
- }
-
- if (!(format & FMT_NOTARGET))
- printf(FMT("%-9s ", "%s "), targname ? targname : "");
-
- fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout);
- {
- const char *pname =
- proto_to_name(proto, format&FMT_NUMERIC);
- if (pname)
- printf(FMT("%-5s", "%s "), pname);
- else
- printf(FMT("%-5hu", "%hu "), proto);
- }
-}
-
-static void
-print_iface(char letter, const char *iface, const unsigned char *mask, int inv)
-{
- unsigned int i;
-
- if (mask[0] == 0)
- return;
-
- printf("%s-%c ", inv ? "! " : "", letter);
-
- for (i = 0; i < IFNAMSIZ; i++) {
- if (mask[i] != 0) {
- if (iface[i] != '\0')
- printf("%c", iface[i]);
- } else {
- if (iface[i-1] != '\0')
- printf("+");
- break;
- }
- }
-
- printf(" ");
-}
-
-void save_rule_details(const struct iptables_command_state *cs,
- uint8_t invflags, uint16_t proto,
- const char *iniface,
- unsigned const char *iniface_mask,
- const char *outiface,
- unsigned const char *outiface_mask)
-{
- if (iniface != NULL) {
- print_iface('i', iniface, iniface_mask,
- invflags & IPT_INV_VIA_IN);
- }
- if (outiface != NULL) {
- print_iface('o', outiface, outiface_mask,
- invflags & IPT_INV_VIA_OUT);
- }
-
- if (proto > 0) {
- const struct protoent *pent = getprotobynumber(proto);
-
- if (invflags & XT_INV_PROTO)
- printf("! ");
-
- if (pent)
- printf("-p %s ", pent->p_name);
- else
- printf("-p %u ", proto);
- }
+ __get_cmp_data(e, data, dlen, &op);
+ *inv = (op == NFT_CMP_NEQ);
}
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy)
@@ -854,33 +287,33 @@ void save_matches_and_target(const struct iptables_command_state *cs,
for (matchp = cs->matches; matchp; matchp = matchp->next) {
if (matchp->match->alias) {
- printf("-m %s",
+ printf(" -m %s",
matchp->match->alias(matchp->match->m));
} else
- printf("-m %s", matchp->match->name);
+ printf(" -m %s", matchp->match->name);
if (matchp->match->save != NULL) {
/* cs->fw union makes the trick */
matchp->match->save(fw, matchp->match->m);
}
- printf(" ");
}
if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS)
- printf("-c %llu %llu ",
+ printf(" -c %llu %llu",
(unsigned long long)cs->counters.pcnt,
(unsigned long long)cs->counters.bcnt);
if (cs->target != NULL) {
if (cs->target->alias) {
- printf("-j %s", cs->target->alias(cs->target->t));
+ printf(" -j %s", cs->target->alias(cs->target->t));
} else
- printf("-j %s", cs->jumpto);
+ printf(" -j %s", cs->jumpto);
- if (cs->target->save != NULL)
+ if (cs->target->save != NULL) {
cs->target->save(fw, cs->target->t);
+ }
} else if (strlen(cs->jumpto) > 0) {
- printf("-%c %s", goto_flag ? 'g' : 'j', cs->jumpto);
+ printf(" -%c %s", goto_flag ? 'g' : 'j', cs->jumpto);
}
printf("\n");
@@ -933,6 +366,7 @@ bool compare_matches(struct xtables_rule_match *mt1,
for (mp1 = mt1, mp2 = mt2; mp1 && mp2; mp1 = mp1->next, mp2 = mp2->next) {
struct xt_entry_match *m1 = mp1->match->m;
struct xt_entry_match *m2 = mp2->match->m;
+ size_t cmplen = mp1->match->userspacesize;
if (strcmp(m1->u.user.name, m2->u.user.name) != 0) {
DEBUGP("mismatching match name\n");
@@ -944,9 +378,13 @@ bool compare_matches(struct xtables_rule_match *mt1,
return false;
}
- if (memcmp(m1->data, m2->data,
- mp1->match->userspacesize) != 0) {
+ if (!strcmp(m1->u.user.name, "among"))
+ cmplen = m1->u.match_size - sizeof(*m1);
+
+ if (memcmp(m1->data, m2->data, cmplen) != 0) {
DEBUGP("mismatch match data\n");
+ DEBUG_HEXDUMP("m1->data", m1->data, cmplen);
+ DEBUG_HEXDUMP("m2->data", m2->data, cmplen);
return false;
}
}
@@ -979,17 +417,11 @@ bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2)
return true;
}
-void nft_ipv46_parse_target(struct xtables_target *t, void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->target = t;
-}
-
void nft_check_xt_legacy(int family, bool is_ipt_save)
{
static const char tables6[] = "/proc/net/ip6_tables_names";
static const char tables4[] = "/proc/net/ip_tables_names";
+ static const char tablesa[] = "/proc/net/arp_tables_names";
const char *prefix = "ip";
FILE *fp = NULL;
char buf[1024];
@@ -1002,6 +434,10 @@ void nft_check_xt_legacy(int family, bool is_ipt_save)
fp = fopen(tables6, "r");
prefix = "ip6";
break;
+ case NFPROTO_ARP:
+ fp = fopen(tablesa, "r");
+ prefix = "arp";
+ break;
default:
break;
}
@@ -1014,3 +450,18 @@ void nft_check_xt_legacy(int family, bool is_ipt_save)
prefix, prefix, is_ipt_save ? "-save" : "");
fclose(fp);
}
+
+enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size)
+{
+ /* convert size to NETLINK_ALIGN-sized chunks */
+ size = (size + NETLINK_ALIGN - 1) / NETLINK_ALIGN;
+
+ /* map 16byte reg to 4byte one */
+ if (reg < __NFT_REG_MAX)
+ reg = NFT_REG32_00 + (reg - 1) * NFT_REG_SIZE / NFT_REG32_SIZE;
+
+ reg += size;
+ assert(reg <= NFT_REG32_15);
+
+ return reg;
+}
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index da4ba9d2..51d1e460 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -11,9 +11,9 @@
#include <linux/netfilter/nf_tables.h>
#include "xshared.h"
+#include "nft-ruleparse.h"
#ifdef DEBUG
-#define NLDEBUG
#define DEBUG_DEL
#endif
@@ -35,98 +35,73 @@
| FMT_NUMERIC | FMT_NOTABLE)
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
+struct nft_rule_ctx;
struct xtables_args;
struct nft_handle;
struct xt_xlate;
-enum {
- NFT_XT_CTX_PAYLOAD = (1 << 0),
- NFT_XT_CTX_META = (1 << 1),
- NFT_XT_CTX_BITWISE = (1 << 2),
- NFT_XT_CTX_IMMEDIATE = (1 << 3),
- NFT_XT_CTX_PREV_PAYLOAD = (1 << 4),
-};
-
-struct nft_xt_ctx {
- struct iptables_command_state *cs;
- struct nftnl_expr_iter *iter;
- struct nft_handle *h;
- uint32_t flags;
- const char *table;
-
- uint32_t reg;
- struct {
- uint32_t base;
- uint32_t offset;
- uint32_t len;
- } payload, prev_payload;
- struct {
- uint32_t key;
- } meta;
- struct {
- uint32_t data[4];
- uint32_t len, reg;
- } immediate;
- struct {
- uint32_t mask[4];
- uint32_t xor[4];
- } bitwise;
-};
-
struct nft_family_ops {
- int (*add)(struct nft_handle *h, struct nftnl_rule *r, void *data);
- bool (*is_same)(const void *data_a,
- const void *data_b);
+ int (*add)(struct nft_handle *h, struct nft_rule_ctx *ctx,
+ struct nftnl_rule *r, struct iptables_command_state *cs);
+ bool (*is_same)(const struct iptables_command_state *cs_a,
+ const struct iptables_command_state *cs_b);
void (*print_payload)(struct nftnl_expr *e,
struct nftnl_expr_iter *iter);
- void (*parse_meta)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_payload)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_bitwise)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
- void *data);
- void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data);
+ void (*set_goto_flag)(struct iptables_command_state *cs);
void (*print_table_header)(const char *tablename);
void (*print_header)(unsigned int format, const char *chain,
const char *pol,
- const struct xt_counters *counters, bool basechain,
- uint32_t refs, uint32_t entries);
+ const struct xt_counters *counters,
+ int refs, uint32_t entries);
void (*print_rule)(struct nft_handle *h, struct nftnl_rule *r,
unsigned int num, unsigned int format);
- void (*save_rule)(const void *data, unsigned int format);
+ void (*save_rule)(const struct iptables_command_state *cs,
+ unsigned int format);
void (*save_chain)(const struct nftnl_chain *c, const char *policy);
- void (*proto_parse)(struct iptables_command_state *cs,
- struct xtables_args *args);
- void (*post_parse)(int command, struct iptables_command_state *cs,
- struct xtables_args *args);
- void (*parse_match)(struct xtables_match *m, void *data);
- void (*parse_target)(struct xtables_target *t, void *data);
- void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r,
+ struct nft_ruleparse_ops *rule_parse;
+ struct xt_cmd_parse_ops cmd_parse;
+ void (*init_cs)(struct iptables_command_state *cs);
+ bool (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r,
struct iptables_command_state *cs);
void (*clear_cs)(struct iptables_command_state *cs);
- int (*xlate)(const void *data, struct xt_xlate *xl);
+ int (*xlate)(const struct iptables_command_state *cs,
+ struct xt_xlate *xl);
+ int (*add_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ bool append, int rulenum);
+ int (*delete_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose);
+ int (*check_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose);
+ int (*replace_entry)(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ struct xtables_args *args, bool verbose,
+ int rulenum);
};
-void add_meta(struct nftnl_rule *r, uint32_t key);
-void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base);
-void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len);
-void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor);
-void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len);
-void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op);
-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, enum nft_payload_bases base, int offset,
+void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key, uint8_t *dreg);
+void add_payload(struct nft_handle *h, struct nftnl_rule *r, int offset, int len, uint32_t base, uint8_t *dreg);
+void add_bitwise(struct nft_handle *h, struct nftnl_rule *r, uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg);
+void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r, uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg);
+void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len, uint8_t sreg);
+void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg);
+void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg);
+void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg);
+void add_iface(struct nft_handle *h, struct nftnl_rule *r,
+ char *iface, uint32_t key, uint32_t op);
+void add_addr(struct nft_handle *h, 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,
+void add_proto(struct nft_handle *h, struct nftnl_rule *r, int offset, size_t len,
uint8_t proto, uint32_t op);
-void add_l4proto(struct nftnl_rule *r, uint8_t proto, uint32_t op);
+void add_l4proto(struct nft_handle *h, struct nftnl_rule *r, uint8_t proto, uint32_t op);
void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv);
bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
@@ -136,30 +111,10 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
unsigned const char *b_iniface_mask,
unsigned const char *b_outiface_mask);
-int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
- unsigned char *iniface_mask, char *outiface,
- unsigned char *outiface_mask, uint8_t *invflags);
-void print_proto(uint16_t proto, int invert);
+void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op);
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv);
-void nft_rule_to_iptables_command_state(struct nft_handle *h,
- const struct nftnl_rule *r,
- struct iptables_command_state *cs);
-void nft_clear_iptables_command_state(struct iptables_command_state *cs);
-void print_header(unsigned int format, const char *chain, const char *pol,
- const struct xt_counters *counters, bool basechain,
- uint32_t refs, uint32_t entries);
-void print_rule_details(const struct iptables_command_state *cs,
- const char *targname, uint8_t flags,
- uint8_t invflags, uint8_t proto,
- unsigned int num, unsigned int format);
void print_matches_and_target(struct iptables_command_state *cs,
unsigned int format);
-void save_rule_details(const struct iptables_command_state *cs,
- uint8_t invflags, uint16_t proto,
- const char *iniface,
- unsigned const char *iniface_mask,
- const char *outiface,
- unsigned const char *outiface_mask);
void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy);
void save_matches_and_target(const struct iptables_command_state *cs,
bool goto_flag, const void *fw,
@@ -167,55 +122,9 @@ void save_matches_and_target(const struct iptables_command_state *cs,
struct nft_family_ops *nft_family_ops_lookup(int family);
-void nft_ipv46_parse_target(struct xtables_target *t, void *data);
-
bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2);
bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2);
-struct addr_mask {
- union {
- struct in_addr *v4;
- struct in6_addr *v6;
- } addr;
-
- unsigned int naddrs;
-
- union {
- struct in_addr *v4;
- struct in6_addr *v6;
- } mask;
-};
-
-struct xtables_args {
- int family;
- uint16_t proto;
- uint8_t flags;
- uint8_t invflags;
- char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
- unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
- bool goto_set;
- const char *shostnetworkmask, *dhostnetworkmask;
- const char *pcnt, *bcnt;
- struct addr_mask s, d;
- unsigned long long pcnt_cnt, bcnt_cnt;
-};
-
-struct nft_xt_cmd_parse {
- unsigned int command;
- unsigned int rulenum;
- char *table;
- const char *chain;
- const char *newname;
- const char *policy;
- bool restore;
- int verbose;
- bool xlate;
-};
-
-void do_parse(struct nft_handle *h, int argc, char *argv[],
- struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
- struct xtables_args *args);
-
struct nftnl_chain_list;
struct nft_xt_restore_cb {
@@ -249,7 +158,9 @@ void xtables_restore_parse(struct nft_handle *h,
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))
+/* simplified nftables:include/netlink.h, netlink_padded_len() */
+#define NETLINK_ALIGN 4
+
+enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size);
#endif
diff --git a/iptables/nft.c b/iptables/nft.c
index 411e2597..884cc77e 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -39,6 +39,8 @@
#include <linux/netfilter/nf_tables_compat.h>
#include <linux/netfilter/xt_limit.h>
+#include <linux/netfilter/xt_NFLOG.h>
+#include <linux/netfilter/xt_mark.h>
#include <libmnl/libmnl.h>
#include <libnftnl/gen.h>
@@ -88,11 +90,11 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
#define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
-/* selected batch page is 256 Kbytes long to load ruleset of
- * half a million rules without hitting -EMSGSIZE due to large
- * iovec.
+/* Selected batch page is 2 Mbytes long to support loading a ruleset of 3.5M
+ * rules matching on source and destination address as well as input and output
+ * interfaces. This is what legacy iptables supports.
*/
-#define BATCH_PAGE_SIZE getpagesize() * 32
+#define BATCH_PAGE_SIZE 2 * 1024 * 1024
static struct nftnl_batch *mnl_batch_init(void)
{
@@ -107,7 +109,9 @@ static struct nftnl_batch *mnl_batch_init(void)
static void mnl_nft_batch_continue(struct nftnl_batch *batch)
{
- assert(nftnl_batch_update(batch) >= 0);
+ int ret = nftnl_batch_update(batch);
+
+ assert(ret >= 0);
}
static uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t genid, uint32_t seqnum)
@@ -143,7 +147,7 @@ struct mnl_err {
static void mnl_err_list_node_add(struct list_head *err_list, int error,
int seqnum)
{
- struct mnl_err *err = malloc(sizeof(struct mnl_err));
+ struct mnl_err *err = xtables_malloc(sizeof(struct mnl_err));
err->seqnum = seqnum;
err->err = error;
@@ -220,8 +224,10 @@ static int mnl_batch_talk(struct nft_handle *h, int numcmds)
int err = 0;
ret = mnl_nft_socket_sendmsg(h, numcmds);
- if (ret == -1)
+ if (ret == -1) {
+ fprintf(stderr, "sendmsg() failed: %s\n", strerror(errno));
return -1;
+ }
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
@@ -288,7 +294,7 @@ static int mnl_append_error(const struct nft_handle *h,
[NFT_COMPAT_TABLE_FLUSH] = "TABLE_FLUSH",
[NFT_COMPAT_CHAIN_ADD] = "CHAIN_ADD",
[NFT_COMPAT_CHAIN_USER_ADD] = "CHAIN_USER_ADD",
- [NFT_COMPAT_CHAIN_USER_DEL] = "CHAIN_USER_DEL",
+ [NFT_COMPAT_CHAIN_DEL] = "CHAIN_DEL",
[NFT_COMPAT_CHAIN_USER_FLUSH] = "CHAIN_USER_FLUSH",
[NFT_COMPAT_CHAIN_UPDATE] = "CHAIN_UPDATE",
[NFT_COMPAT_CHAIN_RENAME] = "CHAIN_RENAME",
@@ -319,7 +325,7 @@ static int mnl_append_error(const struct nft_handle *h,
case NFT_COMPAT_CHAIN_ADD:
case NFT_COMPAT_CHAIN_ZERO:
case NFT_COMPAT_CHAIN_USER_ADD:
- case NFT_COMPAT_CHAIN_USER_DEL:
+ case NFT_COMPAT_CHAIN_DEL:
case NFT_COMPAT_CHAIN_USER_FLUSH:
case NFT_COMPAT_CHAIN_UPDATE:
case NFT_COMPAT_CHAIN_RENAME:
@@ -331,6 +337,7 @@ static int mnl_append_error(const struct nft_handle *h,
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
+ case NFT_COMPAT_RULE_CHANGE_COUNTERS:
snprintf(tcr, sizeof(tcr), "rule in chain %s",
nftnl_rule_get_str(o->rule, NFTNL_RULE_CHAIN));
#if 0
@@ -360,10 +367,7 @@ static struct obj_update *batch_add(struct nft_handle *h, enum obj_update_type t
{
struct obj_update *obj;
- obj = calloc(1, sizeof(struct obj_update));
- if (obj == NULL)
- return NULL;
-
+ obj = xtables_calloc(1, sizeof(struct obj_update));
obj->ptr = ptr;
obj->error.lineno = h->error.lineno;
obj->type = type;
@@ -433,7 +437,7 @@ static void batch_chain_flush(struct nft_handle *h,
}
}
-const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
+static const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
[NFT_TABLE_RAW] = {
.name = "raw",
.type = NFT_TABLE_RAW,
@@ -570,7 +574,7 @@ const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
#include <linux/netfilter_arp.h>
-const struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
+static const struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
[NFT_TABLE_FILTER] = {
.name = "filter",
.type = NFT_TABLE_FILTER,
@@ -593,7 +597,7 @@ const struct builtin_table xtables_arp[NFT_TABLE_MAX] = {
#include <linux/netfilter_bridge.h>
-const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
+static const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
[NFT_TABLE_FILTER] = {
.name = "filter",
.type = NFT_TABLE_FILTER,
@@ -642,6 +646,19 @@ const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
},
},
},
+ [NFT_TABLE_BROUTE] = {
+ .name = "broute",
+ .type = NFT_TABLE_BROUTE,
+ .chains = {
+ {
+ .name = "BROUTING",
+ .type = "filter",
+ .prio = NF_BR_PRI_FIRST,
+ .hook = NF_BR_PRE_ROUTING,
+ },
+ },
+ },
+
};
static int nft_table_builtin_add(struct nft_handle *h,
@@ -657,6 +674,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
if (t == NULL)
return -1;
+ nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family);
nftnl_table_set_str(t, NFTNL_TABLE_NAME, _t->name);
ret = batch_table_add(h, NFT_COMPAT_TABLE_ADD, t) ? 0 : - 1;
@@ -665,7 +683,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
}
static struct nftnl_chain *
-nft_chain_builtin_alloc(const struct builtin_table *table,
+nft_chain_builtin_alloc(int family, const char *tname,
const struct builtin_chain *chain, int policy)
{
struct nftnl_chain *c;
@@ -674,7 +692,8 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
if (c == NULL)
return NULL;
- nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table->name);
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, family);
+ nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, tname);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
@@ -683,21 +702,26 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
+ nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
+ nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
+
return c;
}
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;
- c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT);
+ c = nft_chain_builtin_alloc(h->family, table->name, chain, NF_ACCEPT);
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 +762,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 +772,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 +834,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);
@@ -803,7 +886,22 @@ int nft_restart(struct nft_handle *h)
return 0;
}
-int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
+static const struct builtin_table *builtin_tables_lookup(int family)
+{
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ return xtables_ipv4;
+ case NFPROTO_ARP:
+ return xtables_arp;
+ case NFPROTO_BRIDGE:
+ return xtables_bridge;
+ default:
+ return NULL;
+ }
+}
+
+int nft_init(struct nft_handle *h, int family)
{
memset(h, 0, sizeof(*h));
@@ -821,7 +919,7 @@ int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
xtables_error(PARAMETER_PROBLEM, "Unknown family");
h->portid = mnl_socket_get_portid(h->nl);
- h->tables = t;
+ h->tables = builtin_tables_lookup(family);
h->cache = &h->__cache[0];
h->family = family;
@@ -850,15 +948,16 @@ void nft_fini(struct nft_handle *h)
mnl_socket_close(h->nl);
}
-static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh)
+static void nft_chain_print_debug(struct nft_handle *h,
+ struct nftnl_chain *c, struct nlmsghdr *nlh)
{
-#ifdef NLDEBUG
- char tmp[1024];
-
- nftnl_chain_snprintf(tmp, sizeof(tmp), c, 0, 0);
- printf("DEBUG: chain: %s\n", tmp);
- mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
-#endif
+ if (h->verbose > 1) {
+ nftnl_chain_fprintf(stdout, c, 0, 0);
+ fprintf(stdout, "\n");
+ }
+ if (h->verbose > 2)
+ mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
+ sizeof(struct nfgenmsg));
}
static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
@@ -866,6 +965,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
int policy,
const struct xt_counters *counters)
{
+ static const struct xt_counters zero = {};
struct nftnl_chain *c;
const struct builtin_table *_t;
const struct builtin_chain *_c;
@@ -877,12 +977,12 @@ 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) {
/* This is a built-in chain */
- c = nft_chain_builtin_alloc(_t, _c, policy);
+ c = nft_chain_builtin_alloc(h->family, _t->name, _c, policy);
if (c == NULL)
return NULL;
} else {
@@ -890,12 +990,10 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
return NULL;
}
- if (counters) {
- nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES,
- counters->bcnt);
- nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS,
- counters->pcnt);
- }
+ if (!counters)
+ counters = &zero;
+ nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, counters->bcnt);
+ nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, counters->pcnt);
return c;
}
@@ -934,10 +1032,7 @@ static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
nftnl_expr_set(e, NFTNL_EXPR_MT_NAME, m->u.user.name, strlen(m->u.user.name));
nftnl_expr_set_u32(e, NFTNL_EXPR_MT_REV, m->u.user.revision);
- info = calloc(1, m->u.match_size);
- if (info == NULL)
- return -ENOMEM;
-
+ info = xtables_calloc(1, m->u.match_size);
memcpy(info, m->data, m->u.match_size - sizeof(*m));
nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
@@ -1013,16 +1108,32 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table,
}
static struct nftnl_expr *
-gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg)
+__gen_payload(uint32_t base, uint32_t offset, uint32_t len, uint8_t reg)
{
struct nftnl_expr *e = nftnl_expr_alloc("payload");
if (!e)
return NULL;
+
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
- nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, reg);
+
+ return e;
+}
+
+static struct nftnl_expr *
+gen_payload(struct nft_handle *h, uint32_t base, uint32_t offset, uint32_t len,
+ uint8_t *dreg)
+{
+ struct nftnl_expr *e;
+ uint8_t reg;
+
+ reg = NFT_REG_1;
+ e = __gen_payload(base, offset, len, reg);
+ *dreg = reg;
+
return e;
}
@@ -1040,9 +1151,6 @@ gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags)
return e;
}
-/* simplified nftables:include/netlink.h, netlink_padded_len() */
-#define NETLINK_ALIGN 4
-
/* from nftables:include/datatype.h, TYPE_BITS */
#define CONCAT_TYPE_BITS 6
@@ -1067,13 +1175,14 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
struct nftnl_expr *e;
struct nftnl_set *s;
uint32_t flags = 0;
+ uint8_t reg;
int idx = 0;
if (ip) {
type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
len &= ~(NETLINK_ALIGN - 1);
- flags = NFT_SET_INTERVAL;
+ flags = NFT_SET_INTERVAL | NFT_SET_CONCAT;
}
s = add_anon_set(h, table, flags, type, len, cnt);
@@ -1107,21 +1216,23 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
nftnl_set_elem_add(s, elem);
}
- e = gen_payload(NFT_PAYLOAD_LL_HEADER,
- eth_addr_off[dst], ETH_ALEN, NFT_REG_1);
+ e = gen_payload(h, NFT_PAYLOAD_LL_HEADER,
+ eth_addr_off[dst], ETH_ALEN, &reg);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
if (ip) {
- e = gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
- sizeof(struct in_addr), NFT_REG32_02);
+ reg = nft_get_next_reg(reg, ETH_ALEN);
+ e = __gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst],
+ sizeof(struct in_addr), reg);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
}
- e = gen_lookup(NFT_REG_1, "__set%d", set_id, inv);
+ reg = NFT_REG_1;
+ e = gen_lookup(reg, "__set%d", set_id, inv);
if (!e)
return -ENOMEM;
nftnl_rule_add_expr(r, e);
@@ -1138,9 +1249,10 @@ static int add_nft_among(struct nft_handle *h,
if ((data->src.cnt && data->src.ip) ||
(data->dst.cnt && data->dst.ip)) {
uint16_t eth_p_ip = htons(ETH_P_IP);
+ uint8_t reg;
- add_meta(r, NFT_META_PROTOCOL);
- add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2);
+ add_meta(h, r, NFT_META_PROTOCOL, &reg);
+ add_cmp_ptr(r, NFT_CMP_EQ, &eth_p_ip, 2, reg);
}
if (data->src.cnt)
@@ -1153,16 +1265,230 @@ static int add_nft_among(struct nft_handle *h,
return 0;
}
-int add_match(struct nft_handle *h,
+static int expr_gen_range_cmp16(struct nftnl_rule *r,
+ uint16_t lo,
+ uint16_t hi,
+ bool invert, uint8_t reg)
+{
+ struct nftnl_expr *e;
+
+ if (lo == hi) {
+ add_cmp_u16(r, htons(lo), invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg);
+ return 0;
+ }
+
+ if (lo == 0 && hi < 0xffff) {
+ add_cmp_u16(r, htons(hi) , invert ? NFT_CMP_GT : NFT_CMP_LTE, reg);
+ return 0;
+ }
+
+ e = nftnl_expr_alloc("range");
+ if (!e)
+ return -ENOMEM;
+
+ nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_SREG, reg);
+ nftnl_expr_set_u32(e, NFTNL_EXPR_RANGE_OP, invert ? NFT_RANGE_NEQ : NFT_RANGE_EQ);
+
+ lo = htons(lo);
+ nftnl_expr_set(e, NFTNL_EXPR_RANGE_FROM_DATA, &lo, sizeof(lo));
+ hi = htons(hi);
+ nftnl_expr_set(e, NFTNL_EXPR_RANGE_TO_DATA, &hi, sizeof(hi));
+
+ nftnl_rule_add_expr(r, e);
+ return 0;
+}
+
+static int add_nft_tcpudp(struct nft_handle *h,struct nftnl_rule *r,
+ uint16_t src[2], bool invert_src,
+ uint16_t dst[2], bool invert_dst)
+{
+ struct nftnl_expr *expr;
+ uint8_t op = NFT_CMP_EQ;
+ uint8_t reg;
+ int ret;
+
+ if (!invert_src &&
+ src[0] && src[0] == src[1] &&
+ dst[0] && dst[0] == dst[1] &&
+ invert_src == invert_dst) {
+ uint32_t combined = dst[0] | (src[0] << 16);
+
+ expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 4, &reg);
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, expr);
+ add_cmp_u32(r, htonl(combined), op, reg);
+ return 0;
+ }
+
+ if (src[0] || src[1] < UINT16_MAX || invert_src) {
+ expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 0, 2, &reg);
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, expr);
+ ret = expr_gen_range_cmp16(r, src[0], src[1], invert_src, reg);
+ if (ret)
+ return ret;
+ }
+
+ if (dst[0] || dst[1] < UINT16_MAX || invert_dst) {
+ expr = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 2, 2, &reg);
+ if (!expr)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, expr);
+ ret = expr_gen_range_cmp16(r, dst[0], dst[1], invert_dst, reg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* without this, "iptables -A INPUT -m udp" is
+ * turned into "iptables -A INPUT", which isn't
+ * compatible with iptables-legacy behaviour.
+ */
+static bool udp_all_zero(const struct xt_udp *u)
+{
+ static const struct xt_udp zero = {
+ .spts[1] = 0xffff,
+ .dpts[1] = 0xffff,
+ };
+
+ return memcmp(u, &zero, sizeof(*u)) == 0;
+}
+
+static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_match *m)
+{
+ struct xt_udp *udp = (void *)m->data;
+
+ if (udp->invflags > XT_UDP_INV_MASK ||
+ udp_all_zero(udp)) {
+ struct nftnl_expr *expr = nftnl_expr_alloc("match");
+ int ret;
+
+ ret = __add_match(expr, m);
+ nftnl_rule_add_expr(r, expr);
+ return ret;
+ }
+
+ if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_UDP)
+ xtables_error(PARAMETER_PROBLEM, "UDP match requires '-p udp'");
+
+ return add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT,
+ udp->dpts, udp->invflags & XT_UDP_INV_DSTPT);
+}
+
+static int add_nft_tcpflags(struct nft_handle *h, struct nftnl_rule *r,
+ uint8_t cmp, uint8_t mask,
+ bool invert)
+{
+ struct nftnl_expr *e;
+ uint8_t reg;
+
+ e = gen_payload(h, NFT_PAYLOAD_TRANSPORT_HEADER, 13, 1, &reg);
+
+ if (!e)
+ return -ENOMEM;
+
+ nftnl_rule_add_expr(r, e);
+
+ add_bitwise(h, r, &mask, 1, reg, &reg);
+ add_cmp_u8(r, cmp, invert ? NFT_CMP_NEQ : NFT_CMP_EQ, reg);
+
+ return 0;
+}
+
+static bool tcp_all_zero(const struct xt_tcp *t)
+{
+ static const struct xt_tcp zero = {
+ .spts[1] = 0xffff,
+ .dpts[1] = 0xffff,
+ };
+
+ return memcmp(t, &zero, sizeof(*t)) == 0;
+}
+
+static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_match *m)
+{
+ static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT | XT_TCP_INV_FLAGS;
+ struct xt_tcp *tcp = (void *)m->data;
+
+ if (tcp->invflags & ~supported || tcp->option ||
+ tcp_all_zero(tcp)) {
+ struct nftnl_expr *expr = nftnl_expr_alloc("match");
+ int ret;
+
+ ret = __add_match(expr, m);
+ nftnl_rule_add_expr(r, expr);
+ return ret;
+ }
+
+ if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_TCP)
+ xtables_error(PARAMETER_PROBLEM, "TCP match requires '-p tcp'");
+
+ if (tcp->flg_mask) {
+ int ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask,
+ tcp->invflags & XT_TCP_INV_FLAGS);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return add_nft_tcpudp(h, r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT,
+ tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT);
+}
+
+static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_match *m)
+{
+ struct xt_mark_mtinfo1 *mark = (void *)m->data;
+ uint8_t reg;
+ int op;
+
+ add_meta(h, r, NFT_META_MARK, &reg);
+ if (mark->mask != 0xffffffff)
+ add_bitwise(h, r, (uint8_t *)&mark->mask, sizeof(uint32_t), reg, &reg);
+
+ if (mark->invert)
+ op = NFT_CMP_NEQ;
+ else
+ op = NFT_CMP_EQ;
+
+ add_cmp_u32(r, mark->mark, op, reg);
+
+ return 0;
+}
+
+int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
struct nftnl_rule *r, struct xt_entry_match *m)
{
struct nftnl_expr *expr;
int ret;
- if (!strcmp(m->u.user.name, "limit"))
- return add_nft_limit(r, m);
- else if (!strcmp(m->u.user.name, "among"))
- return add_nft_among(h, r, m);
+ switch (ctx->command) {
+ case NFT_COMPAT_RULE_APPEND:
+ case NFT_COMPAT_RULE_INSERT:
+ case NFT_COMPAT_RULE_REPLACE:
+ if (!strcmp(m->u.user.name, "limit"))
+ return add_nft_limit(r, m);
+ else if (!strcmp(m->u.user.name, "among"))
+ return add_nft_among(h, r, m);
+ else if (!strcmp(m->u.user.name, "udp"))
+ return add_nft_udp(h, r, m);
+ else if (!strcmp(m->u.user.name, "tcp"))
+ return add_nft_tcp(h, r, m);
+ else if (!strcmp(m->u.user.name, "mark"))
+ return add_nft_mark(h, r, m);
+ break;
+ default:
+ break;
+ }
expr = nftnl_expr_alloc("match");
if (expr == NULL)
@@ -1182,10 +1508,7 @@ static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
strlen(t->u.user.name));
nftnl_expr_set_u32(e, NFTNL_EXPR_TG_REV, t->u.user.revision);
- info = calloc(1, t->u.target_size);
- if (info == NULL)
- return -ENOMEM;
-
+ info = xtables_calloc(1, t->u.target_size);
memcpy(info, t->data, t->u.target_size - sizeof(*t));
nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
@@ -1266,38 +1589,66 @@ int add_verdict(struct nftnl_rule *r, int verdict)
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
bool goto_set)
{
- int ret = 0;
-
- /* If no target at all, add nothing (default to continue) */
- if (cs->target != NULL) {
- /* Standard target? */
- if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
- ret = add_verdict(r, NF_ACCEPT);
- else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
- ret = add_verdict(r, NF_DROP);
- else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
- ret = add_verdict(r, NFT_RETURN);
- else
- ret = add_target(r, cs->target->t);
- } else if (strlen(cs->jumpto) > 0) {
- /* Not standard, then it's a go / jump to chain */
- if (goto_set)
- ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
- else
- ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
- }
- return ret;
-}
-
-static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
-{
-#ifdef NLDEBUG
- char tmp[1024];
-
- nftnl_rule_snprintf(tmp, sizeof(tmp), r, 0, 0);
- printf("DEBUG: rule: %s\n", tmp);
- mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg));
-#endif
+ int ret = 0;
+
+ /* If no target at all, add nothing (default to continue) */
+ if (cs->target != NULL) {
+ /* Standard target? */
+ if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
+ ret = add_verdict(r, NF_ACCEPT);
+ else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
+ ret = add_verdict(r, NF_DROP);
+ else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
+ ret = add_verdict(r, NFT_RETURN);
+ else if (strcmp(cs->jumpto, "NFLOG") == 0)
+ ret = add_log(r, cs);
+ else
+ ret = add_target(r, cs->target->t);
+ } else if (strlen(cs->jumpto) > 0) {
+ /* Not standard, then it's a go / jump to chain */
+ if (goto_set)
+ ret = add_jumpto(r, cs->jumpto, NFT_GOTO);
+ else
+ ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
+ }
+ return ret;
+}
+
+int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
+{
+ struct nftnl_expr *expr;
+ struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data;
+
+ expr = nftnl_expr_alloc("log");
+ if (!expr)
+ return -ENOMEM;
+
+ if (info->prefix[0] != '\0')
+ nftnl_expr_set_str(expr, NFTNL_EXPR_LOG_PREFIX,
+ cs->target->udata);
+
+ nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_GROUP, info->group);
+ if (info->flags & XT_NFLOG_F_COPY_LEN)
+ nftnl_expr_set_u32(expr, NFTNL_EXPR_LOG_SNAPLEN,
+ info->len);
+ if (info->threshold)
+ nftnl_expr_set_u16(expr, NFTNL_EXPR_LOG_QTHRESHOLD,
+ info->threshold);
+
+ nftnl_rule_add_expr(r, expr);
+ return 0;
+}
+
+static void nft_rule_print_debug(struct nft_handle *h,
+ struct nftnl_rule *r, struct nlmsghdr *nlh)
+{
+ if (h->verbose > 1) {
+ nftnl_rule_fprintf(stdout, r, 0, 0);
+ fprintf(stdout, "\n");
+ }
+ if (h->verbose > 2)
+ mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
+ sizeof(struct nfgenmsg));
}
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
@@ -1365,8 +1716,9 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
}
struct nftnl_rule *
-nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
- void *data)
+nft_rule_new(struct nft_handle *h, struct nft_rule_ctx *ctx,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs)
{
struct nftnl_rule *r;
@@ -1378,7 +1730,7 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
- if (h->ops->add(h, r, data) < 0)
+ if (h->ops->add(h, ctx, r, cs) < 0)
goto err;
return r;
@@ -1391,10 +1743,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,21 +1773,22 @@ 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;
}
-void
+bool
nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
enum nft_rule_print type, unsigned int format)
{
const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN);
struct iptables_command_state cs = {};
struct nft_family_ops *ops = h->ops;
+ bool ret;
- ops->rule_to_cs(h, r, &cs);
+ ret = ops->rule_to_cs(h, r, &cs);
if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)))
printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt,
@@ -1444,10 +1797,10 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
/* print chain name */
switch(type) {
case NFT_RULE_APPEND:
- printf("-A %s ", chain);
+ printf("-A %s", chain);
break;
case NFT_RULE_DEL:
- printf("-D %s ", chain);
+ printf("-D %s", chain);
break;
}
@@ -1456,6 +1809,8 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
if (ops->clear_cs)
ops->clear_cs(&cs);
+
+ return ret;
}
static bool nft_rule_is_policy_rule(struct nftnl_rule *r)
@@ -1543,8 +1898,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;
@@ -1565,21 +1921,26 @@ int nft_chain_save(struct nftnl_chain *c, void *data)
struct nft_rule_save_data {
struct nft_handle *h;
unsigned int format;
+ unsigned int errors;
};
-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;
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format);
+ bool ret = nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format);
+
+ if (!ret)
+ d->errors++;
+
r = nftnl_rule_iter_next(iter);
}
@@ -1593,14 +1954,12 @@ 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 = nft_chain_foreach(h, table, nft_rule_save_cb, &d);
- ret = nftnl_chain_list_foreach(list, nft_rule_save_cb, &d);
+ if (ret == 0 && d.errors)
+ xtables_error(VERSION_PROBLEM, "Cannot decode all rules provided by kernel");
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1653,9 +2012,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 +2031,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 +2056,22 @@ 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;
- }
+ nft_cache_sort_chains(h, table);
+
+ 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;
@@ -1728,6 +2082,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (c == NULL)
return 0;
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
if (h->family == NFPROTO_BRIDGE)
@@ -1736,9 +2091,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,27 +2099,29 @@ 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;
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, 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
@@ -1792,82 +2147,92 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
#define NLM_F_NONREC 0x100 /* Do not delete recursively */
#endif
-struct chain_user_del_data {
+struct chain_del_data {
struct nft_handle *handle;
+ const char *chain;
bool verbose;
- int builtin_err;
};
-static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
+static bool nft_may_delete_chain(struct nftnl_chain *c)
{
- struct chain_user_del_data *d = data;
- struct nft_handle *h = d->handle;
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY) &&
+ nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY) != NF_ACCEPT)
+ return false;
- /* don't delete built-in chain */
- if (nft_chain_builtin(c))
- return d->builtin_err;
+ return nftnl_rule_lookup_byindex(c, 0) == NULL;
+}
- if (d->verbose)
+static int __nft_chain_del(struct nft_chain *nc, void *data)
+{
+ struct chain_del_data *d = data;
+ struct nftnl_chain *c = nc->nftnl;
+ struct nft_handle *h = d->handle;
+ bool builtin = nft_chain_builtin(c);
+ struct obj_update *obj;
+ int ret = 0;
+
+ if (d->verbose && !builtin)
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))
+ obj = batch_chain_add(h, NFT_COMPAT_CHAIN_DEL, c);
+ if (!obj)
return -1;
- nftnl_chain_list_del(c);
- return 0;
+ if (builtin) {
+ obj->skip = !nft_may_delete_chain(c);
+ if (obj->skip && d->chain) {
+ /* complain if explicitly requested */
+ errno = EBUSY;
+ ret = -1;
+ }
+ *nc->base_slot = NULL;
+ }
+
+ /* nftnl_chain is freed when deleting the batch object */
+ nc->nftnl = NULL;
+
+ nft_chain_list_del(nc);
+ nft_chain_free(nc);
+ return ret;
}
-int nft_chain_user_del(struct nft_handle *h, const char *chain,
- const char *table, bool verbose)
+int nft_chain_del(struct nft_handle *h, const char *chain,
+ const char *table, bool verbose)
{
- struct chain_user_del_data d = {
+ struct chain_del_data d = {
.handle = h,
+ .chain = chain,
.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;
+ nft_fn = nft_chain_del;
if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
+ c = nft_chain_find(h, table, chain);
if (!c) {
errno = ENOENT;
return 0;
}
- d.builtin_err = -2;
- ret = __nft_chain_user_del(c, &d);
- if (ret == -2)
- errno = EINVAL;
+
+ ret = __nft_chain_del(c, &d);
goto out;
}
- ret = nftnl_chain_list_foreach(list, __nft_chain_user_del, &d);
+ if (verbose)
+ nft_cache_sort_chains(h, table);
+
+ ret = nft_chain_foreach(h, table, __nft_chain_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 +2252,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;
@@ -1897,18 +2263,19 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
}
/* 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();
if (c == NULL)
return 0;
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_FAMILY, h->family);
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
@@ -1957,6 +2324,7 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist
if (t == NULL)
return -1;
+ nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, h->family);
nftnl_table_set_str(t, NFTNL_TABLE_NAME, table);
obj = batch_table_add(h, NFT_COMPAT_TABLE_FLUSH, t);
@@ -2000,7 +2368,8 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r)
nftnl_rule_list_del(r);
- if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE))
+ if (!nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE) &&
+ !nftnl_rule_get_u32(r, NFTNL_RULE_ID))
nftnl_rule_set_u32(r, NFTNL_RULE_ID, ++h->rule_id);
obj = batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r);
@@ -2015,15 +2384,18 @@ static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r,
struct nftnl_rule *rule)
{
struct iptables_command_state _cs = {}, this = {}, *cs = &_cs;
- bool ret = false;
+ bool ret = false, ret_this, ret_that;
- h->ops->rule_to_cs(h, r, &this);
- h->ops->rule_to_cs(h, rule, cs);
+ ret_this = h->ops->rule_to_cs(h, r, &this);
+ ret_that = h->ops->rule_to_cs(h, rule, cs);
DEBUGP("comparing with... ");
#ifdef DEBUG_DEL
nft_rule_print_save(h, r, NFT_RULE_APPEND, 0);
#endif
+ if (!ret_this || !ret_that)
+ DEBUGP("Cannot convert rules: %d %d\n", ret_this, ret_that);
+
if (!h->ops->is_same(cs, &this))
goto out;
@@ -2051,9 +2423,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;
@@ -2082,8 +2455,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;
@@ -2108,8 +2481,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;
@@ -2169,9 +2542,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;
@@ -2204,7 +2577,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:
@@ -2215,8 +2588,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;
@@ -2243,8 +2616,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;
@@ -2267,6 +2640,58 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
return ret;
}
+static int nft_rule_change_counters(struct nft_handle *h, const char *table,
+ const char *chain, struct nftnl_rule *rule,
+ int rulenum, struct xt_counters *counters,
+ uint8_t counter_op, bool verbose)
+{
+ struct iptables_command_state cs = {};
+ struct nftnl_rule *r, *new_rule;
+ struct nft_rule_ctx ctx = {
+ .command = NFT_COMPAT_RULE_APPEND,
+ };
+ struct nft_chain *c;
+
+ nft_fn = nft_rule_change_counters;
+
+ c = nft_chain_find(h, table, chain);
+ if (!c) {
+ errno = ENOENT;
+ return 0;
+ }
+
+ r = nft_rule_find(h, c, rule, rulenum);
+ if (!r) {
+ errno = E2BIG;
+ return 0;
+ }
+
+ DEBUGP("changing counters of rule with handle=%llu\n",
+ (unsigned long long)
+ nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE));
+
+ h->ops->rule_to_cs(h, r, &cs);
+
+ if (counter_op & CTR_OP_INC_PKTS)
+ cs.counters.pcnt += counters->pcnt;
+ else if (counter_op & CTR_OP_DEC_PKTS)
+ cs.counters.pcnt -= counters->pcnt;
+ else
+ cs.counters.pcnt = counters->pcnt;
+
+ if (counter_op & CTR_OP_INC_BYTES)
+ cs.counters.bcnt += counters->bcnt;
+ else if (counter_op & CTR_OP_DEC_BYTES)
+ cs.counters.bcnt -= counters->bcnt;
+ else
+ cs.counters.bcnt = counters->bcnt;
+
+ new_rule = nft_rule_new(h, &ctx, chain, table, &cs);
+ h->ops->clear_cs(&cs);
+
+ return nft_rule_append(h, chain, table, new_rule, r, verbose);
+}
+
static int
__nft_rule_list(struct nft_handle *h, struct nftnl_chain *c,
int rulenum, unsigned int format,
@@ -2323,10 +2748,10 @@ 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);
uint32_t entries = nft_rule_count(h, c);
struct xt_counters ctrs = {
@@ -2335,11 +2760,12 @@ static void __nft_print_header(struct nft_handle *h,
};
const char *pname = NULL;
- if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
+ if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM) &&
+ nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
h->ops->print_header(format, chain_name, pname,
- &ctrs, basechain, refs - entries, entries);
+ &ctrs, refs - entries, entries);
}
struct nft_rule_list_cb_data {
@@ -2352,7 +2778,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;
@@ -2364,7 +2790,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,
@@ -2377,16 +2803,17 @@ 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) {
c = nft_chain_find(h, table, chain);
- if (!c)
+ if (!c) {
+ errno = ENOENT;
return 0;
+ }
if (rulenum)
d.save_fmt = true; /* skip header printing */
@@ -2397,14 +2824,12 @@ 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;
+ nft_cache_sort_chains(h, table);
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;
}
@@ -2415,8 +2840,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;
@@ -2446,26 +2907,23 @@ 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);
- if (!c)
+ c = nft_chain_find(h, table, chain);
+ if (!c) {
+ errno = ENOENT;
return 0;
+ }
if (!rulenum)
nft_rule_list_chain_save(c, &counters);
@@ -2473,11 +2931,13 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
return nft_rule_list_cb(c, &d);
}
+ nft_cache_sort_chains(h, table);
+
/* 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;
}
@@ -2486,14 +2946,19 @@ 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_rule_ctx ctx = {
+ .command = NFT_COMPAT_RULE_APPEND,
+ };
+ struct nft_chain *c;
int ret = 0;
nft_fn = nft_rule_delete;
c = nft_chain_find(h, table, chain);
- if (!c)
+ if (!c) {
+ errno = ENOENT;
return 0;
+ }
r = nft_rule_find(h, c, NULL, rulenum);
if (r == NULL) {
@@ -2502,10 +2967,11 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
goto error;
}
- nft_rule_to_iptables_command_state(h, r, &cs);
-
+ h->ops->rule_to_cs(h, r, &cs);
cs.counters.pcnt = cs.counters.bcnt = 0;
- new_rule = nft_rule_new(h, chain, table, &cs);
+ new_rule = nft_rule_new(h, &ctx, chain, table, &cs);
+ h->ops->clear_cs(&cs);
+
if (!new_rule)
return 1;
@@ -2515,15 +2981,28 @@ error:
return ret;
}
+static void nft_table_print_debug(struct nft_handle *h,
+ struct nftnl_table *t, struct nlmsghdr *nlh)
+{
+ if (h->verbose > 1) {
+ nftnl_table_fprintf(stdout, t, 0, 0);
+ fprintf(stdout, "\n");
+ }
+ if (h->verbose > 2)
+ mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len,
+ sizeof(struct nfgenmsg));
+}
+
static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
uint16_t flags, uint32_t seq,
struct nftnl_table *table)
{
struct nlmsghdr *nlh;
- nlh = nftnl_table_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
- type, h->family, flags, seq);
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
+ type, h->family, flags, seq);
nftnl_table_nlmsg_build_payload(nlh, table);
+ nft_table_print_debug(h, table, nlh);
}
static void nft_compat_set_batch_add(struct nft_handle *h, uint16_t type,
@@ -2557,6 +3036,12 @@ static void nft_compat_setelem_batch_add(struct nft_handle *h, uint16_t type,
break;
}
nftnl_set_elems_iter_destroy(iter);
+
+ if (h->verbose > 1) {
+ fprintf(stdout, "set ");
+ nftnl_set_fprintf(stdout, set, 0, 0);
+ fprintf(stdout, "\n");
+ }
}
static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
@@ -2565,10 +3050,10 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
{
struct nlmsghdr *nlh;
- nlh = nftnl_chain_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
- type, h->family, flags, seq);
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
+ type, h->family, flags, seq);
nftnl_chain_nlmsg_build_payload(nlh, chain);
- nft_chain_print_debug(chain, nlh);
+ nft_chain_print_debug(h, chain, nlh);
}
static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
@@ -2577,10 +3062,10 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
{
struct nlmsghdr *nlh;
- nlh = nftnl_rule_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
- type, h->family, flags, seq);
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(h->batch),
+ type, h->family, flags, seq);
nftnl_rule_nlmsg_build_payload(nlh, rule);
- nft_rule_print_debug(rule, nlh);
+ nft_rule_print_debug(h, rule, nlh);
}
static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
@@ -2594,7 +3079,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_CHAIN_USER_ADD:
case NFT_COMPAT_CHAIN_ADD:
break;
- case NFT_COMPAT_CHAIN_USER_DEL:
+ case NFT_COMPAT_CHAIN_DEL:
case NFT_COMPAT_CHAIN_USER_FLUSH:
case NFT_COMPAT_CHAIN_UPDATE:
case NFT_COMPAT_CHAIN_RENAME:
@@ -2603,6 +3088,7 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o)
case NFT_COMPAT_RULE_APPEND:
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
+ case NFT_COMPAT_RULE_CHANGE_COUNTERS:
break;
case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_RULE_FLUSH:
@@ -2628,7 +3114,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;
@@ -2676,16 +3162,21 @@ static void nft_refresh_transaction(struct nft_handle *h)
n->skip = !nft_chain_find(h, tablename, chainname);
break;
+ case NFT_COMPAT_CHAIN_DEL:
+ if (!nftnl_chain_get(n->chain, NFTNL_CHAIN_HOOKNUM))
+ break;
+ n->skip = !nft_may_delete_chain(n->chain);
+ break;
case NFT_COMPAT_TABLE_ADD:
case NFT_COMPAT_CHAIN_ADD:
case NFT_COMPAT_CHAIN_ZERO:
- case NFT_COMPAT_CHAIN_USER_DEL:
case NFT_COMPAT_CHAIN_USER_FLUSH:
case NFT_COMPAT_CHAIN_UPDATE:
case NFT_COMPAT_CHAIN_RENAME:
case NFT_COMPAT_RULE_APPEND:
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
+ case NFT_COMPAT_RULE_CHANGE_COUNTERS:
case NFT_COMPAT_RULE_DELETE:
case NFT_COMPAT_SET_ADD:
case NFT_COMPAT_RULE_LIST:
@@ -2745,7 +3236,7 @@ retry:
NLM_F_EXCL, n->seq,
n->chain);
break;
- case NFT_COMPAT_CHAIN_USER_DEL:
+ case NFT_COMPAT_CHAIN_DEL:
nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN,
NLM_F_NONREC, n->seq,
n->chain);
@@ -2776,6 +3267,7 @@ retry:
n->rule);
break;
case NFT_COMPAT_RULE_REPLACE:
+ case NFT_COMPAT_RULE_CHANGE_COUNTERS:
nft_compat_rule_batch_add(h, NFT_MSG_NEWRULE,
NLM_F_CREATE | NLM_F_REPLACE,
n->seq, n->rule);
@@ -2799,6 +3291,7 @@ retry:
case NFT_COMPAT_RULE_ZERO:
case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE:
assert(0);
+ return 0;
}
mnl_nft_batch_continue(h->batch);
@@ -2864,6 +3357,9 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
.eb.bitmask = EBT_NOPROTO,
};
struct nftnl_udata_buf *udata;
+ struct nft_rule_ctx ctx = {
+ .command = NFT_COMPAT_RULE_APPEND,
+ };
struct nft_handle *h = data;
struct nftnl_rule *r;
const char *pname;
@@ -2891,7 +3387,7 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
command_jump(&cs, pname);
- r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
+ r = nft_rule_new(h, &ctx, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
ebt_cs_clean(&cs);
@@ -2925,7 +3421,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)
@@ -2940,14 +3436,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++) {
@@ -2960,7 +3457,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);
+ }
}
}
@@ -2980,6 +3479,8 @@ static int nft_prepare(struct nft_handle *h)
nft_cache_build(h);
list_for_each_entry_safe(cmd, next, &h->cmd_list, head) {
+ h->error.lineno = cmd->error.lineno;
+
switch (cmd->command) {
case NFT_COMPAT_TABLE_FLUSH:
ret = nft_table_flush(h, cmd->table);
@@ -2987,9 +3488,9 @@ static int nft_prepare(struct nft_handle *h)
case NFT_COMPAT_CHAIN_USER_ADD:
ret = nft_chain_user_add(h, cmd->chain, cmd->table);
break;
- case NFT_COMPAT_CHAIN_USER_DEL:
- ret = nft_chain_user_del(h, cmd->chain, cmd->table,
- cmd->verbose);
+ case NFT_COMPAT_CHAIN_DEL:
+ ret = nft_chain_del(h, cmd->chain, cmd->table,
+ cmd->verbose);
break;
case NFT_COMPAT_CHAIN_RESTORE:
ret = nft_chain_restore(h, cmd->chain, cmd->table);
@@ -3045,7 +3546,7 @@ static int nft_prepare(struct nft_handle *h)
case NFT_COMPAT_RULE_CHECK:
assert_chain_exists(h, cmd->table, cmd->jumpto);
ret = nft_rule_check(h, cmd->chain, cmd->table,
- cmd->obj.rule, cmd->rulenum);
+ cmd->obj.rule, cmd->verbose);
break;
case NFT_COMPAT_RULE_ZERO:
ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
@@ -3061,13 +3562,22 @@ 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;
case NFT_COMPAT_TABLE_ADD:
case NFT_COMPAT_CHAIN_ADD:
assert(0);
+ return 0;
+ case NFT_COMPAT_RULE_CHANGE_COUNTERS:
+ ret = nft_rule_change_counters(h, cmd->table,
+ cmd->chain,
+ cmd->obj.rule,
+ cmd->rulenum,
+ &cmd->counters,
+ cmd->counter_op,
+ cmd->verbose);
break;
}
@@ -3175,6 +3685,20 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt)
err:
mnl_socket_close(nl);
+ /* ignore EPERM and errors for revision 0 -
+ * this is required for printing extension help texts as user, also
+ * helps error messaging on unavailable kernel extension */
+ if (ret < 0) {
+ if (errno == EPERM)
+ return 1;
+ if (rev == 0) {
+ fprintf(stderr,
+ "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
+ name);
+ return 1;
+ }
+ }
+
return ret < 0 ? 0 : 1;
}
@@ -3188,10 +3712,9 @@ const char *nft_strerror(int err)
const char *message;
} table[] =
{
- { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" },
- { nft_chain_user_del, EINVAL, "Can't delete built-in chain" },
- { nft_chain_user_del, EBUSY, "Directory not empty" },
- { nft_chain_user_del, EMLINK,
+ { nft_chain_del, ENOTEMPTY, "Chain is not empty" },
+ { nft_chain_del, EBUSY, "Directory not empty" },
+ { nft_chain_del, EMLINK,
"Can't delete chain with references left" },
{ nft_chain_user_add, EEXIST, "Chain already exists" },
{ nft_chain_user_rename, EEXIST, "File exists" },
@@ -3225,6 +3748,27 @@ const char *nft_strerror(int err)
return strerror(err);
}
+static int l4proto_expr_get_dreg(struct nftnl_expr *e, uint32_t *dregp)
+{
+ const char *name = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
+ uint32_t poff = offsetof(struct iphdr, protocol);
+ uint32_t pbase = NFT_PAYLOAD_NETWORK_HEADER;
+
+ if (!strcmp(name, "payload") &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE) == pbase &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET) == poff &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN) == sizeof(uint8_t)) {
+ *dregp = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
+ return 0;
+ }
+ if (!strcmp(name, "meta") &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) == NFT_META_L4PROTO) {
+ *dregp = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
+ return 0;
+ }
+ return -1;
+}
+
static int recover_rule_compat(struct nftnl_rule *r)
{
struct nftnl_expr_iter *iter;
@@ -3241,12 +3785,10 @@ next_expr:
if (!e)
goto out;
- if (strcmp("meta", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
- nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) != NFT_META_L4PROTO)
+ /* may be 'ip protocol' or 'meta l4proto' with identical RHS */
+ if (l4proto_expr_get_dreg(e, &reg) < 0)
goto next_expr;
- reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
-
e = nftnl_expr_iter_next(iter);
if (!e)
goto out;
@@ -3268,8 +3810,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;
@@ -3277,7 +3820,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. */
@@ -3342,20 +3885,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;
@@ -3365,7 +3903,10 @@ 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);
+ if (verbose)
+ nft_cache_sort_chains(h, table);
+
+ 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;
@@ -3389,6 +3930,7 @@ static const char *supported_exprs[] = {
"counter",
"immediate",
"lookup",
+ "range",
};
@@ -3407,6 +3949,10 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
nftnl_expr_get_u32(expr, NFTNL_EXPR_LIMIT_FLAGS) == 0)
return 0;
+ if (!strcmp(name, "log") &&
+ nftnl_expr_is_set(expr, NFTNL_EXPR_LOG_GROUP))
+ return 0;
+
return -1;
}
@@ -3415,55 +3961,30 @@ 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)
{
- const struct builtin_table *table;
- const struct builtin_chain *chain;
- const char *tname, *cname, *type;
- struct nft_handle *h = data;
- enum nf_inet_hooks hook;
- int prio;
-
- if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL))
- return -1;
-
- if (!nft_chain_builtin(c))
- return 0;
-
- tname = nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE);
- table = nft_table_builtin_find(h, tname);
- if (!table)
- return -1;
-
- cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
- chain = nft_chain_builtin_find(table, cname);
- if (!chain)
- return -1;
-
- type = nftnl_chain_get_str(c, NFTNL_CHAIN_TYPE);
- prio = nftnl_chain_get_u32(c, NFTNL_CHAIN_PRIO);
- hook = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM);
- if (strcmp(type, chain->type) ||
- prio != chain->prio ||
- hook != chain->hook)
- return -1;
+ struct nftnl_chain *c = nc->nftnl;
- return 0;
+ return nftnl_rule_foreach(c, nft_is_rule_compatible, NULL);
}
bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain)
{
- struct nftnl_chain_list *clist;
+ if (chain) {
+ struct nft_chain *c = nft_chain_find(h, table, chain);
- clist = nft_chain_list_get(h, table, chain);
- if (clist == NULL)
- return false;
+ return !c || !nft_is_chain_compatible(c, h);
+ }
- if (nftnl_chain_list_foreach(clist, nft_is_chain_compatible, h))
- return false;
+ return !nft_chain_foreach(h, table, nft_is_chain_compatible, h);
+}
- return true;
+bool nft_is_table_tainted(struct nft_handle *h, const char *table)
+{
+ const struct builtin_table *t = nft_table_builtin_find(h, table);
+
+ return t ? h->cache->table[t->type].tainted : false;
}
void nft_assert_table_compatible(struct nft_handle *h,
@@ -3471,8 +3992,12 @@ void nft_assert_table_compatible(struct nft_handle *h,
{
const char *pfx = "", *sfx = "";
- if (nft_is_table_compatible(h, table, chain))
+ if (nft_is_table_compatible(h, table, chain)) {
+ if (nft_is_table_tainted(h, table))
+ printf("# Table `%s' contains incompatible base-chains, use 'nft' tool to list them.\n",
+ table);
return;
+ }
if (chain) {
pfx = "chain `";
@@ -3481,6 +4006,6 @@ void nft_assert_table_compatible(struct nft_handle *h,
chain = "";
}
xtables_error(OTHER_PROBLEM,
- "%s%s%stable `%s' is incompatible, use 'nft' tool.\n",
+ "%s%s%stable `%s' is incompatible, use 'nft' tool.",
pfx, chain, sfx, table);
}
diff --git a/iptables/nft.h b/iptables/nft.h
index 128e09be..57533b65 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>
@@ -13,8 +14,9 @@ enum nft_table_type {
NFT_TABLE_RAW,
NFT_TABLE_FILTER,
NFT_TABLE_NAT,
+ NFT_TABLE_BROUTE,
};
-#define NFT_TABLE_MAX (NFT_TABLE_NAT + 1)
+#define NFT_TABLE_MAX (NFT_TABLE_BROUTE + 1)
struct builtin_chain {
const char *name;
@@ -39,9 +41,12 @@ 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;
+ bool sorted;
+ bool tainted;
} table[NFT_TABLE_MAX];
};
@@ -50,7 +55,7 @@ enum obj_update_type {
NFT_COMPAT_TABLE_FLUSH,
NFT_COMPAT_CHAIN_ADD,
NFT_COMPAT_CHAIN_USER_ADD,
- NFT_COMPAT_CHAIN_USER_DEL,
+ NFT_COMPAT_CHAIN_DEL,
NFT_COMPAT_CHAIN_USER_FLUSH,
NFT_COMPAT_CHAIN_UPDATE,
NFT_COMPAT_CHAIN_RENAME,
@@ -67,6 +72,7 @@ enum obj_update_type {
NFT_COMPAT_RULE_SAVE,
NFT_COMPAT_RULE_ZERO,
NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE,
+ NFT_COMPAT_RULE_CHANGE_COUNTERS,
};
struct cache_chain {
@@ -105,6 +111,7 @@ struct nft_handle {
int8_t config_done;
struct list_head cmd_list;
bool cache_init;
+ int verbose;
/* meta data, for error reporting */
struct {
@@ -112,14 +119,10 @@ struct nft_handle {
} error;
};
-extern const struct builtin_table xtables_ipv4[NFT_TABLE_MAX];
-extern const struct builtin_table xtables_arp[NFT_TABLE_MAX];
-extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX];
-
int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
int (*cb)(const struct nlmsghdr *nlh, void *data),
void *data);
-int nft_init(struct nft_handle *h, int family, const struct builtin_table *t);
+int nft_init(struct nft_handle *h, int family);
void nft_fini(struct nft_handle *h);
int nft_restart(struct nft_handle *h);
@@ -134,6 +137,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,9 +145,9 @@ 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_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);
int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char *table, const char *newname);
int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char *table, bool verbose);
@@ -151,6 +155,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);
/*
@@ -162,9 +169,11 @@ struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
/*
* Operations with rule-set.
*/
-struct nftnl_rule;
+struct nft_rule_ctx {
+ int command;
+};
-struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
+struct nftnl_rule *nft_rule_new(struct nft_handle *h, struct nft_rule_ctx *rule, const char *chain, const char *table, struct iptables_command_state *cs);
int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose);
int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
@@ -182,10 +191,12 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char *
*/
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes);
int add_verdict(struct nftnl_rule *r, int verdict);
-int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m);
+int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
+ struct nftnl_rule *r, struct xt_entry_match *m);
int add_target(struct nftnl_rule *r, struct xt_entry_target *t);
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict);
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set);
+int add_log(struct nftnl_rule *r, struct iptables_command_state *cs);
char *get_comment(const void *data, uint32_t data_len);
enum nft_rule_print {
@@ -193,7 +204,7 @@ enum nft_rule_print {
NFT_RULE_DEL,
};
-void nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
+bool nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r,
enum nft_rule_print type, unsigned int format);
uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
@@ -223,7 +234,6 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table, bo
/* For xtables-eb.c */
int nft_init_eb(struct nft_handle *h, const char *pname);
void nft_fini_eb(struct nft_handle *h);
-int ebt_get_current_chain(const char *chain);
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table, bool restore);
/*
@@ -255,6 +265,7 @@ void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw);
bool nft_is_table_compatible(struct nft_handle *h,
const char *table, const char *chain);
+bool nft_is_table_tainted(struct nft_handle *h, const char *table);
void nft_assert_table_compatible(struct nft_handle *h,
const char *table, const char *chain);
diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh
index 65c37adb..11256905 100755
--- a/iptables/tests/shell/run-tests.sh
+++ b/iptables/tests/shell/run-tests.sh
@@ -21,7 +21,6 @@ EOF
msg_error() {
echo "E: $1 ..." >&2
- exit 1
}
msg_warn() {
@@ -34,10 +33,12 @@ msg_info() {
if [ "$(id -u)" != "0" ] ; then
msg_error "this requires root!"
+ exit 77
fi
if [ ! -d "$TESTDIR" ] ; then
msg_error "missing testdir $TESTDIR"
+ exit 99
fi
# support matching repeated pattern in SINGLE check below
@@ -76,6 +77,7 @@ while [ -n "$1" ]; do
;;
*)
msg_error "unknown parameter '$1'"
+ exit 99
;;
esac
done
@@ -122,7 +124,8 @@ EOF
if [ "$VALGRIND" == "y" ]; then
tmpd=$(mktemp -d)
msg_info "writing valgrind logs to $tmpd"
- chmod a+rx $tmpd
+ # let nobody write logs, too (././testcases/iptables/0008-unprivileged_0)
+ chmod 777 $tmpd
printscript "$XTABLES_NFT_MULTI" "$tmpd" >${tmpd}/xtables-nft-multi
printscript "$XTABLES_LEGACY_MULTI" "$tmpd" >${tmpd}/xtables-legacy-multi
trap "rm ${tmpd}/xtables-*-multi" EXIT
@@ -195,4 +198,4 @@ failed=$((legacy_fail+failed))
msg_info "combined results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
-exit 0
+exit -$failed
diff --git a/iptables/tests/shell/testcases/chain/0003rename_0 b/iptables/tests/shell/testcases/chain/0003rename_0
new file mode 100755
index 00000000..4cb2745b
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0003rename_0
@@ -0,0 +1,40 @@
+#!/bin/bash -x
+
+die() {
+ echo "E: $@"
+ exit 1
+}
+
+cmds="iptables ip6tables"
+[[ $XT_MULTI == *xtables-nft-multi ]] && cmds+=" arptables ebtables"
+
+declare -A invnames
+invnames["existing"]="c2"
+invnames["spaced"]="foo bar"
+invnames["dashed"]="-foo"
+invnames["negated"]="!foo"
+# XXX: ebtables-nft accepts 255 chars
+#invnames["overlong"]="thisisquitealongnameforachain"
+invnames["standard target"]="ACCEPT"
+invnames["extension target"]="DNAT"
+
+for cmd in $cmds; do
+ $XT_MULTI $cmd -N c1 || die "$cmd: can't add chain c1"
+ $XT_MULTI $cmd -N c2 || die "$cmd: can't add chain c2"
+ for key in "${!invnames[@]}"; do
+ val="${invnames[$key]}"
+ if [[ $key == "extension target" ]]; then
+ if [[ $cmd == "arptables" ]]; then
+ val="mangle"
+ elif [[ $cmd == "ebtables" ]]; then
+ val="dnat"
+ fi
+ fi
+ $XT_MULTI $cmd -N "$val" && \
+ die "$cmd: added chain with $key name"
+ $XT_MULTI $cmd -E c1 "$val" && \
+ die "$cmd: renamed to $key name"
+ done
+done
+
+exit 0
diff --git a/iptables/tests/shell/testcases/chain/0003rename_1 b/iptables/tests/shell/testcases/chain/0003rename_1
deleted file mode 100755
index 975c8e19..00000000
--- a/iptables/tests/shell/testcases/chain/0003rename_1
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-$XT_MULTI iptables -N c1 || exit 0
-$XT_MULTI iptables -N c2 || exit 0
-$XT_MULTI iptables -E c1 c2 || exit 1
-
-$XT_MULTI ip6tables -N c1 || exit 0
-$XT_MULTI ip6tables -N c2 || exit 0
-$XT_MULTI ip6tables -E c1 c2 || exit 1
-
-echo "E: Renamed with existing chain" >&2
-exit 0
diff --git a/iptables/tests/shell/testcases/chain/0004extra-base_0 b/iptables/tests/shell/testcases/chain/0004extra-base_0
new file mode 100755
index 00000000..cc07e4be
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0004extra-base_0
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+case $XT_MULTI in
+*xtables-nft-multi)
+ ;;
+*)
+ echo skip $XT_MULTI
+ exit 0
+ ;;
+esac
+
+set -e
+
+nft -f - <<EOF
+table ip filter {
+ chain a {
+ type filter hook input priority filter
+ }
+
+ chain INPUT {
+ type filter hook input priority filter
+ counter packets 218 bytes 91375 accept
+ }
+
+ chain x {
+ type filter hook input priority filter
+ }
+}
+EOF
+
+EXPECT="# Table \`filter' contains incompatible base-chains, use 'nft' tool to list them.
+-P INPUT ACCEPT
+-P FORWARD ACCEPT
+-P OUTPUT ACCEPT
+-A INPUT -j ACCEPT"
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -S)
diff --git a/iptables/tests/shell/testcases/chain/0005base-delete_0 b/iptables/tests/shell/testcases/chain/0005base-delete_0
new file mode 100755
index 00000000..033a2819
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0005base-delete_0
@@ -0,0 +1,34 @@
+#!/bin/bash -x
+
+$XT_MULTI iptables -N foo || exit 1
+$XT_MULTI iptables -P FORWARD DROP || exit 1
+$XT_MULTI iptables -X || exit 1
+$XT_MULTI iptables -X foo && exit 1
+
+# indefinite -X fails if a non-empty user-defined chain exists
+$XT_MULTI iptables -N foo
+$XT_MULTI iptables -N bar
+$XT_MULTI iptables -A bar -j ACCEPT
+$XT_MULTI iptables -X && exit 1
+$XT_MULTI iptables -D bar -j ACCEPT
+$XT_MULTI iptables -X || exit 1
+
+# make sure OUTPUT chain is created by iptables-nft
+$XT_MULTI iptables -A OUTPUT -j ACCEPT || exit 1
+$XT_MULTI iptables -D OUTPUT -j ACCEPT || exit 1
+
+case $XT_MULTI in
+*xtables-nft-multi)
+ # must not delete chain FORWARD, its policy is not ACCEPT
+ $XT_MULTI iptables -X FORWARD && exit 1
+ nft list chain ip filter FORWARD || exit 1
+ # this should evict chain OUTPUT
+ $XT_MULTI iptables -X OUTPUT || exit 1
+ nft list chain ip filter OUTPUT && exit 1
+ ;;
+*)
+ $XT_MULTI iptables -X FORWARD && exit 1
+ $XT_MULTI iptables -X OUTPUT && exit 1
+ ;;
+esac
+exit 0
diff --git a/iptables/tests/shell/testcases/chain/0006rename-segfault_0 b/iptables/tests/shell/testcases/chain/0006rename-segfault_0
new file mode 100755
index 00000000..c10a8006
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0006rename-segfault_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Cover for a bug in libiptc:
+# - the chain 'node-98-tmp' is the last in the list sorted by name
+# - there are 81 chains in total, so three chain index buckets
+# - the last index bucket contains only the 'node-98-tmp' chain
+# => rename temporarily removes it from the bucket, leaving a NULL bucket
+# behind which is dereferenced later when inserting the chain again with new
+# name again
+
+(
+ echo "*filter"
+ for chain in node-1 node-10 node-101 node-102 node-104 node-107 node-11 node-12 node-13 node-14 node-15 node-16 node-17 node-18 node-19 node-2 node-20 node-21 node-22 node-23 node-25 node-26 node-27 node-28 node-29 node-3 node-30 node-31 node-32 node-33 node-34 node-36 node-37 node-39 node-4 node-40 node-41 node-42 node-43 node-44 node-45 node-46 node-47 node-48 node-49 node-5 node-50 node-51 node-53 node-54 node-55 node-56 node-57 node-58 node-59 node-6 node-60 node-61 node-62 node-63 node-64 node-65 node-66 node-68 node-69 node-7 node-70 node-71 node-74 node-75 node-76 node-8 node-80 node-81 node-86 node-89 node-9 node-92 node-93 node-95 node-98-tmp; do
+ echo ":$chain - [0:0]"
+ done
+ echo "COMMIT"
+) | $XT_MULTI iptables-restore
+$XT_MULTI iptables -E node-98-tmp node-98
+exit $?
diff --git a/iptables/tests/shell/testcases/chain/0007counters_0 b/iptables/tests/shell/testcases/chain/0007counters_0
new file mode 100755
index 00000000..0b21a926
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0007counters_0
@@ -0,0 +1,78 @@
+#!/bin/bash -e
+
+SETUP="*filter
+:FORWARD ACCEPT [13:37]
+-A FORWARD -c 1 2 -j ACCEPT
+-A FORWARD -c 3 4 -j ACCEPT
+COMMIT"
+
+
+### -Z with index shall zero a single chain only
+
+EXPECT="-P FORWARD ACCEPT -c 13 37
+-A FORWARD -c 0 0 -j ACCEPT
+-A FORWARD -c 3 4 -j ACCEPT"
+
+$XT_MULTI iptables-restore --counters <<< "$SETUP"
+$XT_MULTI iptables -Z FORWARD 1
+diff -u <(echo "$EXPECT") <($XT_MULTI iptables -vS FORWARD)
+
+
+### -Z without index shall zero the chain and all rules
+
+EXPECT="-P FORWARD ACCEPT -c 0 0
+-A FORWARD -c 0 0 -j ACCEPT
+-A FORWARD -c 0 0 -j ACCEPT"
+
+$XT_MULTI iptables -Z FORWARD
+diff -u <(echo "$EXPECT") <($XT_MULTI iptables -vS FORWARD)
+
+
+### prepare for live test
+
+# iptables-nft will create output chain on demand, so make sure it exists
+$XT_MULTI iptables -A OUTPUT -d 127.2.3.4 -j ACCEPT
+
+# test runs in its own netns, lo is there but down by default
+ip link set lo up
+
+
+### pings (and pongs) hit OUTPUT policy, its counters must increase
+
+get_pkt_counter() { # (CHAIN)
+ $XT_MULTI iptables -vS $1 | awk '/^-P '$1'/{print $5; exit}'
+}
+
+counter_inc_test() {
+ pkt_pre=$(get_pkt_counter OUTPUT)
+ ping -q -i 0.2 -c 3 127.0.0.1
+ pkt_post=$(get_pkt_counter OUTPUT)
+ [[ $pkt_post -gt $pkt_pre ]]
+}
+
+counter_inc_test
+
+# iptables-nft-restore needed --counters to create chains with them
+if [[ $XT_MULTI == *xtables-nft-multi ]]; then
+ $XT_MULTI iptables -F OUTPUT
+ $XT_MULTI iptables -X OUTPUT
+ $XT_MULTI iptables-restore <<EOF
+*filter
+:OUTPUT ACCEPT [0:0]
+COMMIT
+EOF
+ counter_inc_test
+fi
+
+### unrelated restore must not touch changing counters in kernel
+
+# With legacy iptables, this works without --noflush even. With iptables-nft,
+# ruleset is flushed though. Not sure which behaviour is actually correct. :)
+pkt_pre=$pkt_post
+$XT_MULTI iptables-restore --noflush <<EOF
+*filter$(ping -i 0.2 -c 3 127.0.0.1 >/dev/null 2>&1)
+COMMIT
+EOF
+nft list ruleset
+pkt_post=$(get_pkt_counter OUTPUT)
+[[ $pkt_post -eq $((pkt_pre + 6 )) ]]
diff --git a/iptables/tests/shell/testcases/chain/0008rename-segfault2_0 b/iptables/tests/shell/testcases/chain/0008rename-segfault2_0
new file mode 100755
index 00000000..bc473d25
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0008rename-segfault2_0
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# Another funny rename bug in libiptc:
+# If there is a chain index bucket with only a single chain in it and it is not
+# the last one and that chain is renamed, a chain index rebuild is triggered.
+# Since TC_RENAME_CHAIN missed to temporarily decrement num_chains value, an
+# extra index is allocated and remains NULL. The following insert of renamed
+# chain then segfaults.
+
+(
+ echo "*filter"
+ # first bucket
+ for ((i = 0; i < 40; i++)); do
+ echo ":chain-a-$i - [0:0]"
+ done
+ # second bucket
+ for ((i = 0; i < 40; i++)); do
+ echo ":chain-b-$i - [0:0]"
+ done
+ # third bucket, just make sure it exists
+ echo ":chain-c-0 - [0:0]"
+ echo "COMMIT"
+) | $XT_MULTI iptables-restore
+
+# rename all chains of the middle bucket
+(
+ echo "*filter"
+ for ((i = 0; i < 40; i++)); do
+ echo "-E chain-b-$i chain-d-$i"
+ done
+ echo "COMMIT"
+) | $XT_MULTI iptables-restore --noflush
diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
index 6f11bd12..bae0de7d 100755
--- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
+++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
@@ -15,13 +15,13 @@ get_entries_count() { # (chain)
set -x
-for t in filter nat;do
+for t in filter nat broute; do
$XT_MULTI ebtables -t $t -L || exit 1
$XT_MULTI ebtables -t $t -X || exit 1
$XT_MULTI ebtables -t $t -F || exit 1
done
-for t in broute foobar ;do
+for t in foobar; do
$XT_MULTI ebtables -t $t -L &&
$XT_MULTI ebtables -t $t -X &&
$XT_MULTI ebtables -t $t -F
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..b4f9728b 100755
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
@@ -13,8 +13,8 @@ $XT_MULTI ebtables -A INPUT -p IPv4 -i lo -j ACCEPT
$XT_MULTI ebtables -P FORWARD DROP
$XT_MULTI ebtables -A OUTPUT -s ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff -j DROP
$XT_MULTI ebtables -N foo
-$XT_MULTI ebtables -A foo --802_3-sap 0x23 -j ACCEPT
-$XT_MULTI ebtables -A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
+$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 -j ACCEPT
+$XT_MULTI ebtables -A foo -p length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
#$XT_MULTI ebtables -A foo --among-dst fe:ed:ba:be:00:01,fe:ed:ba:be:00:02,fe:ed:ba:be:00:03 -j ACCEPT
$XT_MULTI ebtables -A foo -p ARP --arp-gratuitous -j ACCEPT
$XT_MULTI ebtables -A foo -p ARP --arp-opcode Request -j ACCEPT
@@ -38,13 +38,13 @@ $XT_MULTI ebtables -A foo -p IPv6 --ip6-proto tcp -j ACCEPT
$XT_MULTI ebtables -A foo --limit 100 --limit-burst 42 -j ACCEPT
$XT_MULTI ebtables -A foo --log
-$XT_MULTI ebtables -A foo --mark-set 0x23 --mark-target ACCEPT
+$XT_MULTI ebtables -A foo -j mark --mark-set 0x23 --mark-target ACCEPT
$XT_MULTI ebtables -A foo --nflog
$XT_MULTI ebtables -A foo --pkttype-type multicast -j ACCEPT
$XT_MULTI ebtables -A foo --stp-type config -j ACCEPT
#$XT_MULTI ebtables -A foo --vlan-id 42 -j ACCEPT
-$XT_MULTI ebtables -A foo --802_3-sap 0x23 --limit 100 -j ACCEPT
+$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 --limit 100 -j ACCEPT
$XT_MULTI ebtables -A foo --pkttype-type multicast --log
$XT_MULTI ebtables -A foo --pkttype-type multicast --limit 100 -j ACCEPT
@@ -53,7 +53,7 @@ $XT_MULTI ebtables -A FORWARD -j foo
$XT_MULTI ebtables -N bar
$XT_MULTI ebtables -P bar RETURN
-$XT_MULTI ebtables -t nat -A PREROUTING --redirect-target ACCEPT
+$XT_MULTI ebtables -t nat -A PREROUTING -j redirect --redirect-target ACCEPT
#$XT_MULTI ebtables -t nat -A PREROUTING --to-src fe:ed:ba:be:00:01
$XT_MULTI ebtables -t nat -A OUTPUT -j ACCEPT
@@ -70,13 +70,13 @@ 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
--A foo --802_3-sap 0x23 -j ACCEPT
--A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
+-A foo -p Length --802_3-sap 0x23 -j ACCEPT
+-A foo -p Length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
-A foo -p ARP --arp-gratuitous -j ACCEPT
-A foo -p ARP --arp-op Request -j ACCEPT
-A foo -p ARP --arp-ip-src 10.0.0.1 -j ACCEPT
@@ -91,13 +91,13 @@ DUMP='*filter
-A foo -p IPv6 --ip6-dst feed:babe::/64 -j ACCEPT
-A foo -p IPv6 --ip6-proto tcp -j ACCEPT
-A foo --limit 100/sec --limit-burst 42 -j ACCEPT
--A foo --log-level notice --log-prefix "" -j CONTINUE
+-A foo --log-level notice -j CONTINUE
-A foo -j mark --mark-set 0x23 --mark-target ACCEPT
-A foo --nflog-group 1 -j CONTINUE
-A foo --pkttype-type multicast -j ACCEPT
-A foo --stp-type config -j ACCEPT
--A foo --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT
--A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE
+-A foo -p Length --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT
+-A foo --pkttype-type multicast --log-level notice -j CONTINUE
-A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT
*nat
:PREROUTING ACCEPT
diff --git a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0 b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
index 63891c1b..7554ef85 100755
--- a/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
+++ b/iptables/tests/shell/testcases/ebtables/0003-ebtables-restore-defaults_0
@@ -24,7 +24,7 @@ EXPECT='*filter
-A FORWARD --limit 100/sec --limit-burst 42 -j ACCEPT
-A FORWARD --limit 1000/sec --limit-burst 5 -j ACCEPT
-A FORWARD --log-level notice --log-prefix "foobar" -j CONTINUE
--A FORWARD --log-level notice --log-prefix "" -j CONTINUE'
+-A FORWARD --log-level notice -j CONTINUE'
$XT_MULTI ebtables --init-table
$XT_MULTI ebtables-restore <<<$DUMP
diff --git a/iptables/tests/shell/testcases/ebtables/0006-flush_0 b/iptables/tests/shell/testcases/ebtables/0006-flush_0
new file mode 100755
index 00000000..5d714529
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0006-flush_0
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+set -e
+
+# there is no legacy backend to test
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+RULESET='*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT
+-A FORWARD --among-dst fe:ed:ba:be:13:37=10.0.0.1 -j ACCEPT
+-A OUTPUT --among-src c0:ff:ee:90:0:0=192.168.0.1 -j DROP
+*nat
+:PREROUTING ACCEPT
+:OUTPUT ACCEPT
+:POSTROUTING ACCEPT
+-A OUTPUT --among-src c0:ff:ee:90:90:90=192.168.0.1 -j DROP'
+
+$XT_MULTI ebtables-restore <<<$RULESET
+diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#')
+
+RULESET='*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT
+-A FORWARD --among-dst fe:ed:ba:be:13:37=10.0.0.1 -j ACCEPT
+-A OUTPUT --among-src c0:ff:ee:90:0:0=192.168.0.1 -j DROP
+*nat
+:PREROUTING ACCEPT
+:OUTPUT ACCEPT
+:POSTROUTING ACCEPT'
+
+$XT_MULTI ebtables -t nat -F
+diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#')
+
+RULESET='*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT
+*nat
+:PREROUTING ACCEPT
+:OUTPUT ACCEPT
+:POSTROUTING ACCEPT'
+
+$XT_MULTI ebtables -t filter -F
+diff -u <(echo -e "$RULESET") <($XT_MULTI ebtables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0 b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0
new file mode 100755
index 00000000..d79f91b1
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0007-chain-policies_0
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+case "$XT_MULTI" in
+*xtables-nft-multi)
+ ;;
+*)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
+set -e
+
+# ebtables supports policies in user-defined chains %)
+# and the default policy is ACCEPT ...
+$XT_MULTI ebtables -N FOO -P DROP
+$XT_MULTI ebtables -N BAR
+$XT_MULTI ebtables -P BAR RETURN
+$XT_MULTI ebtables -N BAZ
+
+EXPECT_BASE="*filter
+:INPUT ACCEPT
+:FORWARD ACCEPT
+:OUTPUT ACCEPT"
+
+EXPECT="$EXPECT_BASE
+:BAR RETURN
+:BAZ ACCEPT
+:FOO DROP"
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
+
+# rule commands must not break the policies
+$XT_MULTI ebtables -A FOO -j ACCEPT
+$XT_MULTI ebtables -D FOO -j ACCEPT
+$XT_MULTI ebtables -F
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ebtables-save | grep -v '^#')
+
+# dropping the chains must implicitly remove the policy rule as well
+$XT_MULTI ebtables -X
+diff -u -Z <(echo -e "$EXPECT_BASE") <($XT_MULTI ebtables-save | grep -v '^#')
diff --git a/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0 b/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0
new file mode 100755
index 00000000..962b1e03
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0008-ebtables-among_0
@@ -0,0 +1,106 @@
+#!/bin/sh
+
+case "$XT_MULTI" in
+*xtables-nft-multi)
+ ;;
+*)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
+sfx=$(mktemp -u "XXXXXXXX")
+nsa="nsa-$sfx"
+nsb="nsb-$sfx"
+nsc="nsc-$sfx"
+
+cleanup()
+{
+ ip netns del "$nsa"
+ ip netns del "$nsb"
+ ip netns del "$nsc"
+}
+
+trap cleanup EXIT
+
+assert_fail()
+{
+ if [ $1 -eq 0 ]; then
+ echo "FAILED: $2"
+ exit 1
+ fi
+}
+
+assert_pass()
+{
+ if [ $1 -ne 0 ]; then
+ echo "FAILED: $2"
+ exit 2
+ fi
+}
+
+ip netns add "$nsa"
+ip netns add "$nsb"
+ip netns add "$nsc"
+
+ip link add name c_b netns "$nsc" type veth peer name b_c netns "$nsb"
+ip link add name s_b netns "$nsa" type veth peer name b_s netns "$nsb"
+ip netns exec "$nsb" ip link add name br0 type bridge
+
+ip -net "$nsb" link set b_c up
+ip netns exec "$nsb" ip link set b_s up
+ip netns exec "$nsb" ip addr add 10.167.11.254/24 dev br0
+ip netns exec "$nsb" ip link set br0 up
+ip netns exec "$nsb" ip link set b_c master br0
+ip netns exec "$nsb" ip link set b_s master br0
+ip netns exec "$nsc" ip addr add 10.167.11.2/24 dev c_b
+ip netns exec "$nsc" ip link set c_b up
+ip -net "$nsa" addr add 10.167.11.1/24 dev s_b
+ip -net "$nsa" link set s_b up
+
+ip netns exec "$nsc" ping -q 10.167.11.1 -c1 >/dev/null || exit 1
+
+bf_bridge_mac1=`ip netns exec "$nsb" cat /sys/class/net/b_s/address`
+bf_bridge_mac0=`ip netns exec "$nsb" cat /sys/class/net/b_c/address`
+bf_client_mac1=`ip netns exec "$nsc" cat /sys/class/net/c_b/address`
+bf_server_mac1=`ip netns exec "$nsa" cat /sys/class/net/s_b/address`
+
+bf_server_ip1="10.167.11.1"
+bf_bridge_ip0="10.167.11.254"
+bf_client_ip1="10.167.11.2"
+pktsize=64
+
+# --among-src [mac,IP]
+among="$bf_bridge_mac0=$bf_bridge_ip0,$bf_client_mac1=$bf_client_ip1"
+ip netns exec "$nsb" $XT_MULTI ebtables -F
+ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD \
+ -p ip --ip-dst $bf_server_ip1 --among-src "$among" -j DROP > /dev/null
+ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 >/dev/null
+assert_fail $? "--among-src [match]"
+
+# ip netns exec "$nsb" $XT_MULTI ebtables -L --Ln --Lc
+
+among="$bf_bridge_mac0=$bf_bridge_ip0,$bf_client_mac1=$bf_client_ip1"
+ip netns exec "$nsb" $XT_MULTI ebtables -F
+ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD \
+ -p ip --ip-dst $bf_server_ip1 ! --among-src "$among" -j DROP > /dev/null
+ip netns exec "$nsc" ping $bf_server_ip1 -c 1 -s $pktsize -W 1 >/dev/null
+assert_pass $? "--among-src [not match]"
+
+# --among-dst [mac,IP]
+among="$bf_client_mac1=$bf_client_ip1,$bf_server_mac1=$bf_server_ip1"
+ip netns exec "$nsb" $XT_MULTI ebtables -F
+ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD \
+ -p ip --ip-src $bf_client_ip1 --among-dst "$among" -j DROP > /dev/null
+ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 > /dev/null
+assert_fail $? "--among-dst [match]"
+
+# ! --among-dst [mac,IP]
+among="$bf_client_mac1=$bf_client_ip1,$bf_server_mac1=$bf_server_ip1"
+ip netns exec "$nsb" $XT_MULTI ebtables -F
+ip netns exec "$nsb" $XT_MULTI ebtables -A FORWARD \
+ -p ip --ip-src $bf_client_ip1 ! --among-dst "$among" -j DROP > /dev/null
+ip netns exec "$nsc" ping -q $bf_server_ip1 -c 1 -s $pktsize -W 1 > /dev/null
+assert_pass $? "--among-dst [not match]"
+
+exit 0
diff --git a/iptables/tests/shell/testcases/ebtables/0009-broute-bug_0 b/iptables/tests/shell/testcases/ebtables/0009-broute-bug_0
new file mode 100755
index 00000000..0def0ac5
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0009-broute-bug_0
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Missing BROUTING-awareness in ebt_get_current_chain() caused an odd caching bug when restoring:
+# - with --noflush
+# - a second table after the broute one
+# - A policy command but no chain line for BROUTING chain
+
+set -e
+
+case "$XT_MULTI" in
+*xtables-nft-multi)
+ ;;
+*)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
+$XT_MULTI ebtables-restore --noflush <<EOF
+*broute
+-P BROUTING ACCEPT
+*nat
+-P PREROUTING ACCEPT
+COMMIT
+EOF
diff --git a/iptables/tests/shell/testcases/ebtables/0010-change-counters_0 b/iptables/tests/shell/testcases/ebtables/0010-change-counters_0
new file mode 100755
index 00000000..4f783819
--- /dev/null
+++ b/iptables/tests/shell/testcases/ebtables/0010-change-counters_0
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+case "$XT_MULTI" in
+*xtables-nft-multi)
+ ;;
+*)
+ echo "skip $XT_MULTI"
+ exit 0
+ ;;
+esac
+
+set -e
+set -x
+
+check_rule() { # (pcnt, bcnt)
+ $XT_MULTI ebtables -L FORWARD --Lc --Ln | \
+ grep -q "^1. -o eth0 -j CONTINUE , pcnt = $1 -- bcnt = $2$"
+}
+
+$XT_MULTI ebtables -A FORWARD -o eth0 -c 10 20
+check_rule 10 20
+
+$XT_MULTI ebtables -C FORWARD 1 100 200
+check_rule 100 200
+
+$XT_MULTI ebtables -C FORWARD 101 201 -o eth0
+check_rule 101 201
+
+$XT_MULTI ebtables -C FORWARD 1 +10 -20
+check_rule 111 181
+
+$XT_MULTI ebtables -C FORWARD -10 +20 -o eth0
+check_rule 101 201
+
+$XT_MULTI ebtables -A FORWARD -o eth1 -c 111 211
+$XT_MULTI ebtables -A FORWARD -o eth2 -c 121 221
+
+$XT_MULTI ebtables -C FORWARD 2:3 +100 -200
+
+EXPECT='1. -o eth0 -j CONTINUE , pcnt = 101 -- bcnt = 201
+2. -o eth1 -j CONTINUE , pcnt = 211 -- bcnt = 11
+3. -o eth2 -j CONTINUE , pcnt = 221 -- bcnt = 21'
+diff -u <(echo "$EXPECT") \
+ <($XT_MULTI ebtables -L FORWARD --Lc --Ln | grep -- '-o eth')
+
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/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
index 7b0e6468..45fab830 100755
--- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
+++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
@@ -6,23 +6,38 @@ set -e
# ensure verbose output is identical between legacy and nft tools
RULE1='-i eth2 -o eth3 -s feed:babe::1 -d feed:babe::2 -j ACCEPT'
-VOUT1='ACCEPT all opt in eth2 out eth3 feed:babe::1 -> feed:babe::2'
+VOUT1='ACCEPT all opt -- in eth2 out eth3 feed:babe::1 -> feed:babe::2'
RULE2='-i eth2 -o eth3 -s feed:babe::4 -d feed:babe::5 -j ACCEPT'
-VOUT2='ACCEPT all opt in eth2 out eth3 feed:babe::4 -> feed:babe::5'
+VOUT2='ACCEPT all opt -- in eth2 out eth3 feed:babe::4 -> feed:babe::5'
+RULE3='-p icmpv6 -m icmp6 --icmpv6-type no-route'
+VOUT3=' ipv6-icmp opt -- in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0'
+RULE4='-m dst --dst-len 42 -m rt --rt-type 23'
+VOUT4=' all opt -- in * out * ::/0 -> ::/0 dst length:42 rt type:23'
+RULE5='-m frag --fragid 1337 -j LOG'
+VOUT5='LOG all opt -- in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4'
diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -A FORWARD $RULE1)
diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -I FORWARD 2 $RULE2)
+diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI ip6tables -v -A FORWARD $RULE3)
+diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI ip6tables -v -A FORWARD $RULE4)
+diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI ip6tables -v -A FORWARD $RULE5)
diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -C FORWARD $RULE1)
diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -C FORWARD $RULE2)
+diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI ip6tables -v -C FORWARD $RULE3)
+diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI ip6tables -v -C FORWARD $RULE4)
+diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI ip6tables -v -C FORWARD $RULE5)
EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
- 0 0 ACCEPT all eth2 eth3 feed:babe::1 feed:babe::2
- 0 0 ACCEPT all eth2 eth3 feed:babe::4 feed:babe::5
+ 0 0 ACCEPT all -- eth2 eth3 feed:babe::1 feed:babe::2
+ 0 0 ACCEPT all -- eth2 eth3 feed:babe::4 feed:babe::5
+ 0 0 ipv6-icmp -- * * ::/0 ::/0 ipv6-icmptype 1 code 0
+ 0 0 all -- * * ::/0 ::/0 dst length:42 rt type:23
+ 0 0 LOG all -- * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination'
diff --git a/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0 b/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0
index c98bdd6e..09e39927 100755
--- a/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0
+++ b/iptables/tests/shell/testcases/ip6tables/0003-list-rules_0
@@ -3,7 +3,7 @@
set -e
$XT_MULTI ip6tables -N foo
-$XT_MULTI ip6tables -A FORWARD -i eth23 -o eth42 -j ACCEPT
+$XT_MULTI ip6tables -A FORWARD -i eth23 -o eth42 -j ACCEPT -c 23 42
$XT_MULTI ip6tables -A FORWARD -i eth42 -o eth23 -g foo
$XT_MULTI ip6tables -t nat -A OUTPUT -o eth123 -m mark --mark 0x42 -j ACCEPT
@@ -20,7 +20,7 @@ EXPECT='-P INPUT ACCEPT -c 0 0
-P FORWARD ACCEPT -c 0 0
-P OUTPUT ACCEPT -c 0 0
-N foo
--A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT
+-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT
-A FORWARD -i eth42 -o eth23 -c 0 0 -g foo'
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -v -S)
@@ -32,7 +32,7 @@ EXPECT='-P FORWARD ACCEPT
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -S FORWARD)
EXPECT='-P FORWARD ACCEPT -c 0 0
--A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT
+-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT
-A FORWARD -i eth42 -o eth23 -c 0 0 -g foo'
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -v -S FORWARD)
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0 b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0
new file mode 100755
index 00000000..7eb42f08
--- /dev/null
+++ b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+
+$XT_MULTI ip6tables-restore <<EOF
+*filter
+-A FORWARD -s feed:babe::/ffff::0
+-A FORWARD -s feed:babe::/ffff:ff00::0
+-A FORWARD -s feed:babe::/ffff:fff0::0
+-A FORWARD -s feed:babe::/ffff:ffff::0
+-A FORWARD -s feed:babe::/0:ffff::0
+-A FORWARD -s feed:c0ff::babe:f00/ffff::ffff:0
+COMMIT
+EOF
+
+EXPECT='-P FORWARD ACCEPT
+-A FORWARD -s feed::/16
+-A FORWARD -s feed:ba00::/24
+-A FORWARD -s feed:bab0::/28
+-A FORWARD -s feed:babe::/32
+-A FORWARD -s 0:babe::/0:ffff::
+-A FORWARD -s feed::babe:0/ffff::ffff:0'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -S FORWARD)
diff --git a/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0 b/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0
new file mode 100755
index 00000000..cc8215bf
--- /dev/null
+++ b/iptables/tests/shell/testcases/ip6tables/0005-rule-check_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Test the fix in commit 78850e7dba64a ("ip6tables: Fix checking existence of
+# rule"). Happens with legacy ip6tables only, but testing ip6tables-nft doesn't
+# hurt.
+#
+# Code taken from https://bugzilla.netfilter.org/show_bug.cgi?id=1667
+# Thanks to Jonathan Caicedo <jonathan@jcaicedo.com> for providing it.
+
+RULE='-p tcp --dport 81 -j DNAT --to-destination [::1]:81'
+
+$XT_MULTI ip6tables -t nat -N testchain || exit 1
+$XT_MULTI ip6tables -t nat -A testchain $RULE || exit 1
+$XT_MULTI ip6tables -t nat -C testchain $RULE || exit 1
+
+$XT_MULTI ip6tables -t nat -C testchain ${RULE//81/82} 2>/dev/null && exit 1
+exit 0
diff --git a/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0 b/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0
index 5c8748ec..d632cbc0 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0002-parameters_0
@@ -2,7 +2,7 @@
set -e
-# make sure wait and wait-interval options are accepted
+# make sure wait options are accepted
clean_tempfile()
{
@@ -18,4 +18,3 @@ tmpfile=$(mktemp) || exit 1
$XT_MULTI iptables-save -f $tmpfile
$XT_MULTI iptables-restore $tmpfile
$XT_MULTI iptables-restore -w 5 $tmpfile
-$XT_MULTI iptables-restore -w 5 -W 1 $tmpfile
diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
index 3f1d229e..5482b7ea 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
@@ -123,3 +123,19 @@ EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
-A FORWARD -m comment --comment "rule 3" -j ACCEPT'
diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
+
+# test adding, referencing and deleting the same rule in a batch
+
+$XT_MULTI iptables-restore <<EOF
+*filter
+-A FORWARD -m comment --comment "first rule" -j ACCEPT
+-A FORWARD -m comment --comment "referenced rule" -j ACCEPT
+-I FORWARD 2 -m comment --comment "referencing rule" -j ACCEPT
+-D FORWARD -m comment --comment "referenced rule" -j ACCEPT
+COMMIT
+EOF
+
+EXPECT='-A FORWARD -m comment --comment "first rule" -j ACCEPT
+-A FORWARD -m comment --comment "referencing rule" -j ACCEPT'
+
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
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/0008-restore-counters_0 b/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0
index 5ac70682..854768c9 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0008-restore-counters_0
@@ -20,3 +20,10 @@ EXPECT=":foo - [0:0]
$XT_MULTI iptables-restore --counters <<< "$DUMP"
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save --counters | grep foo)
+
+# if present, counters must be in proper format
+! $XT_MULTI iptables-restore <<EOF
+*filter
+:FORWARD ACCEPT bar
+COMMIT
+EOF
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..087156b1 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0
@@ -33,6 +33,7 @@ Flushing chain \`bar'
Flushing chain \`foo'
Deleting chain \`bar'
Deleting chain \`foo'
+ACCEPT all opt -- in * out * 0.0.0.0/0 -> 0.0.0.0/0
Flushing chain \`PREROUTING'
Flushing chain \`INPUT'
Flushing chain \`OUTPUT'
@@ -41,6 +42,7 @@ Flushing chain \`natbar'
Flushing chain \`natfoo'
Deleting chain \`natbar'
Deleting chain \`natfoo'
+ACCEPT all opt -- in * out * 0.0.0.0/0 -> 0.0.0.0/0
Flushing chain \`PREROUTING'
Flushing chain \`OUTPUT'
Flushing chain \`rawfoo'
@@ -58,9 +60,10 @@ Flushing chain \`OUTPUT'
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)
-done
+EXPECT6=$(sed -e 's/0\.0\.0\.0/::/g' <<< "$EXPECT")
+
+diff -u -Z <(echo "$EXPECT") <($XT_MULTI iptables-restore -v <<< "$DUMP")
+diff -u -Z <(echo "$EXPECT6") <($XT_MULTI ip6tables-restore -v <<< "$DUMP")
DUMP="*filter
:baz - [0:0]
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/0001load-dumps_0 b/iptables/tests/shell/testcases/ipt-save/0001load-dumps_0
index 4e0be51c..48f5f7b4 100755
--- a/iptables/tests/shell/testcases/ipt-save/0001load-dumps_0
+++ b/iptables/tests/shell/testcases/ipt-save/0001load-dumps_0
@@ -39,6 +39,7 @@ do_simple()
$XT_MULTI ${iptables}-restore < "$dumpfile"
$XT_MULTI ${iptables}-save | grep -v "^#" > "$tmpfile"
+ sed -i -e 's/-p 47 /-p gre /' "$tmpfile"
do_diff $dumpfile "$tmpfile"
if [ $? -ne 0 ]; then
# cp "$tmpfile" "$dumpfile.got"
diff --git a/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0 b/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0
index 50c0cae8..bcfaad36 100755
--- a/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0
+++ b/iptables/tests/shell/testcases/ipt-save/0006iptables-xml_0
@@ -1,13 +1,5 @@
#!/bin/bash
-case "$(basename $XT_MULTI)" in
- xtables-legacy-multi)
- ;;
- *)
- echo "skip $XT_MULTI"
- exit 0
- ;;
-esac
-
dump=$(dirname $0)/dumps/fedora27-iptables
diff -u -Z <(cat ${dump}.xml) <($XT_MULTI iptables-xml <$dump)
+diff -u -Z <(cat ${dump}.xml) <($XT_MULTI iptables-xml -c <$dump)
diff --git a/iptables/tests/shell/testcases/ipt-save/0007-overhead_0 b/iptables/tests/shell/testcases/ipt-save/0007-overhead_0
new file mode 100755
index 00000000..b86d71f2
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-save/0007-overhead_0
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# Test recent performance improvements in iptables-save due to reduced
+# overhead.
+
+strace --version >/dev/null || { echo "skip for missing strace"; exit 0; }
+
+RULESET=$(
+ echo "*filter"
+ for ((i = 0; i < 100; i++)); do
+ echo ":mychain$i -"
+ echo "-A FORWARD -p tcp --dport 22 -j mychain$i"
+ done
+ echo "COMMIT"
+)
+
+RESTORE_STRACE=$(strace $XT_MULTI iptables-restore <<< "$RULESET" 2>&1 >/dev/null)
+SAVE_STRACE=$(strace $XT_MULTI iptables-save 2>&1 >/dev/null)
+
+do_grep() { # (name, threshold, pattern)
+ local cnt=$(grep -c "$3")
+ [[ $cnt -le $2 ]] && return 0
+ echo "ERROR: Too many $3 lookups for $1: $cnt > $2"
+ exit 1
+}
+
+# iptables prefers hard-coded protocol names instead of looking them up first
+
+do_grep "$XT_MULTI iptables-restore" 0 /etc/protocols <<< "$RESTORE_STRACE"
+do_grep "$XT_MULTI iptables-save" 0 /etc/protocols <<< "$SAVE_STRACE"
+
+# iptables-nft-save pointlessly checked whether chain jumps are targets
+
+do_grep "$XT_MULTI iptables-restore" 10 libxt_ <<< "$RESTORE_STRACE"
+do_grep "$XT_MULTI iptables-save" 10 libxt_ <<< "$SAVE_STRACE"
+
+exit 0
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/iptables/0002-verbose-output_0 b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
index b1ef91f6..5d2af4c8 100755
--- a/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
+++ b/iptables/tests/shell/testcases/iptables/0002-verbose-output_0
@@ -54,3 +54,14 @@ diff -u <(echo "Flushing chain \`foobar'") <($XT_MULTI iptables -v -F foobar)
diff -u <(echo "Zeroing chain \`foobar'") <($XT_MULTI iptables -v -Z foobar)
diff -u <(echo "Deleting chain \`foobar'") <($XT_MULTI iptables -v -X foobar)
+
+# make sure non-verbose mode is silent
+diff -u <(echo -n "") <(
+ $XT_MULTI iptables -N foobar
+ $XT_MULTI iptables -A foobar $RULE1
+ $XT_MULTI iptables -A foobar $RULE2
+ $XT_MULTI iptables -C foobar $RULE1
+ $XT_MULTI iptables -D foobar $RULE2
+ $XT_MULTI iptables -F foobar
+ $XT_MULTI iptables -X foobar
+)
diff --git a/iptables/tests/shell/testcases/iptables/0003-list-rules_0 b/iptables/tests/shell/testcases/iptables/0003-list-rules_0
index d335d442..d07bd151 100755
--- a/iptables/tests/shell/testcases/iptables/0003-list-rules_0
+++ b/iptables/tests/shell/testcases/iptables/0003-list-rules_0
@@ -3,7 +3,7 @@
set -e
$XT_MULTI iptables -N foo
-$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j ACCEPT
+$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j ACCEPT -c 23 42
$XT_MULTI iptables -A FORWARD -i eth42 -o eth23 -g foo
$XT_MULTI iptables -t nat -A OUTPUT -o eth123 -m mark --mark 0x42 -j ACCEPT
@@ -20,7 +20,7 @@ EXPECT='-P INPUT ACCEPT -c 0 0
-P FORWARD ACCEPT -c 0 0
-P OUTPUT ACCEPT -c 0 0
-N foo
--A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT
+-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT
-A FORWARD -i eth42 -o eth23 -c 0 0 -g foo'
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -S)
@@ -32,7 +32,7 @@ EXPECT='-P FORWARD ACCEPT
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -S FORWARD)
EXPECT='-P FORWARD ACCEPT -c 0 0
--A FORWARD -i eth23 -o eth42 -c 0 0 -j ACCEPT
+-A FORWARD -i eth23 -o eth42 -c 23 42 -j ACCEPT
-A FORWARD -i eth42 -o eth23 -c 0 0 -g foo'
diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables -v -S FORWARD)
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
index dcd9dfd3..234f3040 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -39,7 +39,7 @@ E2BIG_D=": Index of deletion too big."
E2BIG_R=": Index of replacement too big."
EBADRULE=": Bad rule (does a matching rule exist in that chain?)."
#ENOTGT=" v[0-9\.]* [^ ]*: Couldn't load target \`foobar':No such file or directory"
-ENOMTH=" v[0-9\.]* [^ ]*: Couldn't load match \`foobar':No such file or directory"
+ENOMTH=" v[0-9\.]* [^ ]*: Couldn't \(load\|find\) match \`foobar'\(:No such file or directory\|\)"
ENOTBL=": can't initialize iptables table \`foobar': Table does not exist"
# test chain creation
@@ -58,6 +58,7 @@ cmd 1 "$ENOENT" -Z bar
cmd 0 -E foo bar
cmd 1 "$EEXIST_F" -E foo bar
cmd 1 "$ENOENT" -E foo bar2
+cmd 1 "$ENOENT" -L foo
cmd 0 -N foo2
cmd 1 "$EEXIST_F" -E foo2 bar
diff --git a/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0
new file mode 100755
index 00000000..21793472
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+RC=0
+COUNTR=$RANDOM$RANDOM
+
+$XT_MULTI iptables-restore -c <<EOF
+*filter
+:INPUT ACCEPT [1:23]
+:FOO - [0:0]
+[12:345] -A INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+[22:123] -A FOO -m comment --comment one
+[44:123] -A FOO -m comment --comment two
+[66:123] -A FOO -m comment --comment three
+COMMIT
+EOF
+EXPECT="*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:FOO - [0:0]
+[0:0] -A INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+[0:0] -A FOO -m comment --comment one
+[0:0] -A FOO -m comment --comment two
+[0:0] -A FOO -m comment --comment three
+COMMIT"
+
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+if [ $COUNTER != "[12:345]" ]; then
+ echo "Counter $COUNTER is wrong, expected 12:345"
+ RC=1
+fi
+
+$XT_MULTI iptables -Z FOO 2
+COUNTER=$($XT_MULTI iptables-save -c | grep "comment two"| cut -f 1 -d " ")
+if [ $COUNTER != "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, should have been zeroed"
+ RC=1
+fi
+COUNTER=$($XT_MULTI iptables-save -c | grep "comment three"| cut -f 1 -d " ")
+if [ $COUNTER != "[66:123]" ]; then
+ echo "Counter $COUNTER is wrong, should not have been zeroed"
+ RC=1
+fi
+
+$XT_MULTI iptables -Z FOO
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+if [ $COUNTER = "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, should not have been zeroed"
+ RC=1
+fi
+
+for c in one two; do
+ COUNTER=$($XT_MULTI iptables-save -c |grep "comment $c"| cut -f 1 -d " ")
+ if [ $COUNTER != "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, should have been zeroed at rule $c"
+ RC=1
+ fi
+done
+
+$XT_MULTI iptables -Z
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+
+if [ $COUNTER != "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, expected 0:0 after -Z"
+ RC=1
+fi
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save -c | grep -v '^#')
+if [ $? -ne 0 ]; then
+ echo "Diff error: counters were not zeroed"
+ RC=1
+fi
+
+$XT_MULTI iptables -D INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+$XT_MULTI iptables -D FOO -m comment --comment one
+$XT_MULTI iptables -D FOO -m comment --comment two
+$XT_MULTI iptables -D FOO -m comment --comment three
+$XT_MULTI iptables -X FOO
+exit $RC
diff --git a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
new file mode 100755
index 00000000..983531fe
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# iptables may print match/target specific help texts
+# help output should work for unprivileged users
+
+run() {
+ echo "running: $*" >&2
+ runuser -u nobody -- "$@"
+}
+
+grep_or_rc() {
+ declare -g rc
+ grep -q "$*" && return 0
+ echo "missing in output: $*" >&2
+ return 1
+}
+
+out=$(run $XT_MULTI iptables --help)
+let "rc+=$?"
+grep_or_rc "iptables -h (print this help information)" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -m limit --help)
+let "rc+=$?"
+grep_or_rc "limit match options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -p tcp --help)
+let "rc+=$?"
+grep_or_rc "tcp match options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "DNAT target options:" <<< "$out"
+let "rc+=$?"
+
+# TEE has no revision 0
+out=$(run $XT_MULTI iptables -j TEE --help)
+let "rc+=$?"
+grep_or_rc "TEE target options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -p tcp -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "tcp match options:" <<< "$out"
+let "rc+=$?"
+out=$(run $XT_MULTI iptables -p tcp -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "DNAT target options:" <<< "$out"
+let "rc+=$?"
+
+
+run $XT_MULTI iptables -L 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+run $XT_MULTI iptables -A FORWARD -p tcp --dport 123 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+run $XT_MULTI iptables -A FORWARD -j DNAT --to-destination 1.2.3.4 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+exit $rc
diff --git a/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0 b/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0
new file mode 100755
index 00000000..ac6e7439
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0009-unknown-arg_0
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+rc=0
+
+check() {
+ local cmd="$1"
+ local msg="$2"
+
+ $XT_MULTI $cmd 2>&1 | grep -q "$msg" || {
+ echo "cmd: $XT_MULTI $1"
+ echo "exp: $msg"
+ echo "res: $($XT_MULTI $cmd 2>&1)"
+ rc=1
+ }
+}
+
+cmds="iptables ip6tables"
+[[ $XT_MULTI == *xtables-nft-multi ]] && {
+ cmds+=" ebtables"
+ cmds+=" iptables-translate"
+ cmds+=" ip6tables-translate"
+ cmds+=" ebtables-translate"
+}
+
+for cmd in $cmds; do
+ check "${cmd} --foo" 'unknown option "--foo"'
+ check "${cmd} -A" 'option "-A" requires an argument'
+ check "${cmd} -aL" 'unknown option "-a"'
+done
+
+exit $rc
diff --git a/iptables/tests/shell/testcases/iptables/0010-wait_0 b/iptables/tests/shell/testcases/iptables/0010-wait_0
new file mode 100755
index 00000000..4481f966
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0010-wait_0
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+case "$XT_MULTI" in
+*xtables-legacy-multi)
+ ;;
+*)
+ echo skip $XT_MULTI
+ exit 0
+ ;;
+esac
+
+coproc RESTORE { $XT_MULTI iptables-restore; }
+echo "*filter" >&${RESTORE[1]}
+
+
+$XT_MULTI iptables -A FORWARD -j ACCEPT &
+ipt_pid=$!
+
+waitpid -t 1 $ipt_pid
+[[ $? -eq 3 ]] && {
+ echo "process waits when it should not"
+ exit 1
+}
+wait $ipt_pid
+[[ $? -eq 0 ]] && {
+ echo "process exited 0 despite busy lock"
+ exit 1
+}
+
+t0=$(date +%s)
+$XT_MULTI iptables -w 3 -A FORWARD -j ACCEPT
+t1=$(date +%s)
+[[ $((t1 - t0)) -ge 3 ]] || {
+ echo "wait time not expired"
+ exit 1
+}
+
+$XT_MULTI iptables -w -A FORWARD -j ACCEPT &
+ipt_pid=$!
+
+waitpid -t 3 $ipt_pid
+[[ $? -eq 3 ]] || {
+ echo "no indefinite wait"
+ exit 1
+}
+kill $ipt_pid
+waitpid -t 3 $ipt_pid
+[[ $? -eq 3 ]] && {
+ echo "killed waiting iptables call did not exit in time"
+ exit 1
+}
+
+kill $RESTORE_PID
+wait
+exit 0
diff --git a/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0 b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0
index 43880ffb..981f007f 100755
--- a/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0
+++ b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0
@@ -13,11 +13,11 @@ COMMIT
:foo [0:0]
EOF
-$XT_MULTI iptables-save | grep -q ':foo'
+sleep 1
+$XT_MULTI iptables-save | grep -q ':foo' || exit 1
nft flush ruleset
echo "COMMIT" >&"${COPROC[1]}"
-sleep 1
-
-[[ -n $COPROC_PID ]] && kill $COPROC_PID
-wait
+# close the pipe to make iptables-restore exit if it didn't error out yet
+eval "exec ${COPROC[1]}>&-"
+wait $COPROC_PID
diff --git a/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
index 41d765e5..34802cc2 100755
--- a/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
+++ b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
@@ -336,4 +336,11 @@ bridge filter OUTPUT 10 9
[ counter pkts 0 bytes 0 ]
"
-diff -u -Z <(echo "$EXPECT") <(nft --debug=netlink list ruleset | awk '/^table/{exit} {print}')
+# print nothing but:
+# - lines with bytecode (starting with ' [')
+# - empty lines (so printed diff is not a complete mess)
+filter() {
+ awk '/^table /{exit} /^( \[|$)/{print}'
+}
+
+diff -u -Z <(filter <<< "$EXPECT") <(nft --debug=netlink list ruleset | filter)
diff --git a/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt
new file mode 100644
index 00000000..5ee4c231
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt
@@ -0,0 +1,26 @@
+*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+-A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 23 -j ACCEPT
+-A INPUT -s 1.2.3.0/24 -d 0.0.0.0/32 -p udp -m udp --dport 67:69 -j DROP
+-A INPUT -s 1.0.0.0/8 -d 0.0.0.0/32 -p tcp -m tcp --sport 1024:65535 --dport 443 --tcp-flags SYN,ACK SYN -j ACCEPT
+-A INPUT -p tcp -m tcp --dport 443 ! --tcp-flags SYN NONE -m comment --comment "checks if SYN bit is set"
+-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m comment --comment "same as iptables --syn"
+-A INPUT -p tcp -m tcp --tcp-flags SYN SYN
+-A INPUT -p tcp -m tcp ! --tcp-flags SYN,ACK SYN,ACK
+-A INPUT -d 0.0.0.0/1 -m ttl --ttl-eq 1 -j DROP
+-A INPUT -d 0.0.0.0/2 -m ttl --ttl-gt 2 -j ACCEPT
+-A INPUT -d 0.0.0.0/3 -m ttl --ttl-lt 254 -j ACCEPT
+-A INPUT -d 0.0.0.0/4 -m ttl ! --ttl-eq 255 -j DROP
+-A INPUT -d 8.0.0.0/5 -p icmp -m icmp --icmp-type 1 -j ACCEPT
+-A INPUT -d 8.0.0.0/6 -p icmp -m icmp --icmp-type 2/3 -j ACCEPT
+-A INPUT -d 10.0.0.0/7 -p icmp -m icmp --icmp-type 8 -j ACCEPT
+-A INPUT -m pkttype --pkt-type broadcast -j ACCEPT
+-A INPUT -m pkttype ! --pkt-type unicast -j DROP
+-A INPUT -p tcp
+-A INPUT -d 0.0.0.0/1 -p udp
+-A FORWARD -m limit --limit 10/day
+-A FORWARD -p udp -m udp --dport 42
+-A FORWARD -i lo -o lo+ -j NFLOG --nflog-prefix "should use NFLOG" --nflog-group 1 --nflog-size 123 --nflog-threshold 42
+COMMIT
diff --git a/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0 b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0
new file mode 100755
index 00000000..7859e76c
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0010-native-delinearize_0
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+nft -v >/dev/null || exit 0
+
+set -e
+
+unshare -n bash -c "nft -f $(dirname $0)/0010-nft-native.txt;
+ diff -u -Z $(dirname $0)/0010-iptables-nft-save.txt <($XT_MULTI iptables-save | grep -v '^#')"
diff --git a/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt b/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt
new file mode 100644
index 00000000..d37ce873
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0010-nft-native.txt
@@ -0,0 +1,41 @@
+table ip filter {
+ chain INPUT {
+ type filter hook input priority filter; policy accept;
+
+ ip saddr 1.2.3.4 tcp dport 23 accept
+ ip saddr 1.2.3.0/24 ip daddr 0.0.0.0 udp dport 67-69 drop
+
+ ip saddr 1.0.0.0/8 ip daddr 0.0.0.0 tcp sport 1024-65535 tcp dport 443 tcp flags syn / syn,ack accept
+ tcp dport 443 tcp flags syn comment "checks if SYN bit is set"
+ tcp flags syn / syn,rst,ack,fin comment "same as iptables --syn"
+ tcp flags & syn == syn
+ tcp flags & (syn | ack) != (syn | ack )
+
+ ip daddr 0.0.0.0/1 ip ttl 1 drop
+ ip daddr 0.0.0.0/2 ip ttl > 2 accept
+ ip daddr 0.0.0.0/3 ip ttl < 254 accept
+ ip daddr 0.0.0.0/4 ip ttl != 255 drop
+
+ ip daddr 8.0.0.0/5 icmp type 1 accept
+ ip daddr 8.0.0.0/6 icmp type 2 icmp code port-unreachable accept
+ ip daddr 10.0.0.0/7 icmp type echo-request accept
+
+ meta pkttype broadcast accept
+ meta pkttype != host drop
+
+ ip saddr 0.0.0.0/0 ip protocol tcp
+ ip daddr 0.0.0.0/1 ip protocol udp
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter;
+ limit rate 10/day counter
+ udp dport 42 counter
+
+ # FIXME: can't dissect plain syslog
+ # meta iif "lo" log prefix "just doing a log" level alert flags tcp sequence,options
+
+ # iif, not iifname, and wildcard
+ meta iif "lo" oifname "lo*" log group 1 prefix "should use NFLOG" queue-threshold 42 snaplen 123
+ }
+}
diff --git a/iptables/tests/shell/testcases/nft-only/0011-zero-needs-compat_0 b/iptables/tests/shell/testcases/nft-only/0011-zero-needs-compat_0
new file mode 100755
index 00000000..e276a953
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0011-zero-needs-compat_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+
+set -e
+
+rule="-p tcp -m tcp --dport 27374 -c 23 42 -j TPROXY --on-port 50080"
+for cmd in iptables ip6tables; do
+ $XT_MULTI $cmd -t mangle -A PREROUTING $rule
+ $XT_MULTI $cmd -t mangle -Z
+ $XT_MULTI $cmd -t mangle -v -S | grep -q -- "${rule/23 42/0 0}"
+done
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 7d97637f..b998dd75 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -9,23 +9,38 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <arpa/inet.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <xtables.h>
#include <math.h>
+#include <signal.h>
#include "xshared.h"
+/* a few arp opcode names */
+char *arp_opcodes[] =
+{
+ "Request",
+ "Reply",
+ "Request_Reverse",
+ "Reply_Reverse",
+ "DRARP_Request",
+ "DRARP_Reply",
+ "DRARP_Error",
+ "InARP_Request",
+ "ARP_NAK",
+};
+
/*
* Print out any special helps. A user might like to be able to add a --help
* to the commandline, and see expected results. So we call help for all
* specified matches and targets.
*/
-void print_extension_helps(const struct xtables_target *t,
- const struct xtables_rule_match *m)
+static void print_extension_helps(const struct xtables_target *t,
+ const struct xtables_rule_match *m)
{
for (; t != NULL; t = t->next) {
if (t->used) {
@@ -48,20 +63,20 @@ void print_extension_helps(const struct xtables_target *t,
}
const char *
-proto_to_name(uint8_t proto, int nolookup)
+proto_to_name(uint16_t proto, int nolookup)
{
unsigned int i;
+ for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
+ if (xtables_chain_protos[i].num == proto)
+ return xtables_chain_protos[i].name;
+
if (proto && !nolookup) {
struct protoent *pent = getprotobynumber(proto);
if (pent)
return pent->p_name;
}
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto)
- return xtables_chain_protos[i].name;
-
return NULL;
}
@@ -96,26 +111,19 @@ find_proto(const char *pname, enum xtables_tryload tryload,
* [think of ip6tables-restore!]
* - the protocol extension can be successively loaded
*/
-static bool should_load_proto(struct iptables_command_state *cs)
+static struct xtables_match *load_proto(struct iptables_command_state *cs)
{
if (cs->protocol == NULL)
- return false;
- if (find_proto(cs->protocol, XTF_DONT_LOAD,
- cs->options & OPT_NUMERIC, NULL) == NULL)
- return true;
- return !cs->proto_used;
-}
-
-struct xtables_match *load_proto(struct iptables_command_state *cs)
-{
- if (!should_load_proto(cs))
return NULL;
+ if (cs->proto_used)
+ return NULL;
+ cs->proto_used = true;
return find_proto(cs->protocol, XTF_TRY_LOAD,
cs->options & OPT_NUMERIC, &cs->matches);
}
int command_default(struct iptables_command_state *cs,
- struct xtables_globals *gl)
+ struct xtables_globals *gl, bool invert)
{
struct xtables_rule_match *matchp;
struct xtables_match *m;
@@ -124,7 +132,7 @@ int command_default(struct iptables_command_state *cs,
(cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
cs->c >= cs->target->option_offset &&
cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
- xtables_option_tpcall(cs->c, cs->argv, cs->invert,
+ xtables_option_tpcall(cs->c, cs->argv, invert,
cs->target, &cs->fw);
return 0;
}
@@ -138,17 +146,14 @@ int command_default(struct iptables_command_state *cs,
if (cs->c < matchp->match->option_offset ||
cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE)
continue;
- xtables_option_mpcall(cs->c, cs->argv, cs->invert, m, &cs->fw);
+ xtables_option_mpcall(cs->c, cs->argv, invert, m, &cs->fw);
return 0;
}
- /* Try loading protocol */
m = load_proto(cs);
if (m != NULL) {
size_t size;
- cs->proto_used = 1;
-
size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size;
m->m = xtables_calloc(1, size);
@@ -177,9 +182,12 @@ int command_default(struct iptables_command_state *cs,
if (cs->c == ':')
xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
"requires an argument", cs->argv[optind-1]);
- if (cs->c == '?')
- xtables_error(PARAMETER_PROBLEM, "unknown option "
- "\"%s\"", cs->argv[optind-1]);
+ if (cs->c == '?') {
+ char optoptstr[3] = {'-', optopt, '\0'};
+
+ xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"",
+ optopt ? optoptstr : cs->argv[optind - 1]);
+ }
xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
}
@@ -220,9 +228,7 @@ void xs_init_target(struct xtables_target *target)
{
if (target->udata_size != 0) {
free(target->udata);
- target->udata = calloc(1, target->udata_size);
- if (target->udata == NULL)
- xtables_error(RESOURCE_PROBLEM, "malloc");
+ target->udata = xtables_calloc(1, target->udata_size);
}
if (target->init != NULL)
target->init(target->t);
@@ -238,22 +244,20 @@ void xs_init_match(struct xtables_match *match)
* Same goes for target.
*/
free(match->udata);
- match->udata = calloc(1, match->udata_size);
- if (match->udata == NULL)
- xtables_error(RESOURCE_PROBLEM, "malloc");
+ match->udata = xtables_calloc(1, match->udata_size);
}
if (match->init != NULL)
match->init(match->m);
}
-static int xtables_lock(int wait, struct timeval *wait_interval)
+static void alarm_ignore(int i) {
+}
+
+static int xtables_lock(int wait)
{
- struct timeval time_left, wait_time;
+ struct sigaction sigact_alarm;
const char *lock_file;
- int fd, i = 0;
-
- time_left.tv_sec = wait;
- time_left.tv_usec = 0;
+ int fd;
lock_file = getenv("XTABLES_LOCKFILE");
if (lock_file == NULL || lock_file[0] == '\0')
@@ -266,31 +270,24 @@ static int xtables_lock(int wait, struct timeval *wait_interval)
return XT_LOCK_FAILED;
}
- if (wait == -1) {
- if (flock(fd, LOCK_EX) == 0)
- return fd;
-
- fprintf(stderr, "Can't lock %s: %s\n", lock_file,
- strerror(errno));
- return XT_LOCK_BUSY;
+ if (wait > 0) {
+ sigact_alarm.sa_handler = alarm_ignore;
+ sigact_alarm.sa_flags = SA_RESETHAND;
+ sigemptyset(&sigact_alarm.sa_mask);
+ sigaction(SIGALRM, &sigact_alarm, NULL);
+ alarm(wait);
}
- while (1) {
- if (flock(fd, LOCK_EX | LOCK_NB) == 0)
- return fd;
- else if (timercmp(&time_left, wait_interval, <))
- return XT_LOCK_BUSY;
+ if (flock(fd, LOCK_EX | (wait ? 0 : LOCK_NB)) == 0)
+ return fd;
- if (++i % 10 == 0) {
- fprintf(stderr, "Another app is currently holding the xtables lock; "
- "still %lds %ldus time ahead to have a chance to grab the lock...\n",
- time_left.tv_sec, time_left.tv_usec);
- }
-
- wait_time = *wait_interval;
- select(0, NULL, NULL, NULL, &wait_time);
- timersub(&time_left, wait_interval, &time_left);
+ if (errno == EINTR) {
+ errno = EWOULDBLOCK;
}
+
+ fprintf(stderr, "Can't lock %s: %s\n", lock_file,
+ strerror(errno));
+ return XT_LOCK_BUSY;
}
void xtables_unlock(int lock)
@@ -299,9 +296,9 @@ void xtables_unlock(int lock)
close(lock);
}
-int xtables_lock_or_exit(int wait, struct timeval *wait_interval)
+int xtables_lock_or_exit(int wait)
{
- int lock = xtables_lock(wait, wait_interval);
+ int lock = xtables_lock(wait);
if (lock == XT_LOCK_FAILED) {
xtables_free_opts(1);
@@ -337,7 +334,7 @@ int parse_wait_time(int argc, char *argv[])
return wait;
}
-void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval)
+void parse_wait_interval(int argc, char *argv[])
{
const char *arg;
unsigned int usec;
@@ -357,8 +354,7 @@ void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval)
"too long usec wait %u > 999999 usec",
usec);
- wait_interval->tv_sec = 0;
- wait_interval->tv_usec = usec;
+ fprintf(stderr, "Ignoring deprecated --wait-interval option.\n");
return;
}
xtables_error(PARAMETER_PROBLEM, "wait interval not numeric");
@@ -397,15 +393,15 @@ bool tokenize_rule_counters(char **bufferp, char **pcntp, char **bcntp, int line
ptr = strchr(buffer, ']');
if (!ptr)
- xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
+ xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line);
pcnt = strtok(buffer+1, ":");
if (!pcnt)
- xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line);
+ xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :", line);
bcnt = strtok(NULL, "]");
if (!bcnt)
- xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line);
+ xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]", line);
*pcntp = pcnt;
*bcntp = bcnt;
@@ -430,12 +426,12 @@ void add_argv(struct argv_store *store, const char *what, int quoted)
if (store->argc + 1 >= MAX_ARGC)
xtables_error(PARAMETER_PROBLEM,
- "Parser cannot handle more arguments\n");
+ "Parser cannot handle more arguments");
if (!what)
xtables_error(PARAMETER_PROBLEM,
- "Trying to store NULL argument\n");
+ "Trying to store NULL argument");
- store->argv[store->argc] = strdup(what);
+ store->argv[store->argc] = xtables_strdup(what);
store->argvattr[store->argc] = quoted;
store->argv[++store->argc] = NULL;
}
@@ -550,9 +546,55 @@ void debug_print_argv(struct argv_store *store)
}
#endif
-static const char *ipv4_addr_to_string(const struct in_addr *addr,
- const struct in_addr *mask,
- unsigned int format)
+void print_header(unsigned int format, const char *chain, const char *pol,
+ const struct xt_counters *counters,
+ int refs, uint32_t entries)
+{
+ printf("Chain %s", chain);
+ if (pol) {
+ printf(" (policy %s", pol);
+ if (!(format & FMT_NOCOUNTS)) {
+ fputc(' ', stdout);
+ xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
+ fputs("packets, ", stdout);
+ xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
+ fputs("bytes", stdout);
+ }
+ printf(")\n");
+ } else if (refs < 0) {
+ printf(" (ERROR obtaining refs)\n");
+ } else {
+ printf(" (%d references)\n", refs);
+ }
+
+ if (format & FMT_LINENUMBERS)
+ printf(FMT("%-4s ", "%s "), "num");
+ if (!(format & FMT_NOCOUNTS)) {
+ if (format & FMT_KILOMEGAGIGA) {
+ printf(FMT("%5s ","%s "), "pkts");
+ printf(FMT("%5s ","%s "), "bytes");
+ } else {
+ printf(FMT("%8s ","%s "), "pkts");
+ printf(FMT("%10s ","%s "), "bytes");
+ }
+ }
+ if (!(format & FMT_NOTARGET))
+ printf(FMT("%-9s ","%s "), "target");
+ fputs(" prot ", stdout);
+ if (format & FMT_OPTIONS)
+ fputs("opt", stdout);
+ if (format & FMT_VIA) {
+ printf(FMT(" %-6s ","%s "), "in");
+ printf(FMT("%-6s ","%s "), "out");
+ }
+ printf(FMT(" %-19s ","%s "), "source");
+ printf(FMT(" %-19s "," %s "), "destination");
+ printf("\n");
+}
+
+const char *ipv4_addr_to_string(const struct in_addr *addr,
+ const struct in_addr *mask,
+ unsigned int format)
{
static char buf[BUFSIZ];
@@ -582,6 +624,42 @@ void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format)
ipv4_addr_to_string(&fw->ip.dst, &fw->ip.dmsk, format));
}
+static const char *mask_to_str(const struct in_addr *mask)
+{
+ uint32_t bits, hmask = ntohl(mask->s_addr);
+ static char mask_str[INET_ADDRSTRLEN];
+ int i;
+
+ if (mask->s_addr == 0xFFFFFFFFU) {
+ sprintf(mask_str, "32");
+ return mask_str;
+ }
+
+ i = 32;
+ bits = 0xFFFFFFFEU;
+ while (--i >= 0 && hmask != bits)
+ bits <<= 1;
+ if (i >= 0)
+ sprintf(mask_str, "%u", i);
+ else
+ inet_ntop(AF_INET, mask, mask_str, sizeof(mask_str));
+
+ return mask_str;
+}
+
+void save_ipv4_addr(char letter, const struct in_addr *addr,
+ const struct in_addr *mask, int invert)
+{
+ char addrbuf[INET_ADDRSTRLEN];
+
+ if (!mask->s_addr && !invert && !addr->s_addr)
+ return;
+
+ printf("%s -%c %s/%s", invert ? " !" : "", letter,
+ inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)),
+ mask_to_str(mask));
+}
+
static const char *ipv6_addr_to_string(const struct in6_addr *addr,
const struct in6_addr *mask,
unsigned int format)
@@ -616,6 +694,44 @@ void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format)
&fw6->ipv6.dmsk, format));
}
+void save_ipv6_addr(char letter, const struct in6_addr *addr,
+ const struct in6_addr *mask, int invert)
+{
+ int l = xtables_ip6mask_to_cidr(mask);
+ char addr_str[INET6_ADDRSTRLEN];
+
+ if (!invert && l == 0)
+ return;
+
+ printf("%s -%c %s",
+ invert ? " !" : "", letter,
+ inet_ntop(AF_INET6, addr, addr_str, sizeof(addr_str)));
+
+ if (l == -1)
+ printf("/%s", inet_ntop(AF_INET6, mask,
+ addr_str, sizeof(addr_str)));
+ else
+ printf("/%d", l);
+}
+
+void print_fragment(unsigned int flags, unsigned int invflags,
+ unsigned int format, bool fake)
+{
+ if (!(format & FMT_OPTIONS))
+ return;
+
+ if (format & FMT_NOTABLE)
+ fputs("opt ", stdout);
+
+ if (fake) {
+ fputs("--", stdout);
+ } else {
+ fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout);
+ fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
+ }
+ fputc(' ', stdout);
+}
+
/* Luckily, IPT_INV_VIA_IN and IPT_INV_VIA_OUT
* have the same values as IP6T_INV_VIA_IN and IP6T_INV_VIA_OUT
* so this function serves for both iptables and ip6tables */
@@ -641,13 +757,21 @@ void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
printf(FMT("%-6s ", "out %s "), iface);
}
-void command_match(struct iptables_command_state *cs)
+void save_iface(char letter, const char *iface, int invert)
+{
+ if (!strlen(iface) || !strcmp(iface, "+"))
+ return;
+
+ printf("%s -%c %s", invert ? " !" : "", letter, iface);
+}
+
+static void command_match(struct iptables_command_state *cs, bool invert)
{
struct option *opts = xt_params->opts;
struct xtables_match *m;
size_t size;
- if (cs->invert)
+ if (invert)
xtables_error(PARAMETER_PROBLEM,
"unexpected ! flag before --match");
@@ -674,12 +798,15 @@ void command_match(struct iptables_command_state *cs)
else if (m->extra_opts != NULL)
opts = xtables_merge_options(xt_params->orig_opts, opts,
m->extra_opts, &m->option_offset);
+ else
+ return;
+
if (opts == NULL)
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
xt_params->opts = opts;
}
-const char *xt_parse_target(const char *targetname)
+static const char *xt_parse_target(const char *targetname)
{
const char *ptr;
@@ -732,16 +859,19 @@ void command_jump(struct iptables_command_state *cs, const char *jumpto)
opts = xtables_options_xfrm(xt_params->orig_opts, opts,
cs->target->x6_options,
&cs->target->option_offset);
- else
+ else if (cs->target->extra_opts != NULL)
opts = xtables_merge_options(xt_params->orig_opts, opts,
cs->target->extra_opts,
&cs->target->option_offset);
+ else
+ return;
+
if (opts == NULL)
xtables_error(OTHER_PROBLEM, "can't alloc memory!");
xt_params->opts = opts;
}
-char cmd2char(int option)
+static char cmd2char(int option)
{
/* cmdflags index corresponds with position of bit in CMD_* values */
static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
@@ -752,24 +882,23 @@ char cmd2char(int option)
;
if (i >= ARRAY_SIZE(cmdflags))
xtables_error(OTHER_PROBLEM,
- "cmd2char(): Invalid command number %u.\n",
- 1 << i);
+ "cmd2char(): Invalid command number %u.", 1 << i);
return cmdflags[i];
}
-void add_command(unsigned int *cmd, const int newcmd,
- const int othercmds, int invert)
+static void add_command(unsigned int *cmd, const int newcmd,
+ const int othercmds, int invert)
{
if (invert)
xtables_error(PARAMETER_PROBLEM, "unexpected '!' flag");
if (*cmd & (~othercmds))
- xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n",
- cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
+ xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c",
+ cmd2char(newcmd), cmd2char(*cmd & (~othercmds)));
*cmd |= newcmd;
}
/* Can't be zero. */
-int parse_rulenumber(const char *rule)
+static int parse_rulenumber(const char *rule)
{
unsigned int rulenum;
@@ -779,3 +908,1288 @@ int parse_rulenumber(const char *rule)
return rulenum;
}
+
+static void parse_rule_range(struct xt_cmd_parse *p, const char *argv)
+{
+ char *colon = strchr(argv, ':'), *buffer;
+
+ if (colon) {
+ if (!p->rule_ranges)
+ xtables_error(PARAMETER_PROBLEM,
+ "Rule ranges are not supported");
+
+ *colon = '\0';
+ if (*(colon + 1) == '\0')
+ p->rulenum_end = -1; /* Until the last rule */
+ else {
+ p->rulenum_end = strtol(colon + 1, &buffer, 10);
+ if (*buffer != '\0' || p->rulenum_end == 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid rule range end`%s'",
+ colon + 1);
+ }
+ }
+ if (colon == argv)
+ p->rulenum = 1; /* Beginning with the first rule */
+ else {
+ p->rulenum = strtol(argv, &buffer, 10);
+ if (*buffer != '\0' || p->rulenum == 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid rule number `%s'", argv);
+ }
+ if (!colon)
+ p->rulenum_end = p->rulenum;
+}
+
+/* list the commands an option is allowed with */
+#define CMD_IDRAC CMD_INSERT | CMD_DELETE | CMD_REPLACE | \
+ CMD_APPEND | CMD_CHECK | CMD_CHANGE_COUNTERS
+static const unsigned int options_v_commands[NUMBER_OF_OPT] = {
+/*OPT_NUMERIC*/ CMD_LIST,
+/*OPT_SOURCE*/ CMD_IDRAC,
+/*OPT_DESTINATION*/ CMD_IDRAC,
+/*OPT_PROTOCOL*/ CMD_IDRAC,
+/*OPT_JUMP*/ CMD_IDRAC,
+/*OPT_VERBOSE*/ UINT_MAX,
+/*OPT_EXPANDED*/ CMD_LIST,
+/*OPT_VIANAMEIN*/ CMD_IDRAC,
+/*OPT_VIANAMEOUT*/ CMD_IDRAC,
+/*OPT_LINENUMBERS*/ CMD_LIST,
+/*OPT_COUNTERS*/ CMD_INSERT | CMD_REPLACE | CMD_APPEND | CMD_SET_POLICY,
+/*OPT_FRAGMENT*/ CMD_IDRAC,
+/*OPT_S_MAC*/ CMD_IDRAC,
+/*OPT_D_MAC*/ CMD_IDRAC,
+/*OPT_H_LENGTH*/ CMD_IDRAC,
+/*OPT_OPCODE*/ CMD_IDRAC,
+/*OPT_H_TYPE*/ CMD_IDRAC,
+/*OPT_P_TYPE*/ CMD_IDRAC,
+/*OPT_LOGICALIN*/ CMD_IDRAC,
+/*OPT_LOGICALOUT*/ CMD_IDRAC,
+/*OPT_LIST_C*/ CMD_LIST,
+/*OPT_LIST_X*/ CMD_LIST,
+/*OPT_LIST_MAC2*/ CMD_LIST,
+};
+#undef CMD_IDRAC
+
+static void generic_opt_check(struct xt_cmd_parse_ops *ops,
+ int command, int options)
+{
+ int i, optval;
+
+ /* 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, optval = 1; i < NUMBER_OF_OPT; optval = (1 << ++i)) {
+ if ((options & optval) &&
+ (options_v_commands[i] & command) != command)
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal option `%s' with this command",
+ ops->option_name(optval));
+ }
+}
+
+const char *ip46t_option_name(int option)
+{
+ switch (option) {
+ case OPT_NUMERIC: return "--numeric";
+ case OPT_SOURCE: return "--source";
+ case OPT_DESTINATION: return "--destination";
+ case OPT_PROTOCOL: return "--protocol";
+ case OPT_JUMP: return "--jump";
+ case OPT_VERBOSE: return "--verbose";
+ case OPT_EXPANDED: return "--exact";
+ case OPT_VIANAMEIN: return "--in-interface";
+ case OPT_VIANAMEOUT: return "--out-interface";
+ case OPT_LINENUMBERS: return "--line-numbers";
+ case OPT_COUNTERS: return "--set-counters";
+ case OPT_FRAGMENT: return "--fragments";
+ default: return "unknown option";
+ }
+}
+
+int ip46t_option_invert(int option)
+{
+ switch (option) {
+ case OPT_SOURCE: return IPT_INV_SRCIP;
+ case OPT_DESTINATION: return IPT_INV_DSTIP;
+ case OPT_PROTOCOL: return XT_INV_PROTO;
+ case OPT_VIANAMEIN: return IPT_INV_VIA_IN;
+ case OPT_VIANAMEOUT: return IPT_INV_VIA_OUT;
+ case OPT_FRAGMENT: return IPT_INV_FRAG;
+ default: return -1;
+ }
+}
+
+static void
+set_option(struct xt_cmd_parse_ops *ops,
+ unsigned int *options, unsigned int option,
+ uint16_t *invflg, bool invert)
+{
+ if (*options & option)
+ xtables_error(PARAMETER_PROBLEM,
+ "multiple %s options not allowed",
+ ops->option_name(option));
+ *options |= option;
+
+ if (invert) {
+ int invopt = ops->option_invert(option);
+
+ if (invopt < 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "cannot have ! before %s",
+ ops->option_name(option));
+ *invflg |= invopt;
+ }
+}
+
+void assert_valid_chain_name(const char *chainname)
+{
+ const char *ptr;
+
+ if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name `%s' too long (must be under %u chars)",
+ chainname, XT_EXTENSION_MAXNAMELEN);
+
+ if (*chainname == '-' || *chainname == '!')
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name not allowed to start with `%c'",
+ *chainname);
+
+ if (xtables_find_target(chainname, XTF_TRY_LOAD))
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name may not clash with target name");
+
+ for (ptr = chainname; *ptr; ptr++)
+ if (isspace(*ptr))
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid chain name `%s'", chainname);
+}
+
+void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs,
+ const char *targname, uint8_t proto, uint8_t flags,
+ uint8_t invflags, unsigned int format)
+{
+ const char *pname = proto_to_name(proto, format&FMT_NUMERIC);
+
+ if (format & FMT_LINENUMBERS)
+ printf(FMT("%-4u ", "%u "), linenum);
+
+ if (!(format & FMT_NOCOUNTS)) {
+ xtables_print_num(ctrs->pcnt, format);
+ xtables_print_num(ctrs->bcnt, format);
+ }
+
+ if (!(format & FMT_NOTARGET))
+ printf(FMT("%-9s ", "%s "), targname ? targname : "");
+
+ fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout);
+
+ if (pname)
+ printf(FMT("%-4s ", "%s "), pname);
+ else
+ printf(FMT("%-4hu ", "%hu "), proto);
+}
+
+void save_rule_details(const char *iniface, const char *outiface,
+ uint16_t proto, int frag, uint8_t invflags)
+{
+ if (iniface != NULL) {
+ save_iface('i', iniface, invflags & IPT_INV_VIA_IN);
+ }
+ if (outiface != NULL) {
+ save_iface('o', outiface, invflags & IPT_INV_VIA_OUT);
+ }
+
+ if (proto > 0) {
+ const char *pname = proto_to_name(proto, true);
+
+ if (invflags & XT_INV_PROTO)
+ printf(" !");
+
+ if (pname)
+ printf(" -p %s", pname);
+ else
+ printf(" -p %u", proto);
+ }
+
+ if (frag) {
+ if (invflags & IPT_INV_FRAG)
+ printf(" !");
+ printf(" -f");
+ }
+}
+
+int print_match_save(const struct xt_entry_match *e, const void *ip)
+{
+ const char *name = e->u.user.name;
+ const int revision = e->u.user.revision;
+ struct xtables_match *match, *mt, *mt2;
+
+ match = xtables_find_match(name, XTF_TRY_LOAD, NULL);
+ if (match) {
+ mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD,
+ match, revision);
+ if (!mt2)
+ mt2 = match;
+ printf(" -m %s", mt2->alias ? mt2->alias(e) : name);
+
+ /* some matches don't provide a save function */
+ if (mt && mt->save)
+ mt->save(ip, e);
+ else if (match->save)
+ printf(" [unsupported revision]");
+ } else {
+ if (e->u.match_size) {
+ fprintf(stderr,
+ "Can't find library for match `%s'\n",
+ name);
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+void xtables_printhelp(struct iptables_command_state *cs)
+{
+ const struct xtables_rule_match *matches = cs->matches;
+ const char *prog_name = xt_params->program_name;
+ const char *prog_vers = xt_params->program_version;
+
+ printf("%s v%s\n\n"
+"Usage: %s -[ACD] chain rule-specification [options]\n"
+" %s -I chain [rulenum] rule-specification [options]\n"
+" %s -R chain rulenum rule-specification [options]\n"
+" %s -D chain rulenum [options]\n"
+" %s -[LS] [chain [rulenum]] [options]\n"
+" %s -[FZ] [chain] [options]\n"
+" %s -[NX] chain\n"
+" %s -E old-chain-name new-chain-name\n"
+" %s -P chain target [options]\n"
+" %s -h (print this help information)\n\n",
+ prog_name, prog_vers, prog_name, prog_name,
+ prog_name, prog_name, prog_name, prog_name,
+ prog_name, prog_name, prog_name, prog_name);
+
+ printf(
+"Commands:\n"
+"Either long or short options are allowed.\n"
+" --append -A chain Append to chain\n"
+" --check -C chain Check for the existence of a rule\n"
+" --delete -D chain Delete matching rule from chain\n"
+" --delete -D chain rulenum\n"
+" Delete rule rulenum (1 = first) from chain\n"
+" --insert -I chain [rulenum]\n"
+" Insert in chain as rulenum (default 1=first)\n"
+" --replace -R chain rulenum\n"
+" Replace rule rulenum (1 = first) in chain\n"
+" --list -L [chain [rulenum]]\n"
+" List the rules in a chain or all chains\n"
+" --list-rules -S [chain [rulenum]]\n"
+" Print the rules in a chain or all chains\n"
+" --flush -F [chain] Delete all rules in chain or all chains\n"
+" --zero -Z [chain [rulenum]]\n"
+" Zero counters in chain or all chains\n"
+" --new -N chain Create a new user-defined chain\n"
+" --delete-chain\n"
+" -X [chain] Delete a user-defined chain\n"
+" --policy -P chain target\n"
+" Change policy on chain to target\n"
+" --rename-chain\n"
+" -E old-chain new-chain\n"
+" Change chain name, (moving any references)\n"
+"\n"
+"Options:\n");
+
+ if (afinfo->family == NFPROTO_ARP) {
+ printf(
+"[!] --source-ip -s address[/mask]\n"
+" source specification\n"
+"[!] --destination-ip -d address[/mask]\n"
+" destination specification\n"
+"[!] --source-mac address[/mask]\n"
+"[!] --destination-mac address[/mask]\n"
+" --h-length -l length[/mask] hardware length (nr of bytes)\n"
+" --opcode code[/mask] operation code (2 bytes)\n"
+" --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n"
+" --proto-type type[/mask] protocol type (2 bytes)\n");
+ } else {
+ printf(
+" --ipv4 -4 %s (line is ignored by ip6tables-restore)\n"
+" --ipv6 -6 %s (line is ignored by iptables-restore)\n"
+"[!] --protocol -p proto protocol: by number or name, eg. `tcp'\n"
+"[!] --source -s address[/mask][...]\n"
+" source specification\n"
+"[!] --destination -d address[/mask][...]\n"
+" destination specification\n",
+ afinfo->family == NFPROTO_IPV4 ? "Nothing" : "Error",
+ afinfo->family == NFPROTO_IPV4 ? "Error" : "Nothing");
+ }
+
+ printf(
+"[!] --in-interface -i input name[+]\n"
+" network interface name ([+] for wildcard)\n"
+" --jump -j target\n"
+" target for rule (may load target extension)\n");
+
+ if (0
+#ifdef IPT_F_GOTO
+ || afinfo->family == NFPROTO_IPV4
+#endif
+#ifdef IP6T_F_GOTO
+ || afinfo->family == NFPROTO_IPV6
+#endif
+ )
+ printf(
+" --goto -g chain\n"
+" jump to chain with no return\n");
+ printf(
+" --match -m match\n"
+" extended match (may load extension)\n"
+" --numeric -n numeric output of addresses and ports\n"
+"[!] --out-interface -o output name[+]\n"
+" network interface name ([+] for wildcard)\n"
+" --table -t table table to manipulate (default: `filter')\n"
+" --verbose -v verbose mode\n"
+" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
+" --line-numbers print line numbers when listing\n"
+" --exact -x expand numbers (display exact values)\n");
+
+ if (afinfo->family == NFPROTO_IPV4)
+ printf(
+"[!] --fragment -f match second or further fragments only\n");
+
+ printf(
+" --modprobe=<command> try to insert modules using this command\n"
+" --set-counters -c PKTS BYTES set the counter during insert/append\n"
+"[!] --version -V print package version.\n");
+
+ if (afinfo->family == NFPROTO_ARP) {
+ int i;
+
+ printf(" opcode strings: \n");
+ for (i = 0; i < ARP_NUMOPCODES; i++)
+ printf(" %d = %s\n", i + 1, arp_opcodes[i]);
+ printf(
+ " hardware type string: 1 = Ethernet\n"
+ " protocol type string: 0x800 = IPv4\n");
+
+ xtables_find_target("standard", XTF_TRY_LOAD);
+ xtables_find_target("mangle", XTF_TRY_LOAD);
+ xtables_find_target("CLASSIFY", XTF_TRY_LOAD);
+ xtables_find_target("MARK", XTF_TRY_LOAD);
+ }
+
+ print_extension_helps(xtables_targets, matches);
+}
+
+void exit_tryhelp(int status, int line)
+{
+ if (line != -1)
+ fprintf(stderr, "Error occurred at line: %d\n", line);
+ fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
+ xt_params->program_name, xt_params->program_name);
+ xtables_free_opts(1);
+ exit(status);
+}
+
+static void check_empty_interface(struct xtables_args *args, const char *arg)
+{
+ const char *msg = "Empty interface is likely to be undesired";
+
+ if (*arg != '\0')
+ return;
+
+ if (args->family != NFPROTO_ARP)
+ xtables_error(PARAMETER_PROBLEM, "%s", msg);
+
+ fprintf(stderr, "%s", msg);
+}
+
+static void check_inverse(struct xtables_args *args, const char option[],
+ bool *invert, int argc, char **argv)
+{
+ switch (args->family) {
+ case NFPROTO_ARP:
+ case NFPROTO_BRIDGE:
+ break;
+ default:
+ return;
+ }
+
+ if (!option || strcmp(option, "!"))
+ return;
+
+ fprintf(stderr, "Using intrapositioned negation (`--option ! this`) "
+ "is deprecated in favor of extrapositioned (`! --option this`).\n");
+
+ if (*invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Multiple `!' flags not allowed");
+ *invert = true;
+ optind++;
+ if (optind > argc)
+ xtables_error(PARAMETER_PROBLEM, "no argument following `!'");
+
+ optarg = argv[optind - 1];
+}
+
+static const char *optstring_lookup(int family)
+{
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ return IPT_OPTSTRING;
+ case NFPROTO_ARP:
+ return ARPT_OPTSTRING;
+ case NFPROTO_BRIDGE:
+ return EBT_OPTSTRING;
+ }
+ return "";
+}
+
+void xtables_clear_iptables_command_state(struct iptables_command_state *cs)
+{
+ xtables_rule_matches_free(&cs->matches);
+ if (cs->target) {
+ free(cs->target->t);
+ cs->target->t = NULL;
+
+ free(cs->target->udata);
+ cs->target->udata = NULL;
+
+ if (cs->target == cs->target->next) {
+ free(cs->target);
+ cs->target = NULL;
+ }
+ }
+}
+
+void iface_to_mask(const char *iface, unsigned char *mask)
+{
+ unsigned int len = strlen(iface);
+
+ memset(mask, 0, IFNAMSIZ);
+
+ if (!len) {
+ return;
+ } else if (iface[len - 1] == '+') {
+ memset(mask, 0xff, len - 1);
+ /* Don't remove `+' here! -HW */
+ } else {
+ /* Include nul-terminator in match */
+ memset(mask, 0xff, len + 1);
+ }
+}
+
+static void parse_interface(const char *arg, char *iface)
+{
+ unsigned int len = strlen(arg);
+
+ memset(iface, 0, IFNAMSIZ);
+
+ if (!len)
+ return;
+ if (len >= IFNAMSIZ)
+ xtables_error(PARAMETER_PROBLEM,
+ "interface name `%s' must be shorter than %d characters",
+ arg, IFNAMSIZ);
+
+ if (strchr(arg, '/') || strchr(arg, ' '))
+ fprintf(stderr,
+ "Warning: weird character in interface `%s' ('/' and ' ' are not allowed by the kernel).\n",
+ arg);
+
+ strcpy(iface, arg);
+}
+
+static bool
+parse_signed_counter(char *argv, unsigned long long *val, uint8_t *ctr_op,
+ uint8_t flag_inc, uint8_t flag_dec)
+{
+ char *endptr, *p = argv;
+
+ switch (*p) {
+ case '+':
+ *ctr_op |= flag_inc;
+ p++;
+ break;
+ case '-':
+ *ctr_op |= flag_dec;
+ p++;
+ break;
+ }
+ *val = strtoull(p, &endptr, 10);
+ return *endptr == '\0';
+}
+
+static void parse_change_counters_rule(int argc, char **argv,
+ struct xt_cmd_parse *p,
+ struct xtables_args *args)
+{
+ if (optind + 1 >= argc ||
+ (argv[optind][0] == '-' && !isdigit(argv[optind][1])) ||
+ (argv[optind + 1][0] == '-' && !isdigit(argv[optind + 1][1])))
+ xtables_error(PARAMETER_PROBLEM,
+ "The command -C needs at least 2 arguments");
+ if (optind + 2 < argc &&
+ (argv[optind + 2][0] != '-' || isdigit(argv[optind + 2][1]))) {
+ if (optind + 3 != argc)
+ xtables_error(PARAMETER_PROBLEM,
+ "No extra options allowed with -C start_nr[:end_nr] pcnt bcnt");
+ parse_rule_range(p, argv[optind++]);
+ }
+
+ if (!parse_signed_counter(argv[optind++], &args->pcnt_cnt,
+ &args->counter_op,
+ CTR_OP_INC_PKTS, CTR_OP_DEC_PKTS) ||
+ !parse_signed_counter(argv[optind++], &args->bcnt_cnt,
+ &args->counter_op,
+ CTR_OP_INC_BYTES, CTR_OP_DEC_BYTES))
+ xtables_error(PARAMETER_PROBLEM,
+ "Packet counter '%s' invalid", argv[optind - 1]);
+}
+
+static void option_test_and_reject(struct xt_cmd_parse *p,
+ struct iptables_command_state *cs,
+ unsigned int option)
+{
+ if (cs->options & option)
+ xtables_error(PARAMETER_PROBLEM, "Can't use %s with %s",
+ p->ops->option_name(option), p->chain);
+}
+
+void do_parse(int argc, char *argv[],
+ struct xt_cmd_parse *p, struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ bool family_is_bridge = args->family == NFPROTO_BRIDGE;
+ struct xtables_match *m;
+ struct xtables_rule_match *matchp;
+ bool wait_interval_set = false;
+ struct xtables_target *t;
+ bool table_set = false;
+ bool invert = false;
+
+ /* re-set optind to 0 in case do_command4 gets called
+ * a second time */
+ optind = 0;
+
+ /* clear mflags in case do_command4 gets called a second time
+ * (we clear the global list of all matches for security)*/
+ for (m = xtables_matches; m; m = m->next)
+ m->mflags = 0;
+
+ for (t = xtables_targets; t; t = t->next) {
+ t->tflags = 0;
+ t->used = 0;
+ }
+
+ /* Suppress error messages: we may add new options if we
+ demand-load a protocol. */
+ opterr = 0;
+
+ while ((cs->c = getopt_long(argc, argv,
+ optstring_lookup(afinfo->family),
+ xt_params->opts ?: xt_params->orig_opts,
+ NULL)) != -1) {
+ switch (cs->c) {
+ /*
+ * Command selection
+ */
+ case 'A':
+ add_command(&p->command, CMD_APPEND, CMD_NONE, invert);
+ p->chain = optarg;
+ break;
+
+ case 'C':
+ if (family_is_bridge) {
+ add_command(&p->command, CMD_CHANGE_COUNTERS,
+ CMD_NONE, invert);
+ p->chain = optarg;
+ parse_change_counters_rule(argc, argv, p, args);
+ break;
+ }
+ /* fall through */
+ case 14: /* ebtables --check */
+ add_command(&p->command, CMD_CHECK, CMD_NONE, invert);
+ p->chain = optarg;
+ break;
+
+ case 'D':
+ add_command(&p->command, CMD_DELETE, CMD_NONE, invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv)) {
+ parse_rule_range(p, argv[optind++]);
+ p->command = CMD_DELETE_NUM;
+ }
+ break;
+
+ case 'R':
+ add_command(&p->command, CMD_REPLACE, CMD_NONE, invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ else
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c requires a rule number",
+ cmd2char(CMD_REPLACE));
+ break;
+
+ case 'I':
+ add_command(&p->command, CMD_INSERT, CMD_NONE, invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ else
+ p->rulenum = 1;
+ break;
+
+ case 'L':
+ add_command(&p->command, CMD_LIST,
+ CMD_ZERO | CMD_ZERO_NUM, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ break;
+
+ case 'S':
+ add_command(&p->command, CMD_LIST_RULES,
+ CMD_ZERO|CMD_ZERO_NUM, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ if (xs_has_arg(argc, argv))
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ break;
+
+ case 'F':
+ add_command(&p->command, CMD_FLUSH, CMD_NONE, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ break;
+
+ case 'Z':
+ add_command(&p->command, CMD_ZERO,
+ CMD_LIST|CMD_LIST_RULES, invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ if (xs_has_arg(argc, argv)) {
+ p->rulenum = parse_rulenumber(argv[optind++]);
+ p->command = CMD_ZERO_NUM;
+ }
+ break;
+
+ case 'N':
+ assert_valid_chain_name(optarg);
+ add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
+ invert);
+ p->chain = optarg;
+ break;
+
+ case 'X':
+ add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
+ invert);
+ if (optarg)
+ p->chain = optarg;
+ else if (xs_has_arg(argc, argv))
+ p->chain = argv[optind++];
+ break;
+
+ case 'E':
+ add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
+ invert);
+ p->chain = optarg;
+ if (xs_has_arg(argc, argv))
+ p->newname = argv[optind++];
+ else
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c requires old-chain-name and "
+ "new-chain-name",
+ cmd2char(CMD_RENAME_CHAIN));
+ assert_valid_chain_name(p->newname);
+ break;
+
+ case 'P':
+ add_command(&p->command, CMD_SET_POLICY,
+ family_is_bridge ? CMD_NEW_CHAIN : CMD_NONE,
+ invert);
+ if (p->command & CMD_NEW_CHAIN) {
+ p->policy = optarg;
+ } else if (xs_has_arg(argc, argv)) {
+ p->chain = optarg;
+ p->policy = argv[optind++];
+ } else {
+ xtables_error(PARAMETER_PROBLEM,
+ "-%c requires a chain and a policy",
+ cmd2char(CMD_SET_POLICY));
+ }
+ break;
+
+ case 'h':
+ /* iptables -p icmp -h */
+ if (!cs->matches && cs->protocol)
+ xtables_find_match(cs->protocol,
+ XTF_TRY_LOAD, &cs->matches);
+
+ p->ops->print_help(cs);
+ xtables_clear_iptables_command_state(cs);
+ xtables_free_opts(1);
+ xtables_fini();
+ exit(0);
+
+ /*
+ * Option selection
+ */
+ case 'p':
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_PROTOCOL,
+ &args->invflags, invert);
+
+ /* Canonicalize into lower case */
+ for (cs->protocol = optarg;
+ *cs->protocol; cs->protocol++)
+ *cs->protocol = tolower(*cs->protocol);
+
+ cs->protocol = optarg;
+
+ /* This needs to happen here to parse extensions */
+ if (p->ops->proto_parse)
+ p->ops->proto_parse(cs, args);
+ break;
+
+ case 's':
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_SOURCE,
+ &args->invflags, invert);
+ args->shostnetworkmask = optarg;
+ break;
+
+ case 'd':
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_DESTINATION,
+ &args->invflags, invert);
+ args->dhostnetworkmask = optarg;
+ break;
+
+#ifdef IPT_F_GOTO
+ case 'g':
+ set_option(p->ops, &cs->options, OPT_JUMP,
+ &args->invflags, invert);
+ args->goto_set = true;
+ cs->jumpto = xt_parse_target(optarg);
+ break;
+#endif
+
+ case 2:/* src-mac */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_S_MAC,
+ &args->invflags, invert);
+ args->src_mac = optarg;
+ break;
+
+ case 3:/* dst-mac */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_D_MAC,
+ &args->invflags, invert);
+ args->dst_mac = optarg;
+ break;
+
+ case 'l':/* hardware length */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_H_LENGTH,
+ &args->invflags, invert);
+ args->arp_hlen = optarg;
+ break;
+
+ case 8: /* was never supported, not even in arptables-legacy */
+ xtables_error(PARAMETER_PROBLEM, "not supported");
+ case 4:/* opcode */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_OPCODE,
+ &args->invflags, invert);
+ args->arp_opcode = optarg;
+ break;
+
+ case 5:/* h-type */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_H_TYPE,
+ &args->invflags, invert);
+ args->arp_htype = optarg;
+ break;
+
+ case 6:/* proto-type */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_P_TYPE,
+ &args->invflags, invert);
+ args->arp_ptype = optarg;
+ break;
+
+ case 11: /* ebtables --init-table */
+ if (p->restore)
+ xtables_error(PARAMETER_PROBLEM,
+ "--init-table is not supported in daemon mode");
+ add_command(&p->command, CMD_INIT_TABLE, CMD_NONE, invert);
+ break;
+
+ case 12 : /* ebtables --Lmac2 */
+ set_option(p->ops, &cs->options, OPT_LIST_MAC2,
+ &args->invflags, invert);
+ break;
+
+ case 13 : /* ebtables --concurrent */
+ break;
+
+ case 15 : /* ebtables --logical-in */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_LOGICALIN,
+ &args->invflags, invert);
+ parse_interface(optarg, args->bri_iniface);
+ break;
+
+ case 16 : /* ebtables --logical-out */
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_LOGICALOUT,
+ &args->invflags, invert);
+ parse_interface(optarg, args->bri_outiface);
+ break;
+
+ case 17 : /* ebtables --Lc */
+ set_option(p->ops, &cs->options, OPT_LIST_C,
+ &args->invflags, invert);
+ break;
+
+ case 19 : /* ebtables --Lx */
+ set_option(p->ops, &cs->options, OPT_LIST_X,
+ &args->invflags, invert);
+ break;
+
+ case 'j':
+ set_option(p->ops, &cs->options, OPT_JUMP,
+ &args->invflags, invert);
+ if (strcmp(optarg, "CONTINUE"))
+ command_jump(cs, optarg);
+ break;
+
+ case 'i':
+ check_empty_interface(args, optarg);
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_VIANAMEIN,
+ &args->invflags, invert);
+ parse_interface(optarg, args->iniface);
+ break;
+
+ case 'o':
+ check_empty_interface(args, optarg);
+ check_inverse(args, optarg, &invert, argc, argv);
+ set_option(p->ops, &cs->options, OPT_VIANAMEOUT,
+ &args->invflags, invert);
+ parse_interface(optarg, args->outiface);
+ break;
+
+ case 'f':
+ if (args->family == AF_INET6) {
+ xtables_error(PARAMETER_PROBLEM,
+ "`-f' is not supported in IPv6, "
+ "use -m frag instead");
+ }
+ set_option(p->ops, &cs->options, OPT_FRAGMENT,
+ &args->invflags, invert);
+ args->flags |= IPT_F_FRAG;
+ break;
+
+ case 'v':
+ if (!p->verbose)
+ set_option(p->ops, &cs->options, OPT_VERBOSE,
+ &args->invflags, invert);
+ p->verbose++;
+ break;
+
+ case 'm':
+ command_match(cs, invert);
+ break;
+
+ case 'n':
+ set_option(p->ops, &cs->options, OPT_NUMERIC,
+ &args->invflags, invert);
+ break;
+
+ case 't':
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "unexpected ! flag before --table");
+ if (p->restore && table_set)
+ xtables_error(PARAMETER_PROBLEM,
+ "The -t option cannot be used in %s.\n",
+ xt_params->program_name);
+ p->table = optarg;
+ table_set = true;
+ break;
+
+ case 'x':
+ set_option(p->ops, &cs->options, OPT_EXPANDED,
+ &args->invflags, invert);
+ break;
+
+ case 'V':
+ if (invert)
+ printf("Not %s ;-)\n",
+ xt_params->program_version);
+ else
+ printf("%s v%s\n",
+ xt_params->program_name,
+ xt_params->program_version);
+ exit(0);
+
+ case 'w':
+ if (p->restore) {
+ xtables_error(PARAMETER_PROBLEM,
+ "You cannot use `-w' from "
+ "iptables-restore");
+ }
+
+ args->wait = parse_wait_time(argc, argv);
+ break;
+
+ case 'W':
+ if (p->restore) {
+ xtables_error(PARAMETER_PROBLEM,
+ "You cannot use `-W' from "
+ "iptables-restore");
+ }
+
+ parse_wait_interval(argc, argv);
+ wait_interval_set = true;
+ break;
+
+ case '0':
+ case 18 : /* ebtables --Ln */
+ set_option(p->ops, &cs->options, OPT_LINENUMBERS,
+ &args->invflags, invert);
+ break;
+
+ case 'M':
+ xtables_modprobe_program = optarg;
+ break;
+
+ case 'c':
+ set_option(p->ops, &cs->options, OPT_COUNTERS,
+ &args->invflags, invert);
+ args->pcnt = optarg;
+ args->bcnt = strchr(args->pcnt + 1, ',');
+ if (args->bcnt)
+ args->bcnt++;
+ if (!args->bcnt && xs_has_arg(argc, argv))
+ args->bcnt = argv[optind++];
+ if (!args->bcnt)
+ xtables_error(PARAMETER_PROBLEM,
+ "%s requires packet and byte counter",
+ p->ops->option_name(OPT_COUNTERS));
+
+ if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "%s packet counter not numeric",
+ p->ops->option_name(OPT_COUNTERS));
+
+ if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "%s byte counter not numeric",
+ p->ops->option_name(OPT_COUNTERS));
+ break;
+
+ case '4':
+ if (args->family == AF_INET)
+ break;
+
+ if (p->restore && args->family == AF_INET6)
+ return;
+
+ exit_tryhelp(2, p->line);
+
+ case '6':
+ if (args->family == AF_INET6)
+ break;
+
+ if (p->restore && args->family == AF_INET)
+ return;
+
+ exit_tryhelp(2, p->line);
+
+ case 1: /* non option */
+ if (optarg[0] == '!' && optarg[1] == '\0') {
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "multiple consecutive ! not"
+ " allowed");
+ invert = true;
+ optarg[0] = '\0';
+ continue;
+ }
+ fprintf(stderr, "Bad argument `%s'\n", optarg);
+ exit_tryhelp(2, p->line);
+
+ default:
+ check_inverse(args, optarg, &invert, argc, argv);
+ if (p->ops->command_default(cs, xt_params, invert))
+ /* cf. ip6tables.c */
+ continue;
+ break;
+ }
+ invert = false;
+ }
+
+ if (!family_is_bridge &&
+ strcmp(p->table, "nat") == 0 &&
+ ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
+ (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
+ xtables_error(PARAMETER_PROBLEM,
+ "\nThe \"nat\" table is not intended for filtering, "
+ "the use of DROP is therefore inhibited.\n\n");
+
+ if (!args->wait && wait_interval_set)
+ xtables_error(PARAMETER_PROBLEM,
+ "--wait-interval only makes sense with --wait\n");
+
+ for (matchp = cs->matches; matchp; matchp = matchp->next)
+ xtables_option_mfcall(matchp->match);
+ if (cs->target != NULL)
+ xtables_option_tfcall(cs->target);
+
+ /* Fix me: must put inverse options checking here --MN */
+
+ if (optind < argc)
+ xtables_error(PARAMETER_PROBLEM,
+ "unknown arguments found on commandline");
+ if (!p->command)
+ xtables_error(PARAMETER_PROBLEM, "no command specified");
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "nothing appropriate following !");
+
+ if (p->ops->post_parse)
+ p->ops->post_parse(p->command, cs, args);
+
+ generic_opt_check(p->ops, p->command, cs->options);
+
+ if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name `%s' too long (must be under %u chars)",
+ p->chain, XT_EXTENSION_MAXNAMELEN);
+
+ if (p->command == CMD_APPEND ||
+ p->command == CMD_DELETE ||
+ p->command == CMD_CHECK ||
+ p->command == CMD_INSERT ||
+ p->command == CMD_REPLACE ||
+ p->command == CMD_CHANGE_COUNTERS) {
+ if (strcmp(p->chain, "PREROUTING") == 0
+ || strcmp(p->chain, "INPUT") == 0) {
+ /* -o not valid with incoming packets. */
+ option_test_and_reject(p, cs, OPT_VIANAMEOUT);
+ /* same with --logical-out */
+ option_test_and_reject(p, cs, OPT_LOGICALOUT);
+ }
+
+ if (strcmp(p->chain, "POSTROUTING") == 0
+ || strcmp(p->chain, "OUTPUT") == 0) {
+ /* -i not valid with outgoing packets */
+ option_test_and_reject(p, cs, OPT_VIANAMEIN);
+ /* same with --logical-in */
+ option_test_and_reject(p, cs, OPT_LOGICALIN);
+ }
+ }
+}
+
+void ipv4_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw.ip.proto = xtables_parse_protocol(cs->protocol);
+
+ if (cs->fw.ip.proto == 0 &&
+ (args->invflags & XT_INV_PROTO))
+ xtables_error(PARAMETER_PROBLEM,
+ "rule would never match protocol");
+
+ cs->fw.ip.invflags = args->invflags;
+}
+
+/* These are invalid numbers as upper layer protocol */
+static int is_exthdr(uint16_t proto)
+{
+ return (proto == IPPROTO_ROUTING ||
+ proto == IPPROTO_FRAGMENT ||
+ proto == IPPROTO_AH ||
+ proto == IPPROTO_DSTOPTS);
+}
+
+void ipv6_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw6.ipv6.proto = xtables_parse_protocol(cs->protocol);
+
+ if (cs->fw6.ipv6.proto == 0 &&
+ (args->invflags & XT_INV_PROTO))
+ xtables_error(PARAMETER_PROBLEM,
+ "rule would never match protocol");
+
+ cs->fw6.ipv6.invflags = args->invflags;
+
+ /* this is needed for ip6tables-legacy only */
+ args->flags |= IP6T_F_PROTO;
+ cs->fw6.ipv6.flags |= IP6T_F_PROTO;
+
+ if (is_exthdr(cs->fw6.ipv6.proto)
+ && (cs->fw6.ipv6.invflags & XT_INV_PROTO) == 0)
+ fprintf(stderr,
+ "Warning: never matched protocol: %s. "
+ "use extension match instead.\n",
+ cs->protocol);
+}
+
+void ipv4_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw.ip.flags = args->flags;
+ /* We already set invflags in proto_parse, but we need to refresh it
+ * to include new parsed options.
+ */
+ cs->fw.ip.invflags = args->invflags;
+
+ memcpy(cs->fw.ip.iniface, args->iniface, IFNAMSIZ);
+ memcpy(cs->fw.ip.outiface, args->outiface, IFNAMSIZ);
+
+ if (args->goto_set)
+ cs->fw.ip.flags |= IPT_F_GOTO;
+
+ /* nft-variants use cs->counters, legacy uses cs->fw.counters */
+ cs->counters.pcnt = args->pcnt_cnt;
+ cs->counters.bcnt = args->bcnt_cnt;
+ cs->fw.counters.pcnt = args->pcnt_cnt;
+ cs->fw.counters.bcnt = args->bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs->options & OPT_DESTINATION))
+ args->dhostnetworkmask = "0.0.0.0/0";
+ if (!(cs->options & OPT_SOURCE))
+ args->shostnetworkmask = "0.0.0.0/0";
+ }
+
+ if (args->shostnetworkmask)
+ xtables_ipparse_multiple(args->shostnetworkmask,
+ &args->s.addr.v4, &args->s.mask.v4,
+ &args->s.naddrs);
+ if (args->dhostnetworkmask)
+ xtables_ipparse_multiple(args->dhostnetworkmask,
+ &args->d.addr.v4, &args->d.mask.v4,
+ &args->d.naddrs);
+
+ if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+ (cs->fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+}
+
+void ipv6_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args)
+{
+ cs->fw6.ipv6.flags = args->flags;
+ /* We already set invflags in proto_parse, but we need to refresh it
+ * to include new parsed options.
+ */
+ cs->fw6.ipv6.invflags = args->invflags;
+
+ memcpy(cs->fw6.ipv6.iniface, args->iniface, IFNAMSIZ);
+ memcpy(cs->fw6.ipv6.iniface_mask,
+ args->iniface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ memcpy(cs->fw6.ipv6.outiface, args->outiface, IFNAMSIZ);
+ memcpy(cs->fw6.ipv6.outiface_mask,
+ args->outiface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ if (args->goto_set)
+ cs->fw6.ipv6.flags |= IP6T_F_GOTO;
+
+ /* nft-variants use cs->counters, legacy uses cs->fw6.counters */
+ cs->counters.pcnt = args->pcnt_cnt;
+ cs->counters.bcnt = args->bcnt_cnt;
+ cs->fw6.counters.pcnt = args->pcnt_cnt;
+ cs->fw6.counters.bcnt = args->bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs->options & OPT_DESTINATION))
+ args->dhostnetworkmask = "::0/0";
+ if (!(cs->options & OPT_SOURCE))
+ args->shostnetworkmask = "::0/0";
+ }
+
+ if (args->shostnetworkmask)
+ xtables_ip6parse_multiple(args->shostnetworkmask,
+ &args->s.addr.v6,
+ &args->s.mask.v6,
+ &args->s.naddrs);
+ if (args->dhostnetworkmask)
+ xtables_ip6parse_multiple(args->dhostnetworkmask,
+ &args->d.addr.v6,
+ &args->d.mask.v6,
+ &args->d.naddrs);
+
+ if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+ (cs->fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+}
+
+unsigned char *
+make_delete_mask(const struct xtables_rule_match *matches,
+ const struct xtables_target *target,
+ size_t entry_size)
+{
+ /* Establish mask for comparison */
+ unsigned int size = entry_size;
+ const struct xtables_rule_match *matchp;
+ unsigned char *mask, *mptr;
+
+ for (matchp = matches; matchp; matchp = matchp->next)
+ size += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
+
+ mask = xtables_calloc(1, size
+ + XT_ALIGN(sizeof(struct xt_entry_target))
+ + target->size);
+
+ memset(mask, 0xFF, entry_size);
+ mptr = mask + entry_size;
+
+ for (matchp = matches; matchp; matchp = matchp->next) {
+ memset(mptr, 0xFF,
+ XT_ALIGN(sizeof(struct xt_entry_match))
+ + matchp->match->userspacesize);
+ mptr += XT_ALIGN(sizeof(struct xt_entry_match)) + matchp->match->size;
+ }
+
+ memset(mptr, 0xFF,
+ XT_ALIGN(sizeof(struct xt_entry_target))
+ + target->userspacesize);
+
+ return mask;
+}
+
+void xtables_clear_args(struct xtables_args *args)
+{
+ free(args->s.addr.ptr);
+ free(args->s.mask.ptr);
+ free(args->d.addr.ptr);
+ free(args->d.mask.ptr);
+}
diff --git a/iptables/xshared.h b/iptables/xshared.h
index c41bd054..26c492eb 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -6,15 +6,21 @@
#include <stdint.h>
#include <netinet/in.h>
#include <net/if.h>
-#include <sys/time.h>
#include <linux/netfilter_arp/arp_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#ifdef DEBUG
#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
+#define DEBUG_HEXDUMP(pfx, data, len) \
+ for (int __i = 0; __i < (len); __i++) { \
+ if (__i % 16 == 0) \
+ printf("%s%s: ", __i ? "\n" : "", (pfx)); \
+ printf("%02x ", ((const unsigned char *)data)[__i]); \
+ } printf("\n")
#else
#define DEBUGP(x, args...)
+#define DEBUG_HEXDUMP(pfx, data, len)
#endif
enum {
@@ -30,14 +36,22 @@ 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,
+ /* below are for ebtables only */
+ OPT_LOGICALIN = 1 << 18,
+ OPT_LOGICALOUT = 1 << 19,
+ OPT_LIST_C = 1 << 20,
+ OPT_LIST_X = 1 << 21,
+ OPT_LIST_MAC2 = 1 << 22,
};
+#define NUMBER_OF_OPT 24
enum {
CMD_NONE = 0,
@@ -56,32 +70,28 @@ enum {
CMD_LIST_RULES = 1 << 12,
CMD_ZERO_NUM = 1 << 13,
CMD_CHECK = 1 << 14,
+ CMD_CHANGE_COUNTERS = 1 << 15, /* ebtables only */
+ CMD_INIT_TABLE = 1 << 16, /* ebtables only */
};
-#define NUMBER_OF_CMD 16
+#define NUMBER_OF_CMD 18
struct xtables_globals;
struct xtables_rule_match;
struct xtables_target;
-/**
- * xtables_afinfo - protocol family dependent information
- * @kmod: kernel module basename (e.g. "ip_tables")
- * @proc_exists: file which exists in procfs when module already loaded
- * @libprefix: prefix of .so library name (e.g. "libipt_")
- * @family: nfproto family
- * @ipproto: used by setsockopt (e.g. IPPROTO_IP)
- * @so_rev_match: optname to check revision support of match
- * @so_rev_target: optname to check revision support of target
+#define OPTSTRING_COMMON "-:A:C:D:E:F::I:L::M:N:P:R:S::VX::Z::" "c:d:i:j:o:p:s:t:v"
+#define IPT_OPTSTRING OPTSTRING_COMMON "W::" "46bfg:h::m:nw::x"
+#define ARPT_OPTSTRING OPTSTRING_COMMON "h::l:nx" /* "m:" */
+#define EBT_OPTSTRING OPTSTRING_COMMON "h"
+
+/* define invflags which won't collide with IPT ones.
+ * arptables-nft does NOT use the legacy ARPT_INV_* defines.
*/
-struct xtables_afinfo {
- const char *kmod;
- const char *proc_exists;
- const char *libprefix;
- uint8_t family;
- uint8_t ipproto;
- int so_rev_match;
- int so_rev_target;
-};
+#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
/* trick for ebtables-compat, since watchers are targets */
struct ebt_match {
@@ -120,7 +130,6 @@ struct iptables_command_state {
struct ip6t_entry fw6;
struct arpt_entry arp;
};
- int invert;
int c;
unsigned int options;
struct xtables_rule_match *matches;
@@ -130,10 +139,13 @@ struct iptables_command_state {
char *protocol;
int proto_used;
const char *jumpto;
+ int argc;
char **argv;
bool restore;
};
+void xtables_clear_iptables_command_state(struct iptables_command_state *cs);
+
typedef int (*mainfunc_t)(int, char **);
struct subcommand {
@@ -141,16 +153,6 @@ struct subcommand {
mainfunc_t main;
};
-enum {
- XT_OPTION_OFFSET_SCALE = 256,
-};
-
-extern void print_extension_helps(const struct xtables_target *,
- const struct xtables_rule_match *);
-extern const char *proto_to_name(uint8_t, int);
-extern int command_default(struct iptables_command_state *,
- struct xtables_globals *);
-extern struct xtables_match *load_proto(struct iptables_command_state *);
extern int subcmd_main(int, char **, const struct subcommand *);
extern void xs_init_target(struct xtables_target *);
extern void xs_init_match(struct xtables_match *);
@@ -174,16 +176,14 @@ enum {
XT_LOCK_NOT_ACQUIRED = -3,
};
extern void xtables_unlock(int lock);
-extern int xtables_lock_or_exit(int wait, struct timeval *tv);
+extern int xtables_lock_or_exit(int wait);
int parse_wait_time(int argc, char *argv[]);
-void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval);
+void parse_wait_interval(int argc, char *argv[]);
int parse_counters(const char *string, struct xt_counters *ctr);
bool tokenize_rule_counters(char **bufferp, char **pcnt, char **bcnt, int line);
bool xs_has_arg(int argc, char *argv[]);
-extern const struct xtables_afinfo *afinfo;
-
#define MAX_ARGC 255
struct argv_store {
int argc;
@@ -201,19 +201,140 @@ void debug_print_argv(struct argv_store *store);
# define debug_print_argv(...) /* nothing */
#endif
+const char *ipv4_addr_to_string(const struct in_addr *addr,
+ const struct in_addr *mask,
+ unsigned int format);
+void print_header(unsigned int format, const char *chain, const char *pol,
+ const struct xt_counters *counters,
+ int refs, uint32_t entries);
void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format);
+void save_ipv4_addr(char letter, const struct in_addr *addr,
+ const struct in_addr *mask, int invert);
void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format);
+void save_ipv6_addr(char letter, const struct in6_addr *addr,
+ const struct in6_addr *mask, int invert);
void print_ifaces(const char *iniface, const char *outiface, uint8_t invflags,
unsigned int format);
+void save_iface(char letter, const char *iface, int invert);
+
+void print_fragment(unsigned int flags, unsigned int invflags,
+ unsigned int format, bool fake);
-void command_match(struct iptables_command_state *cs);
-const char *xt_parse_target(const char *targetname);
void command_jump(struct iptables_command_state *cs, const char *jumpto);
-char cmd2char(int option);
-void add_command(unsigned int *cmd, const int newcmd,
- const int othercmds, int invert);
-int parse_rulenumber(const char *rule);
+void assert_valid_chain_name(const char *chainname);
+
+void print_rule_details(unsigned int linenum, const struct xt_counters *ctrs,
+ const char *targname, uint8_t proto, uint8_t flags,
+ uint8_t invflags, unsigned int format);
+void save_rule_details(const char *iniface, const char *outiface,
+ uint16_t proto, int frag, uint8_t invflags);
+
+int print_match_save(const struct xt_entry_match *e, const void *ip);
+
+void exit_tryhelp(int status, int line) __attribute__((noreturn));
+
+struct addr_mask {
+ union {
+ struct in_addr *v4;
+ struct in6_addr *v6;
+ void *ptr;
+ } addr;
+
+ unsigned int naddrs;
+
+ union {
+ struct in_addr *v4;
+ struct in6_addr *v6;
+ void *ptr;
+ } mask;
+};
+
+enum {
+ CTR_OP_INC_PKTS = 1 << 0,
+ CTR_OP_DEC_PKTS = 1 << 1,
+ CTR_OP_INC_BYTES = 1 << 2,
+ CTR_OP_DEC_BYTES = 1 << 3,
+};
+
+struct xtables_args {
+ int family;
+ uint8_t flags;
+ uint16_t invflags;
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+ char bri_iniface[IFNAMSIZ], bri_outiface[IFNAMSIZ];
+ bool goto_set;
+ const char *shostnetworkmask, *dhostnetworkmask;
+ const char *pcnt, *bcnt;
+ struct addr_mask s, d;
+ const char *src_mac, *dst_mac;
+ const char *arp_hlen, *arp_opcode;
+ const char *arp_htype, *arp_ptype;
+ unsigned long long pcnt_cnt, bcnt_cnt;
+ uint8_t counter_op;
+ int wait;
+};
+
+struct xt_cmd_parse_ops {
+ void (*proto_parse)(struct iptables_command_state *cs,
+ struct xtables_args *args);
+ void (*post_parse)(int command,
+ struct iptables_command_state *cs,
+ struct xtables_args *args);
+ const char *(*option_name)(int option);
+ int (*option_invert)(int option);
+ int (*command_default)(struct iptables_command_state *cs,
+ struct xtables_globals *gl, bool invert);
+ void (*print_help)(struct iptables_command_state *cs);
+};
+
+struct xt_cmd_parse {
+ unsigned int command;
+ unsigned int rulenum;
+ unsigned int rulenum_end;
+ char *table;
+ const char *chain;
+ const char *newname;
+ const char *policy;
+ bool restore;
+ int line;
+ int verbose;
+ bool rule_ranges;
+ struct xt_cmd_parse_ops *ops;
+};
+
+void xtables_printhelp(struct iptables_command_state *cs);
+const char *ip46t_option_name(int option);
+int ip46t_option_invert(int option);
+int command_default(struct iptables_command_state *cs,
+ struct xtables_globals *gl, bool invert);
+
+void do_parse(int argc, char *argv[],
+ struct xt_cmd_parse *p, struct iptables_command_state *cs,
+ struct xtables_args *args);
+
+void ipv4_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args);
+void ipv6_proto_parse(struct iptables_command_state *cs,
+ struct xtables_args *args);
+void ipv4_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args);
+void ipv6_post_parse(int command, struct iptables_command_state *cs,
+ struct xtables_args *args);
+
+extern char *arp_opcodes[];
+#define ARP_NUMOPCODES 9
+
+unsigned char *make_delete_mask(const struct xtables_rule_match *matches,
+ const struct xtables_target *target,
+ size_t entry_size);
+
+void iface_to_mask(const char *ifname, unsigned char *mask);
+
+void xtables_clear_args(struct xtables_args *args);
+
+const char *proto_to_name(uint16_t proto, int nolookup);
#endif /* IPTABLES_XSHARED_H */
diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
deleted file mode 100644
index 04cf7dcc..00000000
--- a/iptables/xtables-arp-standalone.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
- *
- * Based on the ipchains code by Paul Russell and Michael Neuling
- *
- * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>:
- * Paul 'Rusty' Russell <rusty@rustcorp.com.au>
- * Marc Boucher <marc+nf@mbsi.ca>
- * James Morris <jmorris@intercode.com.au>
- * Harald Welte <laforge@gnumonks.org>
- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- *
- * arptables -- IP firewall administration for kernels with
- * firewall table (aimed for the 2.3 kernels)
- *
- * See the accompanying manual page arptables(8) for information
- * about proper usage of this program.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <xtables.h>
-#include "nft.h"
-#include <linux/netfilter_arp/arp_tables.h>
-
-#include "xtables-multi.h"
-
-extern struct xtables_globals arptables_globals;
-
-int xtables_arp_main(int argc, char *argv[])
-{
- int ret;
- char *table = "filter";
- struct nft_handle h;
-
- nft_init_arp(&h, "arptables");
-
- ret = do_commandarp(&h, argc, argv, &table, false);
- if (ret)
- ret = nft_commit(&h);
-
- nft_fini(&h);
- xtables_fini();
-
- if (!ret)
- fprintf(stderr, "arptables: %s\n", nft_strerror(errno));
-
- exit(!ret);
-}
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 8632774d..71518a9c 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -30,39 +30,22 @@
#include "config.h"
#include <getopt.h>
#include <string.h>
-#include <netdb.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <inttypes.h>
-#include <dlfcn.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/wait.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <iptables.h>
#include <xtables.h>
#include "xshared.h"
#include "nft.h"
-#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' },
+ { "check", 1, 0, 'C'},
{ "insert", 1, 0, 'I' },
{ "replace", 1, 0, 'R' },
{ "list", 2, 0, 'L' },
+ { "list-rules", 2, 0, 'S'},
{ "flush", 2, 0, 'F' },
{ "zero", 2, 0, 'Z' },
{ "new-chain", 1, 0, 'N' },
@@ -100,391 +83,13 @@ static struct option original_opts[] = {
#define opts xt_params->opts
-extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals arptables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (nf_tables)",
.orig_opts = original_opts,
- .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
-/* index relates to bit of each OPT_* value */
-static int inverse_for_options[] =
-{
-/* -n */ 0,
-/* -s */ ARPT_INV_SRCIP,
-/* -d */ ARPT_INV_TGTIP,
-/* -p */ 0,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ ARPT_INV_VIA_IN,
-/* -o */ ARPT_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,
-};
-
-/***********************************************/
-/* 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;
- int i;
-
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- i = strtol(p+1, &buffer, 10);
- if (*buffer != '\0' || i < 0 || i > 255)
- return -1;
- *mask = (uint8_t)i;
- } else
- *mask = 255;
- i = strtol(from, &buffer, 10);
- if (*buffer != '\0' || i < 0 || i > 255)
- return -1;
- *to = (uint8_t)i;
- return 0;
-}
-
-static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
-{
- char *p, *buffer;
- int i;
-
- if ( (p = strrchr(from, '/')) != NULL) {
- *p = '\0';
- i = strtol(p+1, &buffer, base);
- if (*buffer != '\0' || i < 0 || i > 65535)
- return -1;
- *mask = htons((uint16_t)i);
- } else
- *mask = 65535;
- i = strtol(from, &buffer, base);
- if (*buffer != '\0' || i < 0 || i > 65535)
- return -1;
- *to = htons((uint16_t)i);
- return 0;
-}
-
-/*********************************************/
-/* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
-/*********************************************/
-
-static void
-exit_tryhelp(int status)
-{
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- arptables_globals.program_name,
- arptables_globals.program_version);
- exit(status);
-}
-
-static void
-printhelp(void)
-{
- struct xtables_target *t = NULL;
- int i;
-
- printf("%s v%s\n\n"
-"Usage: %s -[AD] chain rule-specification [options]\n"
-" %s -[RI] chain rulenum rule-specification [options]\n"
-" %s -D chain rulenum [options]\n"
-" %s -[LFZ] [chain] [options]\n"
-" %s -[NX] chain\n"
-" %s -E old-chain-name new-chain-name\n"
-" %s -P chain target [options]\n"
-" %s -h (print this help information)\n\n",
- arptables_globals.program_name,
- arptables_globals.program_version,
- arptables_globals.program_name,
- arptables_globals.program_name,
- arptables_globals.program_name,
- arptables_globals.program_name,
- arptables_globals.program_name,
- arptables_globals.program_name,
- arptables_globals.program_name,
- arptables_globals.program_name);
- printf(
-"Commands:\n"
-"Either long or short options are allowed.\n"
-" --append -A chain Append to chain\n"
-" --delete -D chain Delete matching rule from chain\n"
-" --delete -D chain rulenum\n"
-" Delete rule rulenum (1 = first) from chain\n"
-" --insert -I chain [rulenum]\n"
-" Insert in chain as rulenum (default 1=first)\n"
-" --replace -R chain rulenum\n"
-" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain] List the rules in a chain or all chains\n"
-" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain] Zero counters in chain or all chains\n"
-" --new -N chain Create a new user-defined chain\n"
-" --delete-chain\n"
-" -X [chain] Delete a user-defined chain\n"
-" --policy -P chain target\n"
-" Change policy on chain to target\n"
-" --rename-chain\n"
-" -E old-chain new-chain\n"
-" Change chain name, (moving any references)\n"
-
-"Options:\n"
-" --source-ip -s [!] address[/mask]\n"
-" source specification\n"
-" --destination-ip -d [!] address[/mask]\n"
-" destination specification\n"
-" --source-mac [!] address[/mask]\n"
-" --destination-mac [!] address[/mask]\n"
-" --h-length -l length[/mask] hardware length (nr of bytes)\n"
-" --opcode code[/mask] operation code (2 bytes)\n"
-" --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n"
-" --proto-type type[/mask] protocol type (2 bytes)\n"
-" --in-interface -i [!] input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --out-interface -o [!] output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters -c PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
- printf(" opcode strings: \n");
- for (i = 0; i < NUMOPCODES; i++)
- printf(" %d = %s\n", i + 1, arp_opcodes[i]);
- printf(
-" hardware type string: 1 = Ethernet\n"
-" protocol type string: 0x800 = IPv4\n");
-
- /* Print out any special helps. A user might like to be able
- to add a --help to the commandline, and see expected
- results. So we call help for all matches & targets */
- for (t = xtables_targets; t; t = t->next) {
- if (strcmp(t->name, "CLASSIFY") && strcmp(t->name, "mangle"))
- continue;
- printf("\n");
- t->help();
- }
-}
-
-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)
-{
- if (option && strcmp(option, "!") == 0) {
- if (*invert)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple `!' flags not allowed");
- *invert = true;
- if (optidx) {
- *optidx = *optidx+1;
- if (argc && *optidx > argc)
- xtables_error(PARAMETER_PROBLEM,
- "no argument following `!'");
- }
-
- return true;
- }
- return false;
-}
-
-static void
-set_option(unsigned int *options, unsigned int option, u_int16_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-static int
-list_entries(struct nft_handle *h, const char *chain, const char *table,
- int rulenum, int verbose, int numeric, int expanded,
- int linenumbers)
-{
- unsigned int format;
-
- format = FMT_OPTIONS;
- if (!verbose)
- format |= FMT_NOCOUNTS;
- else
- format |= FMT_VIA;
-
- if (numeric)
- format |= FMT_NUMERIC;
-
- if (!expanded)
- format |= FMT_KILOMEGAGIGA;
-
- if (linenumbers)
- format |= FMT_LINENUMBERS;
-
- return nft_cmd_rule_list(h, chain, table, rulenum, format);
-}
-
-static int
-append_entry(struct nft_handle *h,
- const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- int rulenum,
- unsigned int nsaddrs,
- const struct in_addr saddrs[],
- const struct in_addr smasks[],
- unsigned int ndaddrs,
- const struct in_addr daddrs[],
- const struct in_addr dmasks[],
- bool verbose, bool append)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < nsaddrs; i++) {
- cs->arp.arp.src.s_addr = saddrs[i].s_addr;
- cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
- for (j = 0; j < ndaddrs; j++) {
- cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
- cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
- if (append) {
- ret = nft_cmd_rule_append(h, chain, table, cs, NULL,
- verbose);
- } else {
- ret = nft_cmd_rule_insert(h, chain, table, cs,
- rulenum, verbose);
- }
- }
- }
-
- return ret;
-}
-
-static int
-replace_entry(const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- unsigned int rulenum,
- const struct in_addr *saddr,
- const struct in_addr *smask,
- const struct in_addr *daddr,
- const struct in_addr *dmask,
- bool verbose, struct nft_handle *h)
-{
- cs->arp.arp.src.s_addr = saddr->s_addr;
- cs->arp.arp.tgt.s_addr = daddr->s_addr;
- cs->arp.arp.smsk.s_addr = smask->s_addr;
- cs->arp.arp.tmsk.s_addr = dmask->s_addr;
-
- return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
-}
-
-static int
-delete_entry(const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- unsigned int nsaddrs,
- const struct in_addr saddrs[],
- const struct in_addr smasks[],
- unsigned int ndaddrs,
- const struct in_addr daddrs[],
- const struct in_addr dmasks[],
- bool verbose, struct nft_handle *h)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < nsaddrs; i++) {
- cs->arp.arp.src.s_addr = saddrs[i].s_addr;
- cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
- for (j = 0; j < ndaddrs; j++) {
- cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
- cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
- ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
- }
- }
-
- return ret;
-}
-
int nft_init_arp(struct nft_handle *h, const char *pname)
{
arptables_globals.program_name = pname;
@@ -494,536 +99,12 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
arptables_globals.program_version);
exit(1);
}
-
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
init_extensionsa();
-#endif
- if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0)
+ if (nft_init(h, NFPROTO_ARP) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
return 0;
}
-
-int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
- bool restore)
-{
- struct iptables_command_state cs = {
- .jumpto = "",
- .arp.arp = {
- .arhln = 6,
- .arhln_mask = 255,
- .arhrd = htons(ARPHRD_ETHER),
- .arhrd_mask = 65535,
- },
- };
- int invert = 0;
- unsigned int nsaddrs = 0, ndaddrs = 0;
- struct in_addr *saddrs = NULL, *smasks = NULL;
- struct in_addr *daddrs = NULL, *dmasks = NULL;
-
- int c, verbose = 0;
- const char *chain = NULL;
- const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
- const char *policy = NULL, *newname = NULL;
- unsigned int rulenum = 0, options = 0, command = 0;
- const char *pcnt = NULL, *bcnt = NULL;
- int ret = 1;
- struct xtables_target *t;
-
- /* re-set optind to 0 in case do_command gets called
- * a second time */
- optind = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- opterr = 0;
-
- opts = xt_params->orig_opts;
- while ((c = getopt_long(argc, argv,
- "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:",
- opts, NULL)) != -1) {
- switch (c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&command, CMD_APPEND, CMD_NONE,
- invert);
- chain = optarg;
- break;
-
- case 'D':
- add_command(&command, CMD_DELETE, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv)) {
- rulenum = parse_rulenumber(argv[optind++]);
- command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&command, CMD_REPLACE, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&command, CMD_INSERT, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- rulenum = parse_rulenumber(argv[optind++]);
- else rulenum = 1;
- break;
-
- case 'L':
- add_command(&command, CMD_LIST, CMD_ZERO,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'F':
- add_command(&command, CMD_FLUSH, CMD_NONE,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&command, CMD_ZERO, CMD_LIST,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'N':
- if (optarg && *optarg == '-')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `-'\n");
- if (xtables_find_target(optarg, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
- add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
- invert);
- chain = optarg;
- break;
-
- case 'X':
- add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
- invert);
- if (optarg) chain = optarg;
- else if (xs_has_arg(argc, argv))
- chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&command, CMD_SET_POLICY, CMD_NONE,
- invert);
- chain = optarg;
- if (xs_has_arg(argc, argv))
- policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
-
- printhelp();
- command = CMD_NONE;
- break;
- case 's':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_SOURCE, &cs.arp.arp.invflags,
- invert);
- shostnetworkmask = argv[optind-1];
- break;
-
- case 'd':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_DESTINATION, &cs.arp.arp.invflags,
- invert);
- dhostnetworkmask = argv[optind-1];
- break;
-
- case 2:/* src-mac */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags,
- invert);
- if (getmac_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");
- break;
-
- case 3:/* dst-mac */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags,
- invert);
-
- if (getmac_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");
- break;
-
- case 'l':/* hardware length */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_H_LENGTH, &cs.arp.arp.invflags,
- invert);
- getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln,
- &cs.arp.arp.arhln_mask);
-
- if (cs.arp.arp.arhln != 6) {
- xtables_error(PARAMETER_PROBLEM,
- "Only harware address length of"
- " 6 is supported currently.");
- }
-
- break;
-
- case 8: /* was never supported, not even in arptables-legacy */
- xtables_error(PARAMETER_PROBLEM, "not supported");
- case 4:/* opcode */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_OPCODE, &cs.arp.arp.invflags,
- invert);
- if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop,
- &cs.arp.arp.arpop_mask, 10)) {
- int i;
-
- for (i = 0; i < NUMOPCODES; i++)
- if (!strcasecmp(arp_opcodes[i], optarg))
- break;
- if (i == NUMOPCODES)
- xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
- cs.arp.arp.arpop = htons(i+1);
- }
- break;
-
- case 5:/* h-type */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_H_TYPE, &cs.arp.arp.invflags,
- invert);
- if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd,
- &cs.arp.arp.arhrd_mask, 16)) {
- if (strcasecmp(argv[optind-1], "Ethernet"))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
- cs.arp.arp.arhrd = htons(1);
- }
- break;
-
- case 6:/* proto-type */
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_P_TYPE, &cs.arp.arp.invflags,
- invert);
- if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro,
- &cs.arp.arp.arpro_mask, 0)) {
- if (strcasecmp(argv[optind-1], "ipv4"))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
- cs.arp.arp.arpro = htons(0x800);
- }
- break;
-
- case 'j':
- set_option(&options, OPT_JUMP, &cs.arp.arp.invflags,
- invert);
- command_jump(&cs, optarg);
- break;
-
- case 'i':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
- invert);
- xtables_parse_interface(argv[optind-1],
- cs.arp.arp.iniface,
- cs.arp.arp.iniface_mask);
- break;
-
- case 'o':
- check_inverse(optarg, &invert, &optind, argc);
- set_option(&options, OPT_VIANAMEOUT, &cs.arp.arp.invflags,
- invert);
- xtables_parse_interface(argv[optind-1],
- cs.arp.arp.outiface,
- cs.arp.arp.outiface_mask);
- break;
-
- case 'v':
- if (!verbose)
- set_option(&options, OPT_VERBOSE,
- &cs.arp.arp.invflags, invert);
- verbose++;
- break;
-
- case 'm': /* ignored by arptables-legacy */
- break;
- case 'n':
- set_option(&options, OPT_NUMERIC, &cs.arp.arp.invflags,
- invert);
- break;
-
- case 't':
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- /* ignore this option.
- * arptables-legacy parses it, but libarptc doesn't use it.
- * arptables only has a 'filter' table anyway.
- */
- break;
-
- case 'V':
- if (invert)
- printf("Not %s ;-)\n", arptables_globals.program_version);
- else
- printf("%s v%s (nf_tables)\n",
- arptables_globals.program_name,
- arptables_globals.program_version);
- exit(0);
-
- case '0':
- set_option(&options, OPT_LINENUMBERS, &cs.arp.arp.invflags,
- invert);
- break;
-
- case 'M':
- //modprobe = optarg;
- break;
-
- case 'c':
-
- set_option(&options, OPT_COUNTERS, &cs.arp.arp.invflags,
- invert);
- pcnt = optarg;
- if (xs_has_arg(argc, argv))
- bcnt = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(pcnt, "%llu", &cs.arp.counters.pcnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(bcnt, "%llu", &cs.arp.counters.bcnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
-
- break;
-
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- invert = true;
- optarg[0] = '\0';
- continue;
- }
- printf("Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (cs.target) {
- xtables_option_tpcall(c, argv,
- invert, cs.target, &cs.arp);
- }
- break;
- }
- invert = false;
- }
-
- if (cs.target)
- xtables_option_tfcall(cs.target);
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
- if (!(options & OPT_DESTINATION))
- dhostnetworkmask = "0.0.0.0/0";
- if (!(options & OPT_SOURCE))
- shostnetworkmask = "0.0.0.0/0";
- }
-
- if (shostnetworkmask)
- xtables_ipparse_multiple(shostnetworkmask, &saddrs,
- &smasks, &nsaddrs);
-
- if (dhostnetworkmask)
- xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
- &dmasks, &ndaddrs);
-
- if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
- xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
- " source or destination IP addresses");
-
- if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %i chars)",
- chain, ARPT_FUNCTION_MAXNAMELEN);
-
- if (command == CMD_APPEND
- || command == CMD_DELETE
- || command == CMD_INSERT
- || command == CMD_REPLACE) {
- if (strcmp(chain, "PREROUTING") == 0
- || strcmp(chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- chain);
- }
-
- if (strcmp(chain, "POSTROUTING") == 0
- || strcmp(chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- chain);
- }
- }
-
- switch (command) {
- case CMD_APPEND:
- ret = append_entry(h, chain, *table, &cs, 0,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- options&OPT_VERBOSE, true);
- break;
- case CMD_DELETE:
- ret = delete_entry(chain, *table, &cs,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- options&OPT_VERBOSE, h);
- break;
- case CMD_DELETE_NUM:
- ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
- break;
- case CMD_REPLACE:
- ret = replace_entry(chain, *table, &cs, rulenum - 1,
- saddrs, smasks, daddrs, dmasks,
- options&OPT_VERBOSE, h);
- break;
- case CMD_INSERT:
- ret = append_entry(h, chain, *table, &cs, rulenum - 1,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- options&OPT_VERBOSE, false);
- break;
- case CMD_LIST:
- ret = list_entries(h, chain, *table,
- rulenum,
- options&OPT_VERBOSE,
- options&OPT_NUMERIC,
- /*options&OPT_EXPANDED*/0,
- options&OPT_LINENUMBERS);
- break;
- case CMD_FLUSH:
- ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE);
- break;
- case CMD_ZERO:
- ret = nft_cmd_chain_zero_counters(h, chain, *table,
- options & OPT_VERBOSE);
- break;
- case CMD_LIST|CMD_ZERO:
- ret = list_entries(h, chain, *table, rulenum,
- options&OPT_VERBOSE,
- options&OPT_NUMERIC,
- /*options&OPT_EXPANDED*/0,
- options&OPT_LINENUMBERS);
- if (ret)
- ret = nft_cmd_chain_zero_counters(h, chain, *table,
- options & OPT_VERBOSE);
- break;
- case CMD_NEW_CHAIN:
- ret = nft_cmd_chain_user_add(h, chain, *table);
- break;
- case CMD_DELETE_CHAIN:
- ret = nft_cmd_chain_user_del(h, chain, *table,
- options & OPT_VERBOSE);
- break;
- case CMD_RENAME_CHAIN:
- ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
- break;
- case CMD_SET_POLICY:
- ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
- if (ret < 0)
- xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
- policy);
- break;
- case CMD_NONE:
- break;
- default:
- /* We should never reach this... */
- exit_tryhelp(2);
- }
-
- free(saddrs);
- free(smasks);
- free(daddrs);
- free(dmasks);
-
- nft_clear_iptables_command_state(&cs);
- xtables_free_opts(1);
-
-/* if (verbose > 1)
- dump_entries(*handle);*/
-
- return ret;
-}
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
index 96b2730f..fbeff74f 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -21,94 +21,10 @@
#include "nft-bridge.h"
#include "nft.h"
#include "nft-shared.h"
-/*
- * From include/ebtables_u.h
- */
-#define EXEC_STYLE_PRG 0
-#define EXEC_STYLE_DAEMON 1
-#define ebt_check_option2(flags, mask) EBT_CHECK_OPTION(flags, mask)
-
-extern int ebt_invert;
-
-static int ebt_check_inverse2(const char option[], int argc, char **argv)
-{
- if (!option)
- return ebt_invert;
- if (strcmp(option, "!") == 0) {
- if (ebt_invert == 1)
- xtables_error(PARAMETER_PROBLEM,
- "Double use of '!' not allowed");
- if (optind >= argc)
- optarg = NULL;
- else
- optarg = argv[optind];
- optind++;
- ebt_invert = 1;
- return 1;
- }
- return ebt_invert;
-}
-
-/*
- * Glue code to use libxtables
- */
-static int parse_rule_number(const char *rule)
-{
- unsigned int rule_nr;
-
- if (!xtables_strtoui(rule, NULL, &rule_nr, 1, INT_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid rule number `%s'", rule);
-
- return rule_nr;
-}
-
-static int get_current_chain(const char *chain)
-{
- if (strcmp(chain, "PREROUTING") == 0)
- return NF_BR_PRE_ROUTING;
- else if (strcmp(chain, "INPUT") == 0)
- return NF_BR_LOCAL_IN;
- else if (strcmp(chain, "FORWARD") == 0)
- return NF_BR_FORWARD;
- else if (strcmp(chain, "OUTPUT") == 0)
- return NF_BR_LOCAL_OUT;
- else if (strcmp(chain, "POSTROUTING") == 0)
- return NF_BR_POST_ROUTING;
-
- return -1;
-}
-
-/*
- * The original ebtables parser
- */
-
-/* Checks whether a command has already been specified */
-#define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO)
-
-#define OPT_COMMAND 0x01
-#define OPT_TABLE 0x02
-#define OPT_IN 0x04
-#define OPT_OUT 0x08
-#define OPT_JUMP 0x10
-#define OPT_PROTOCOL 0x20
-#define OPT_SOURCE 0x40
-#define OPT_DEST 0x80
-#define OPT_ZERO 0x100
-#define OPT_LOGICALIN 0x200
-#define OPT_LOGICALOUT 0x400
-#define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */
-
-/* Default command line options. Do not mess around with the already
- * assigned numbers unless you know what you are doing */
-extern struct option ebt_original_options[];
-extern struct xtables_globals ebtables_globals;
-#define opts ebtables_globals.opts
#define prog_name ebtables_globals.program_name
-#define prog_vers ebtables_globals.program_version
-static void print_help(void)
+static void print_help(struct iptables_command_state *cs)
{
fprintf(stderr, "%s: Translate ebtables command to nft syntax\n"
"no side effects occur, the translated command is written "
@@ -118,46 +34,6 @@ static void print_help(void)
exit(0);
}
-static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
-{
- char *colon = strchr(argv, ':'), *buffer;
-
- if (colon) {
- *colon = '\0';
- if (*(colon + 1) == '\0')
- *rule_nr_end = -1; /* Until the last rule */
- else {
- *rule_nr_end = strtol(colon + 1, &buffer, 10);
- if (*buffer != '\0' || *rule_nr_end == 0)
- return -1;
- }
- }
- if (colon == argv)
- *rule_nr = 1; /* Beginning with the first rule */
- else {
- *rule_nr = strtol(argv, &buffer, 10);
- if (*buffer != '\0' || *rule_nr == 0)
- return -1;
- }
- if (!colon)
- *rule_nr_end = *rule_nr;
- return 0;
-}
-
-static void ebtables_parse_interface(const char *arg, char *vianame)
-{
- unsigned char mask[IFNAMSIZ];
- char *c;
-
- xtables_parse_interface(arg, vianame, mask);
-
- if ((c = strchr(vianame, '+'))) {
- if (*(c + 1) != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Spurious characters after '+' wildcard");
- }
-}
-
static void print_ebt_cmd(int argc, char *argv[])
{
int i;
@@ -169,384 +45,110 @@ static void print_ebt_cmd(int argc, char *argv[])
printf("\n");
}
-static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct nft_xt_cmd_parse *p,
+static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct xt_cmd_parse *p,
const struct iptables_command_state *cs, bool append)
{
struct xt_xlate *xl = xt_xlate_alloc(10240);
+ const char *tick = cs->restore ? "" : "'";
int ret;
- if (append) {
- xt_xlate_add(xl, "add rule bridge %s %s ", p->table, p->chain);
- } else {
- xt_xlate_add(xl, "insert rule bridge %s %s ", p->table, p->chain);
- }
+ xt_xlate_add(xl, "%s%s rule bridge %s %s ", tick,
+ append ? "add" : "insert", p->table, p->chain);
ret = h->ops->xlate(cs, xl);
if (ret)
- printf("%s\n", xt_xlate_get(xl));
+ printf("%s%s\n", xt_xlate_get(xl), tick);
+ else
+ printf("%s ", tick);
xt_xlate_free(xl);
return ret;
}
-/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */
static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char **table)
{
- char *buffer;
- int c, i;
- int rule_nr = 0;
- int rule_nr_end = 0;
- int ret = 0;
- unsigned int flags = 0;
struct iptables_command_state cs = {
.argv = argv,
+ .jumpto = "",
.eb.bitmask = EBT_NOPROTO,
};
- char command = 'h';
- const char *chain = NULL;
- int exec_style = EXEC_STYLE_PRG;
- int selected_chain = -1;
- struct xtables_rule_match *xtrm_i;
- struct ebt_match *match;
- struct nft_xt_cmd_parse p = {
+ struct xt_cmd_parse p = {
.table = *table,
+ .rule_ranges = true,
+ .ops = &h->ops->cmd_parse,
};
+ struct xtables_args args = {
+ .family = h->family,
+ };
+ int ret = 0;
- /* prevent getopt to spoil our error reporting */
- opterr = false;
-
- printf("nft ");
- /* Getopt saves the day */
- while ((c = getopt_long(argc, argv,
- "-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
- cs.c = c;
- cs.invert = ebt_invert;
- switch (c) {
- case 'A': /* Add a rule */
- case 'D': /* Delete a rule */
- case 'P': /* Define policy */
- case 'I': /* Insert a rule */
- case 'N': /* Make a user defined chain */
- case 'E': /* Rename chain */
- case 'X': /* Delete chain */
- /* We allow -N chainname -P policy */
- /* XXX: Not in ebtables-compat */
- if (command == 'N' && c == 'P') {
- command = c;
- optind--; /* No table specified */
- break;
- }
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- command = c;
- chain = optarg;
- selected_chain = get_current_chain(chain);
- p.chain = chain;
- flags |= OPT_COMMAND;
-
- if (c == 'N') {
- printf("add chain bridge %s %s\n", p.table, p.chain);
- ret = 1;
- break;
- } else if (c == 'X') {
- printf("delete chain bridge %s %s\n", p.table, p.chain);
- ret = 1;
- break;
- }
-
- if (c == 'E') {
- break;
- } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
- if (optind != argc - 1)
- xtables_error(PARAMETER_PROBLEM,
- "No extra options allowed with -D start_nr[:end_nr]");
- if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end))
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified rule number(s) '%s'", argv[optind]);
- optind++;
- } else if (c == 'I') {
- if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
- rule_nr = 1;
- else {
- rule_nr = parse_rule_number(argv[optind]);
- optind++;
- }
- p.rulenum = rule_nr;
- } else if (c == 'P') {
- break;
- }
- break;
- case 'L': /* List */
- printf("list table bridge %s\n", p.table);
- ret = 1;
- break;
- case 'F': /* Flush */
- if (p.chain) {
- printf("flush chain bridge %s %s\n", p.table, p.chain);
- } else {
- printf("flush table bridge %s\n", p.table);
- }
- ret = 1;
- break;
- case 'Z': /* Zero counters */
- if (c == 'Z') {
- if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L'))
-print_zero:
- xtables_error(PARAMETER_PROBLEM,
- "Command -Z only allowed together with command -L");
- flags |= OPT_ZERO;
- } else {
- if (flags & OPT_COMMAND)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- command = c;
- flags |= OPT_COMMAND;
- if (flags & OPT_ZERO && c != 'L')
- goto print_zero;
- }
- break;
- case 'V': /* Version */
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- if (exec_style == EXEC_STYLE_DAEMON)
- xtables_error(PARAMETER_PROBLEM,
- "%s %s\n", prog_name, prog_vers);
- printf("%s %s\n", prog_name, prog_vers);
- exit(0);
- case 'h':
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- print_help();
- break;
- case 't': /* Table */
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Please put the -t option first");
- ebt_check_option2(&flags, OPT_TABLE);
- if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
- xtables_error(PARAMETER_PROBLEM,
- "Table name length cannot exceed %d characters",
- EBT_TABLE_MAXNAMELEN - 1);
- *table = optarg;
- p.table = optarg;
- break;
- case 'i': /* Input interface */
- case 2 : /* Logical input interface */
- case 'o': /* Output interface */
- case 3 : /* Logical output interface */
- case 'j': /* Target */
- case 'p': /* Net family protocol */
- case 's': /* Source mac */
- case 'd': /* Destination mac */
- case 'c': /* Set counters */
- if (!OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "No command specified");
- if (command != 'A' && command != 'D' && command != 'I')
- xtables_error(PARAMETER_PROBLEM,
- "Command and option do not match");
- if (c == 'i') {
- ebt_check_option2(&flags, OPT_IN);
- if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IIN;
-
- ebtables_parse_interface(optarg, cs.eb.in);
- break;
- } else if (c == 2) {
- ebt_check_option2(&flags, OPT_LOGICALIN);
- if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_ILOGICALIN;
-
- ebtables_parse_interface(optarg, cs.eb.logical_in);
- break;
- } else if (c == 'o') {
- ebt_check_option2(&flags, OPT_OUT);
- if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IOUT;
-
- ebtables_parse_interface(optarg, cs.eb.out);
- break;
- } else if (c == 3) {
- ebt_check_option2(&flags, OPT_LOGICALOUT);
- if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_ILOGICALOUT;
-
- ebtables_parse_interface(optarg, cs.eb.logical_out);
- break;
- } else if (c == 'j') {
- ebt_check_option2(&flags, OPT_JUMP);
- command_jump(&cs, optarg);
- break;
- } else if (c == 's') {
- ebt_check_option2(&flags, OPT_SOURCE);
- 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))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
- cs.eb.bitmask |= EBT_SOURCEMAC;
- break;
- } else if (c == 'd') {
- ebt_check_option2(&flags, OPT_DEST);
- 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))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
- cs.eb.bitmask |= EBT_DESTMAC;
- break;
- } else if (c == 'c') {
- ebt_check_option2(&flags, OPT_COUNT);
- if (ebt_check_inverse2(optarg, argc, argv))
- xtables_error(PARAMETER_PROBLEM,
- "Unexpected '!' after -c");
- if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-')
- xtables_error(PARAMETER_PROBLEM,
- "Option -c needs 2 arguments");
-
- cs.counters.pcnt = strtoull(optarg, &buffer, 10);
- if (*buffer != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Packet counter '%s' invalid",
- optarg);
- cs.counters.bcnt = strtoull(argv[optind], &buffer, 10);
- if (*buffer != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Packet counter '%s' invalid",
- argv[optind]);
- optind++;
- break;
- }
- ebt_check_option2(&flags, OPT_PROTOCOL);
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IPROTO;
-
- cs.eb.bitmask &= ~((unsigned int)EBT_NOPROTO);
- i = strtol(optarg, &buffer, 16);
- if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified protocol");
- if (*buffer != '\0') {
- struct xt_ethertypeent *ent;
-
- if (!strcasecmp(optarg, "LENGTH")) {
- cs.eb.bitmask |= EBT_802_3;
- break;
- }
- ent = xtables_getethertypebyname(optarg);
- if (!ent)
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing", optarg);
- cs.eb.ethproto = ent->e_ethertype;
- } else
- cs.eb.ethproto = i;
-
- if (cs.eb.ethproto < 0x0600)
- xtables_error(PARAMETER_PROBLEM,
- "Sorry, protocols have values above or equal to 0x0600");
- break;
- case 4 : /* Lc */
- ebt_check_option2(&flags, LIST_C);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lc with -L");
- flags |= LIST_C;
- break;
- case 5 : /* Ln */
- ebt_check_option2(&flags, LIST_N);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Ln with -L");
- if (flags & LIST_X)
- xtables_error(PARAMETER_PROBLEM,
- "--Lx is not compatible with --Ln");
- flags |= LIST_N;
- break;
- case 6 : /* Lx */
- ebt_check_option2(&flags, LIST_X);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lx with -L");
- if (flags & LIST_N)
- xtables_error(PARAMETER_PROBLEM,
- "--Lx is not compatible with --Ln");
- flags |= LIST_X;
- break;
- case 12 : /* Lmac2 */
- ebt_check_option2(&flags, LIST_MAC2);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lmac2 with -L");
- flags |= LIST_MAC2;
- break;
- case 1 :
- if (!strcmp(optarg, "!"))
- ebt_check_inverse2(optarg, argc, argv);
- else
- xtables_error(PARAMETER_PROBLEM,
- "Bad argument : '%s'", optarg);
- /* ebt_ebt_check_inverse2() did optind++ */
- optind--;
- continue;
- default:
- ebt_check_inverse2(optarg, argc, argv);
+ p.ops->print_help = print_help;
- if (ebt_command_default(&cs))
- xtables_error(PARAMETER_PROBLEM,
- "Unknown argument: '%s'",
- argv[optind - 1]);
+ do_parse(argc, argv, &p, &cs, &args);
- if (command != 'A' && command != 'I' &&
- command != 'D')
- xtables_error(PARAMETER_PROBLEM,
- "Extensions only for -A, -I, -D");
- }
- ebt_invert = 0;
- }
+ h->verbose = p.verbose;
/* Do the final checks */
- if (command == 'A' || command == 'I' || command == 'D') {
- for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
- xtables_option_mfcall(xtrm_i->match);
-
- for (match = cs.match_list; match; match = match->next) {
- if (match->ismatch)
- continue;
+ if (!nft_table_builtin_find(h, p.table))
+ xtables_error(VERSION_PROBLEM,
+ "table '%s' does not exist", p.table);
- xtables_option_tfcall(match->u.watcher);
+ printf("nft ");
+ switch (p.command) {
+ case CMD_FLUSH:
+ if (p.chain) {
+ printf("flush chain bridge %s %s\n", p.table, p.chain);
+ } else {
+ printf("flush table bridge %s\n", p.table);
}
-
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
- }
-
- cs.eb.ethproto = htons(cs.eb.ethproto);
-
- if (command == 'P') {
- return 0;
- } else if (command == 'A') {
+ ret = 1;
+ break;
+ case CMD_APPEND:
ret = nft_rule_eb_xlate_add(h, &p, &cs, true);
if (!ret)
print_ebt_cmd(argc, argv);
- } else if (command == 'I') {
+ break;
+ case CMD_INSERT:
ret = nft_rule_eb_xlate_add(h, &p, &cs, false);
if (!ret)
print_ebt_cmd(argc, argv);
+ break;
+ case CMD_LIST:
+ printf("list table bridge %s\n", p.table);
+ ret = 1;
+ break;
+ case CMD_NEW_CHAIN:
+ printf("add chain bridge %s %s\n", p.table, p.chain);
+ ret = 1;
+ break;
+ case CMD_DELETE_CHAIN:
+ printf("delete chain bridge %s %s\n", p.table, p.chain);
+ ret = 1;
+ break;
+ case CMD_INIT_TABLE:
+ printf("flush table bridge %s\n", p.table);
+ ret = 1;
+ break;
+ case CMD_DELETE:
+ case CMD_DELETE_NUM:
+ case CMD_CHECK:
+ case CMD_REPLACE:
+ case CMD_ZERO:
+ case CMD_ZERO_NUM:
+ case CMD_LIST|CMD_ZERO:
+ case CMD_LIST|CMD_ZERO_NUM:
+ case CMD_LIST_RULES:
+ case CMD_LIST_RULES|CMD_ZERO:
+ case CMD_LIST_RULES|CMD_ZERO_NUM:
+ case CMD_NEW_CHAIN|CMD_SET_POLICY:
+ case CMD_SET_POLICY:
+ case CMD_RENAME_CHAIN:
+ case CMD_CHANGE_COUNTERS:
+ break;
+ default:
+ /* We should never reach this... */
+ printf("Unsupported command?\n");
+ exit(1);
}
ebt_cs_clean(&cs);
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 5e4184b8..51c699de 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -42,121 +42,6 @@
#include "nft.h"
#include "nft-bridge.h"
-/*
- * From include/ebtables_u.h
- */
-#define ebt_check_option2(flags, mask) EBT_CHECK_OPTION(flags, mask)
-
-/*
- * From useful_functions.c
- */
-
-/* 0: default
- * 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)
- return ebt_invert;
- if (strcmp(option, "!") == 0) {
- if (ebt_invert == 1)
- xtables_error(PARAMETER_PROBLEM,
- "Double use of '!' not allowed");
- if (optind >= argc)
- optarg = NULL;
- else
- optarg = argv[optind];
- optind++;
- ebt_invert = 1;
- return 1;
- }
- return ebt_invert;
-}
-
-/*
- * Glue code to use libxtables
- */
-static int parse_rule_number(const char *rule)
-{
- unsigned int rule_nr;
-
- if (!xtables_strtoui(rule, NULL, &rule_nr, 1, INT_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid rule number `%s'", rule);
-
- return rule_nr;
-}
-
-static int
-append_entry(struct nft_handle *h,
- const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- int rule_nr,
- bool verbose, bool append)
-{
- int ret = 1;
-
- if (append)
- ret = nft_cmd_rule_append(h, chain, table, cs, NULL, verbose);
- else
- ret = nft_cmd_rule_insert(h, chain, table, cs, rule_nr, verbose);
-
- return ret;
-}
-
static int
delete_entry(struct nft_handle *h,
const char *chain,
@@ -181,48 +66,28 @@ delete_entry(struct nft_handle *h,
return ret;
}
-int ebt_get_current_chain(const char *chain)
+static int
+change_entry_counters(struct nft_handle *h,
+ const char *chain, const char *table,
+ struct iptables_command_state *cs,
+ int rule_nr, int rule_nr_end, uint8_t counter_op,
+ bool verbose)
{
- if (!chain)
- return -1;
-
- if (strcmp(chain, "PREROUTING") == 0)
- return NF_BR_PRE_ROUTING;
- else if (strcmp(chain, "INPUT") == 0)
- return NF_BR_LOCAL_IN;
- else if (strcmp(chain, "FORWARD") == 0)
- return NF_BR_FORWARD;
- else if (strcmp(chain, "OUTPUT") == 0)
- return NF_BR_LOCAL_OUT;
- else if (strcmp(chain, "POSTROUTING") == 0)
- return NF_BR_POST_ROUTING;
-
- /* placeholder for user defined chain */
- return NF_BR_NUMHOOKS;
-}
+ int ret = 1;
-/*
- * The original ebtables parser
- */
+ if (rule_nr == -1)
+ return nft_cmd_rule_change_counters(h, chain, table, cs,
+ rule_nr, counter_op,
+ verbose);
+ do {
+ ret = nft_cmd_rule_change_counters(h, chain, table, cs,
+ rule_nr, counter_op,
+ verbose);
+ rule_nr++;
+ } while (rule_nr < rule_nr_end);
-/* Checks whether a command has already been specified */
-#define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO)
-
-#define OPT_COMMAND 0x01
-#define OPT_TABLE 0x02
-#define OPT_IN 0x04
-#define OPT_OUT 0x08
-#define OPT_JUMP 0x10
-#define OPT_PROTOCOL 0x20
-#define OPT_SOURCE 0x40
-#define OPT_DEST 0x80
-#define OPT_ZERO 0x100
-#define OPT_LOGICALIN 0x200
-#define OPT_LOGICALOUT 0x400
-#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */
-#define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */
-#define OPT_CNT_INCR 0x2000 /* This value is also defined in libebtc.c */
-#define OPT_CNT_DECR 0x4000 /* This value is also defined in libebtc.c */
+ return ret;
+}
/* Default command line options. Do not mess around with the already
* assigned numbers unless you know what you are doing */
@@ -232,20 +97,21 @@ struct option ebt_original_options[] =
{ "insert" , required_argument, 0, 'I' },
{ "delete" , required_argument, 0, 'D' },
{ "list" , optional_argument, 0, 'L' },
- { "Lc" , no_argument , 0, 4 },
- { "Ln" , no_argument , 0, 5 },
- { "Lx" , no_argument , 0, 6 },
+ { "Lc" , no_argument , 0, 17 },
+ { "Ln" , no_argument , 0, 18 },
+ { "Lx" , no_argument , 0, 19 },
{ "Lmac2" , no_argument , 0, 12 },
{ "zero" , optional_argument, 0, 'Z' },
{ "flush" , optional_argument, 0, 'F' },
{ "policy" , required_argument, 0, 'P' },
{ "in-interface" , required_argument, 0, 'i' },
{ "in-if" , required_argument, 0, 'i' },
- { "logical-in" , required_argument, 0, 2 },
- { "logical-out" , required_argument, 0, 3 },
+ { "logical-in" , required_argument, 0, 15 },
+ { "logical-out" , required_argument, 0, 16 },
{ "out-interface" , required_argument, 0, 'o' },
{ "out-if" , required_argument, 0, 'o' },
{ "version" , no_argument , 0, 'V' },
+ { "verbose" , no_argument , 0, 'v' },
{ "help" , no_argument , 0, 'h' },
{ "jump" , required_argument, 0, 'j' },
{ "set-counters" , required_argument, 0, 'c' },
@@ -262,32 +128,22 @@ struct option ebt_original_options[] =
{ "new-chain" , required_argument, 0, 'N' },
{ "rename-chain" , required_argument, 0, 'E' },
{ "delete-chain" , optional_argument, 0, 'X' },
- { "atomic-init" , no_argument , 0, 7 },
- { "atomic-commit" , no_argument , 0, 8 },
- { "atomic-file" , required_argument, 0, 9 },
- { "atomic-save" , no_argument , 0, 10 },
{ "init-table" , no_argument , 0, 11 },
{ "concurrent" , no_argument , 0, 13 },
+ { "check" , required_argument, 0, 14 },
{ 0 }
};
-extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
struct xtables_globals ebtables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (nf_tables)",
.orig_opts = ebt_original_options,
- .exit_err = xtables_exit_error,
.compat_rev = nft_compatible_revision,
};
-#define opts ebtables_globals.opts
#define prog_name ebtables_globals.program_name
#define prog_vers ebtables_globals.program_version
-/*
- * From libebtc.c
- */
-
/* Prints all registered extensions */
static void ebt_list_extensions(const struct xtables_target *t,
const struct xtables_rule_match *m)
@@ -313,41 +169,38 @@ static void ebt_list_extensions(const struct xtables_target *t,
}*/
}
-#define OPTION_OFFSET 256
-static struct option *merge_options(struct option *oldopts,
- const struct option *newopts,
- unsigned int *options_offset)
+void nft_bridge_print_help(struct iptables_command_state *cs)
{
- unsigned int num_old, num_new, i;
- struct option *merge;
-
- if (!newopts || !oldopts || !options_offset)
- return oldopts;
- for (num_old = 0; oldopts[num_old].name; num_old++);
- for (num_new = 0; newopts[num_new].name; num_new++);
-
- ebtables_globals.option_offset += OPTION_OFFSET;
- *options_offset = ebtables_globals.option_offset;
-
- merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
- if (!merge)
- return NULL;
- memcpy(merge, oldopts, num_old * sizeof(struct option));
- for (i = 0; i < num_new; i++) {
- merge[num_old + i] = newopts[i];
- merge[num_old + i].val += *options_offset;
- }
- memset(merge + num_old + num_new, 0, sizeof(struct option));
- /* Only free dynamically allocated stuff */
- if (oldopts != ebt_original_options)
- free(oldopts);
+ const struct xtables_rule_match *m = cs->matches;
+ struct xtables_target *t = cs->target;
- return merge;
-}
+ while (optind < cs->argc) {
+ /*struct ebt_u_match *m;
+ struct ebt_u_watcher *w;*/
+
+ if (!strcasecmp("list_extensions", cs->argv[optind])) {
+ ebt_list_extensions(xtables_targets, cs->matches);
+ exit(0);
+ }
+ /*if ((m = ebt_find_match(cs->argv[optind])))
+ ebt_add_match(new_entry, m);
+ else if ((w = ebt_find_watcher(cs->argv[optind])))
+ ebt_add_watcher(new_entry, w);
+ else {*/
+ if (!(t = xtables_find_target(cs->argv[optind],
+ XTF_TRY_LOAD)))
+ xtables_error(PARAMETER_PROBLEM,
+ "Extension '%s' not found",
+ cs->argv[optind]);
+ if (cs->options & OPT_JUMP)
+ xtables_error(PARAMETER_PROBLEM,
+ "Sorry, you can only see help for one target extension at a time");
+ cs->options |= OPT_JUMP;
+ cs->target = t;
+ //}
+ optind++;
+ }
-static void print_help(const struct xtables_target *t,
- const struct xtables_rule_match *m, const char *table)
-{
printf("%s %s\n", prog_name, prog_vers);
printf(
"Usage:\n"
@@ -371,22 +224,19 @@ static void print_help(const struct xtables_target *t,
"--new-chain -N chain : create a user defined chain\n"
"--rename-chain -E old new : rename a chain\n"
"--delete-chain -X [chain] : delete a user defined chain\n"
-"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
-"--atomic-init : put the initial kernel table into <FILE>\n"
-"--atomic-save : put the current kernel table into <FILE>\n"
-"--atomic-file file : set <FILE> to file\n\n"
"Options:\n"
-"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
-"--src -s [!] address[/mask]: source mac address\n"
-"--dst -d [!] address[/mask]: destination mac address\n"
-"--in-if -i [!] name[+] : network input interface name\n"
-"--out-if -o [!] name[+] : network output interface name\n"
-"--logical-in [!] name[+] : logical bridge input interface name\n"
-"--logical-out [!] name[+] : logical bridge output interface name\n"
+"[!] --proto -p proto : protocol hexadecimal, by name or LENGTH\n"
+"[!] --src -s address[/mask]: source mac address\n"
+"[!] --dst -d address[/mask]: destination mac address\n"
+"[!] --in-if -i name[+] : network input interface name\n"
+"[!] --out-if -o name[+] : network output interface name\n"
+"[!] --logical-in name[+] : logical bridge input interface name\n"
+"[!] --logical-out name[+] : logical bridge output interface name\n"
"--set-counters -c chain\n"
" pcnt bcnt : set the counters of the to be added rule\n"
"--modprobe -M program : try to insert modules using this program\n"
"--concurrent : use a file lock to support concurrent scripts\n"
+"--verbose -v : verbose mode\n"
"--version -V : print package version\n\n"
"Environment variable:\n"
/*ATOMIC_ENV_VARIABLE " : if set <FILE> (see above) will equal its value"*/
@@ -399,9 +249,6 @@ static void print_help(const struct xtables_target *t,
printf("\n");
t->help();
}
-
-// if (table->help)
-// table->help(ebt_hooknames);
}
/* Execute command L */
@@ -430,99 +277,10 @@ static int list_rules(struct nft_handle *h, const char *chain, const char *table
return nft_cmd_rule_list(h, chain, table, rule_nr, format);
}
-static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
-{
- char *colon = strchr(argv, ':'), *buffer;
-
- if (colon) {
- *colon = '\0';
- if (*(colon + 1) == '\0')
- *rule_nr_end = -1; /* Until the last rule */
- else {
- *rule_nr_end = strtol(colon + 1, &buffer, 10);
- if (*buffer != '\0' || *rule_nr_end == 0)
- return -1;
- }
- }
- if (colon == argv)
- *rule_nr = 1; /* Beginning with the first rule */
- else {
- *rule_nr = strtol(argv, &buffer, 10);
- if (*buffer != '\0' || *rule_nr == 0)
- return -1;
- }
- if (!colon)
- *rule_nr_end = *rule_nr;
- return 0;
-}
-
-/* Incrementing or decrementing rules in daemon mode is not supported as the
- * involved code overload is not worth it (too annoying to take the increased
- * counters in the kernel into account). */
-static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, struct iptables_command_state *cs)
-{
- char *buffer;
- int ret = 0;
-
- if (optind + 1 >= argc || argv[optind][0] == '-' || argv[optind + 1][0] == '-')
- xtables_error(PARAMETER_PROBLEM,
- "The command -C needs at least 2 arguments");
- if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind + 2][1] >= '0' && argv[optind + 2][1] <= '9'))) {
- if (optind + 3 != argc)
- xtables_error(PARAMETER_PROBLEM,
- "No extra options allowed with -C start_nr[:end_nr] pcnt bcnt");
- if (parse_rule_range(argv[optind], rule_nr, rule_nr_end))
- xtables_error(PARAMETER_PROBLEM,
- "Something is wrong with the rule number specification '%s'", argv[optind]);
- optind++;
- }
-
- if (argv[optind][0] == '+') {
- ret += 1;
- cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
- } else if (argv[optind][0] == '-') {
- ret += 2;
- cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10);
- } else
- cs->counters.pcnt = strtoull(argv[optind], &buffer, 10);
-
- if (*buffer != '\0')
- goto invalid;
- optind++;
- if (argv[optind][0] == '+') {
- ret += 3;
- cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
- } else if (argv[optind][0] == '-') {
- ret += 6;
- cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10);
- } else
- cs->counters.bcnt = strtoull(argv[optind], &buffer, 10);
-
- if (*buffer != '\0')
- goto invalid;
- optind++;
- return ret;
-invalid:
- xtables_error(PARAMETER_PROBLEM,"Packet counter '%s' invalid", argv[optind]);
-}
-
-static void ebtables_parse_interface(const char *arg, char *vianame)
-{
- unsigned char mask[IFNAMSIZ];
- char *c;
-
- xtables_parse_interface(arg, vianame, mask);
-
- if ((c = strchr(vianame, '+'))) {
- if (*(c + 1) != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Spurious characters after '+' wildcard");
- }
-}
-
/* This code is very similar to iptables/xtables.c:command_match() */
static void ebt_load_match(const char *name)
{
+ struct option *opts = xt_params->opts;
struct xtables_match *m;
size_t size;
@@ -539,19 +297,29 @@ static void ebt_load_match(const char *name)
m->m->u.user.revision = m->revision;
xs_init_match(m);
- opts = merge_options(opts, m->extra_opts, &m->option_offset);
+ if (m->x6_options != NULL)
+ opts = xtables_options_xfrm(xt_params->orig_opts, opts,
+ m->x6_options, &m->option_offset);
+ else if (m->extra_opts != NULL)
+ opts = xtables_merge_options(xt_params->orig_opts, opts,
+ m->extra_opts, &m->option_offset);
+ else
+ return;
+
if (opts == NULL)
xtables_error(OTHER_PROBLEM, "Can't alloc memory");
+ xt_params->opts = opts;
}
-static void __ebt_load_watcher(const char *name, const char *typename)
+static void ebt_load_watcher(const char *name)
{
+ struct option *opts = xt_params->opts;
struct xtables_target *watcher;
size_t size;
watcher = xtables_find_target(name, XTF_TRY_LOAD);
if (!watcher) {
- fprintf(stderr, "Unable to load %s %s\n", name, typename);
+ fprintf(stderr, "Unable to load %s watcher\n", name);
return;
}
@@ -566,25 +334,24 @@ static void __ebt_load_watcher(const char *name, const char *typename)
xs_init_target(watcher);
- opts = merge_options(opts, watcher->extra_opts,
- &watcher->option_offset);
+ if (watcher->x6_options != NULL)
+ opts = xtables_options_xfrm(xt_params->orig_opts, opts,
+ watcher->x6_options,
+ &watcher->option_offset);
+ else if (watcher->extra_opts != NULL)
+ opts = xtables_merge_options(xt_params->orig_opts, opts,
+ watcher->extra_opts,
+ &watcher->option_offset);
+ else
+ return;
+
if (opts == NULL)
xtables_error(OTHER_PROBLEM, "Can't alloc memory");
+ xt_params->opts = opts;
}
-static void ebt_load_watcher(const char *name)
-{
- return __ebt_load_watcher(name, "watcher");
-}
-
-static void ebt_load_target(const char *name)
+static void ebt_load_match_extensions(void)
{
- return __ebt_load_watcher(name, "target");
-}
-
-void ebt_load_match_extensions(void)
-{
- opts = ebt_original_options;
ebt_load_match("802_3");
ebt_load_match("arp");
ebt_load_match("ip");
@@ -598,13 +365,6 @@ void ebt_load_match_extensions(void)
ebt_load_watcher("log");
ebt_load_watcher("nflog");
-
- ebt_load_target("mark");
- ebt_load_target("dnat");
- ebt_load_target("snat");
- ebt_load_target("arpreply");
- ebt_load_target("redirect");
- ebt_load_target("standard");
}
void ebt_add_match(struct xtables_match *m,
@@ -630,10 +390,7 @@ void ebt_add_match(struct xtables_match *m,
m->mflags = 0;
/* glue code for watchers */
- newnode = calloc(1, sizeof(struct ebt_match));
- if (newnode == NULL)
- xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
-
+ newnode = xtables_calloc(1, sizeof(struct ebt_match));
newnode->ismatch = true;
newnode->u.match = newm;
@@ -662,10 +419,7 @@ void ebt_add_watcher(struct xtables_target *watcher,
watcher->tflags = 0;
- newnode = calloc(1, sizeof(struct ebt_match));
- if (newnode == NULL)
- xtables_error(OTHER_PROBLEM, "Unable to alloc memory");
-
+ newnode = xtables_calloc(1, sizeof(struct ebt_match));
newnode->u.watcher = clone;
for (matchp = &cs->match_list; *matchp; matchp = &(*matchp)->next)
@@ -673,56 +427,84 @@ void ebt_add_watcher(struct xtables_target *watcher,
*matchp = newnode;
}
-int ebt_command_default(struct iptables_command_state *cs)
+int ebt_command_default(struct iptables_command_state *cs,
+ struct xtables_globals *unused, bool ebt_invert)
{
struct xtables_target *t = cs->target;
struct xtables_match *m;
struct ebt_match *matchp;
/* Is it a target option? */
- if (t && t->parse) {
- if (t->parse(cs->c - t->option_offset, cs->argv,
- ebt_invert, &t->tflags, NULL, &t->t))
- return 0;
+ if (cs->target != NULL &&
+ (cs->target->parse != NULL || cs->target->x6_parse != NULL) &&
+ cs->c >= cs->target->option_offset &&
+ cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) {
+ xtables_option_tpcall(cs->c, cs->argv, ebt_invert,
+ cs->target, &cs->eb);
+ return 0;
}
/* check previously added matches/watchers to this rule first */
for (matchp = cs->match_list; matchp; matchp = matchp->next) {
if (matchp->ismatch) {
m = matchp->u.match;
- if (m->parse &&
- m->parse(cs->c - m->option_offset, cs->argv,
- ebt_invert, &m->mflags, NULL, &m->m))
- return 0;
+ if (!m->parse && !m->x6_parse)
+ continue;
+ if (cs->c < m->option_offset ||
+ cs->c >= m->option_offset + XT_OPTION_OFFSET_SCALE)
+ continue;
+ xtables_option_mpcall(cs->c, cs->argv, ebt_invert,
+ m, &cs->eb);
+ return 0;
} else {
t = matchp->u.watcher;
- if (t->parse &&
- t->parse(cs->c - t->option_offset, cs->argv,
- ebt_invert, &t->tflags, NULL, &t->t))
- return 0;
+ if (!t->parse && !t->x6_parse)
+ continue;
+ if (cs->c < t->option_offset ||
+ cs->c >= t->option_offset + XT_OPTION_OFFSET_SCALE)
+ continue;
+ xtables_option_tpcall(cs->c, cs->argv, ebt_invert,
+ t, &cs->eb);
+ return 0;
}
}
/* Is it a match_option? */
for (m = xtables_matches; m; m = m->next) {
- if (m->parse &&
- m->parse(cs->c - m->option_offset, cs->argv,
- ebt_invert, &m->mflags, NULL, &m->m)) {
- ebt_add_match(m, cs);
- return 0;
- }
+ if (!m->parse && !m->x6_parse)
+ continue;
+ if (cs->c < m->option_offset ||
+ cs->c >= m->option_offset + XT_OPTION_OFFSET_SCALE)
+ continue;
+ xtables_option_mpcall(cs->c, cs->argv, ebt_invert, m, &cs->eb);
+ ebt_add_match(m, cs);
+ return 0;
}
/* Is it a watcher option? */
for (t = xtables_targets; t; t = t->next) {
- if (t->parse &&
- t->parse(cs->c - t->option_offset, cs->argv,
- ebt_invert, &t->tflags, NULL, &t->t)) {
- ebt_add_watcher(t, cs);
- return 0;
- }
+ if (!(t->ext_flags & XTABLES_EXT_WATCHER))
+ continue;
+
+ if (!t->parse && !t->x6_parse)
+ continue;
+ if (cs->c < t->option_offset ||
+ cs->c >= t->option_offset + XT_OPTION_OFFSET_SCALE)
+ continue;
+ xtables_option_tpcall(cs->c, cs->argv, ebt_invert, t, &cs->eb);
+ ebt_add_watcher(t, cs);
+ return 0;
+ }
+ if (cs->c == ':')
+ xtables_error(PARAMETER_PROBLEM, "option \"%s\" "
+ "requires an argument", cs->argv[optind - 1]);
+ if (cs->c == '?') {
+ char optoptstr[3] = {'-', optopt, '\0'};
+
+ xtables_error(PARAMETER_PROBLEM, "unknown option \"%s\"",
+ optopt ? optoptstr : cs->argv[optind - 1]);
}
- return 1;
+ xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg);
}
int nft_init_eb(struct nft_handle *h, const char *pname)
@@ -734,12 +516,10 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
ebtables_globals.program_version);
exit(1);
}
-
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ init_extensions();
init_extensionsb();
-#endif
- if (nft_init(h, NFPROTO_BRIDGE, xtables_bridge) < 0)
+ if (nft_init(h, NFPROTO_BRIDGE) < 0)
xtables_error(OTHER_PROBLEM,
"Could not initialize nftables layer.");
@@ -764,7 +544,7 @@ void nft_fini_eb(struct nft_handle *h)
free(target->t);
}
- free(opts);
+ free(xt_params->opts);
nft_fini(h);
xtables_fini();
@@ -773,512 +553,133 @@ void nft_fini_eb(struct nft_handle *h)
int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
bool restore)
{
- char *buffer;
- int c, i;
- int chcounter = 0; /* Needed for -C */
- int rule_nr = 0;
- int rule_nr_end = 0;
- int ret = 0;
- unsigned int flags = 0;
- struct xtables_target *t;
struct iptables_command_state cs = {
+ .argc = argc,
.argv = argv,
.jumpto = "",
.eb.bitmask = EBT_NOPROTO,
};
- char command = 'h';
- const char *chain = NULL;
- const char *policy = NULL;
- int selected_chain = -1;
- struct xtables_rule_match *xtrm_i;
- struct ebt_match *match;
- bool table_set = false;
-
- /* prevent getopt to spoil our error reporting */
- optind = 0;
- opterr = false;
-
- /* Getopt saves the day */
- while ((c = getopt_long(argc, argv,
- "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
- cs.c = c;
- cs.invert = ebt_invert;
- switch (c) {
-
- case 'A': /* Add a rule */
- case 'D': /* Delete a rule */
- case 'C': /* Change counters */
- case 'P': /* Define policy */
- case 'I': /* Insert a rule */
- case 'N': /* Make a user defined chain */
- case 'E': /* Rename chain */
- case 'X': /* Delete chain */
- /* We allow -N chainname -P policy */
- if (command == 'N' && c == 'P') {
- command = c;
- optind--; /* No table specified */
- goto handle_P;
- }
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
-
- command = c;
- if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!")))
- xtables_error(PARAMETER_PROBLEM, "No chain name specified");
- chain = optarg;
- selected_chain = ebt_get_current_chain(chain);
- flags |= OPT_COMMAND;
-
- if (c == 'N') {
- ret = nft_cmd_chain_user_add(h, chain, *table);
- break;
- } else if (c == 'X') {
- /* X arg is optional, optarg is NULL */
- if (!chain && optind < argc && argv[optind][0] != '-') {
- chain = argv[optind];
- optind++;
- }
- ret = nft_cmd_chain_user_del(h, chain, *table, 0);
- break;
- }
-
- if (c == 'E') {
- if (optind >= argc)
- xtables_error(PARAMETER_PROBLEM, "No new chain name specified");
- else if (optind < argc - 1)
- xtables_error(PARAMETER_PROBLEM, "No extra options allowed with -E");
- else if (strlen(argv[optind]) >= NFT_CHAIN_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM, "Chain name length can't exceed %d"" characters", NFT_CHAIN_MAXNAMELEN - 1);
- 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)
- xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain);
-
- optind++;
- break;
- } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
- if (optind != argc - 1)
- xtables_error(PARAMETER_PROBLEM,
- "No extra options allowed with -D start_nr[:end_nr]");
- if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end))
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified rule number(s) '%s'", argv[optind]);
- optind++;
- } else if (c == 'C') {
- if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, &cs)) == -1)
- return -1;
- } else if (c == 'I') {
- if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
- rule_nr = 1;
- else {
- rule_nr = parse_rule_number(argv[optind]);
- optind++;
- }
- } else if (c == 'P') {
-handle_P:
- if (optind >= argc)
- xtables_error(PARAMETER_PROBLEM,
- "No policy specified");
- for (i = 0; i < NUM_STANDARD_TARGETS; i++)
- if (!strcmp(argv[optind], nft_ebt_standard_target(i))) {
- policy = argv[optind];
- if (-i-1 == EBT_CONTINUE)
- xtables_error(PARAMETER_PROBLEM,
- "Wrong policy '%s'",
- argv[optind]);
- break;
- }
- if (i == NUM_STANDARD_TARGETS)
- xtables_error(PARAMETER_PROBLEM,
- "Unknown policy '%s'", argv[optind]);
- optind++;
- }
- break;
- case 'L': /* List */
- case 'F': /* Flush */
- case 'Z': /* Zero counters */
- if (c == 'Z') {
- if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L'))
-print_zero:
- xtables_error(PARAMETER_PROBLEM,
- "Command -Z only allowed together with command -L");
- flags |= OPT_ZERO;
- } else {
- if (flags & OPT_COMMAND)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- command = c;
- flags |= OPT_COMMAND;
- if (flags & OPT_ZERO && c != 'L')
- goto print_zero;
- }
-
- if (optind < argc && argv[optind][0] != '-') {
- chain = argv[optind];
- optind++;
- }
- break;
- case 'V': /* Version */
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- printf("%s %s (nf_tables)\n", prog_name, prog_vers);
- exit(0);
- case 'h': /* Help */
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- command = 'h';
-
- /* All other arguments should be extension names */
- while (optind < argc) {
- /*struct ebt_u_match *m;
- struct ebt_u_watcher *w;*/
-
- if (!strcasecmp("list_extensions", argv[optind])) {
- ebt_list_extensions(xtables_targets, cs.matches);
- exit(0);
- }
- /*if ((m = ebt_find_match(argv[optind])))
- ebt_add_match(new_entry, m);
- else if ((w = ebt_find_watcher(argv[optind])))
- ebt_add_watcher(new_entry, w);
- else {*/
- if (!(t = xtables_find_target(argv[optind], XTF_TRY_LOAD)))
- xtables_error(PARAMETER_PROBLEM,"Extension '%s' not found", argv[optind]);
- if (flags & OPT_JUMP)
- xtables_error(PARAMETER_PROBLEM,"Sorry, you can only see help for one target extension at a time");
- flags |= OPT_JUMP;
- cs.target = t;
- //}
- optind++;
- }
- break;
- case 't': /* Table */
- ebt_check_option2(&flags, OPT_TABLE);
- if (restore && table_set)
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
- xtables_error(PARAMETER_PROBLEM,
- "Table name length cannot exceed %d characters",
- EBT_TABLE_MAXNAMELEN - 1);
- *table = optarg;
- table_set = true;
- break;
- case 'i': /* Input interface */
- case 2 : /* Logical input interface */
- case 'o': /* Output interface */
- case 3 : /* Logical output interface */
- case 'j': /* Target */
- case 'p': /* Net family protocol */
- case 's': /* Source mac */
- case 'd': /* Destination mac */
- case 'c': /* Set counters */
- if (!OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "No command specified");
- if (command != 'A' && command != 'D' && command != 'I' && command != 'C')
- xtables_error(PARAMETER_PROBLEM,
- "Command and option do not match");
- if (c == 'i') {
- ebt_check_option2(&flags, OPT_IN);
- if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IIN;
-
- ebtables_parse_interface(optarg, cs.eb.in);
- break;
- } else if (c == 2) {
- ebt_check_option2(&flags, OPT_LOGICALIN);
- if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_ILOGICALIN;
-
- ebtables_parse_interface(optarg, cs.eb.logical_in);
- break;
- } else if (c == 'o') {
- ebt_check_option2(&flags, OPT_OUT);
- if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IOUT;
-
- ebtables_parse_interface(optarg, cs.eb.out);
- break;
- } else if (c == 3) {
- ebt_check_option2(&flags, OPT_LOGICALOUT);
- if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_ILOGICALOUT;
-
- ebtables_parse_interface(optarg, cs.eb.logical_out);
- break;
- } else if (c == 'j') {
- ebt_check_option2(&flags, OPT_JUMP);
- if (strcmp(optarg, "CONTINUE") != 0) {
- command_jump(&cs, optarg);
- }
- break;
- } else if (c == 's') {
- ebt_check_option2(&flags, OPT_SOURCE);
- 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))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
- cs.eb.bitmask |= EBT_SOURCEMAC;
- break;
- } else if (c == 'd') {
- ebt_check_option2(&flags, OPT_DEST);
- 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))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
- cs.eb.bitmask |= EBT_DESTMAC;
- break;
- } else if (c == 'c') {
- ebt_check_option2(&flags, OPT_COUNT);
- if (ebt_check_inverse2(optarg, argc, argv))
- xtables_error(PARAMETER_PROBLEM,
- "Unexpected '!' after -c");
- if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-')
- xtables_error(PARAMETER_PROBLEM,
- "Option -c needs 2 arguments");
-
- cs.counters.pcnt = strtoull(optarg, &buffer, 10);
- if (*buffer != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Packet counter '%s' invalid",
- optarg);
- cs.counters.bcnt = strtoull(argv[optind], &buffer, 10);
- if (*buffer != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Packet counter '%s' invalid",
- argv[optind]);
- optind++;
- break;
- }
- ebt_check_option2(&flags, OPT_PROTOCOL);
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IPROTO;
-
- cs.eb.bitmask &= ~((unsigned int)EBT_NOPROTO);
- i = strtol(optarg, &buffer, 16);
- if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified protocol");
- if (*buffer != '\0') {
- struct xt_ethertypeent *ent;
-
- if (!strcasecmp(optarg, "LENGTH")) {
- cs.eb.bitmask |= EBT_802_3;
- break;
- }
- ent = xtables_getethertypebyname(optarg);
- if (!ent)
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing", optarg);
- cs.eb.ethproto = ent->e_ethertype;
- } else
- cs.eb.ethproto = i;
-
- if (cs.eb.ethproto < 0x0600)
- xtables_error(PARAMETER_PROBLEM,
- "Sorry, protocols have values above or equal to 0x0600");
- break;
- case 4 : /* Lc */
- ebt_check_option2(&flags, LIST_C);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lc with -L");
- flags |= LIST_C;
- break;
- case 5 : /* Ln */
- ebt_check_option2(&flags, LIST_N);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Ln with -L");
- if (flags & LIST_X)
- xtables_error(PARAMETER_PROBLEM,
- "--Lx is not compatible with --Ln");
- flags |= LIST_N;
- break;
- case 6 : /* Lx */
- ebt_check_option2(&flags, LIST_X);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lx with -L");
- if (flags & LIST_N)
- xtables_error(PARAMETER_PROBLEM,
- "--Lx is not compatible with --Ln");
- flags |= LIST_X;
- break;
- case 12 : /* Lmac2 */
- ebt_check_option2(&flags, LIST_MAC2);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lmac2 with -L");
- flags |= LIST_MAC2;
- break;
- case 8 : /* atomic-commit */
-/*
- replace->command = c;
- if (OPT_COMMANDS)
- ebt_print_error2("Multiple commands are not allowed");
- replace->flags |= OPT_COMMAND;
- if (!replace->filename)
- ebt_print_error2("No atomic file specified");*/
- /* Get the information from the file */
- /*ebt_get_table(replace, 0);*/
- /* We don't want the kernel giving us its counters,
- * they would overwrite the counters extracted from
- * the file */
- /*replace->num_counters = 0;*/
- /* Make sure the table will be written to the kernel */
- /*free(replace->filename);
- replace->filename = NULL;
- break;*/
- /*case 7 :*/ /* atomic-init */
- /*case 10:*/ /* atomic-save */
- case 11: /* init-table */
- nft_cmd_table_flush(h, *table, false);
- return 1;
- /*
- replace->command = c;
- if (OPT_COMMANDS)
- ebt_print_error2("Multiple commands are not allowed");
- if (c != 11 && !replace->filename)
- ebt_print_error2("No atomic file specified");
- replace->flags |= OPT_COMMAND;
- {
- char *tmp = replace->filename;*/
-
- /* Get the kernel table */
- /*replace->filename = NULL;
- ebt_get_kernel_table(replace, c == 10 ? 0 : 1);
- replace->filename = tmp;
- }
- break;
- case 9 :*/ /* atomic */
- /*
- if (OPT_COMMANDS)
- ebt_print_error2("--atomic has to come before the command");*/
- /* A possible memory leak here, but this is not
- * executed in daemon mode */
- /*replace->filename = (char *)malloc(strlen(optarg) + 1);
- strcpy(replace->filename, optarg);
- break; */
- case 13 :
- break;
- case 1 :
- if (!strcmp(optarg, "!"))
- ebt_check_inverse2(optarg, argc, argv);
- else
- xtables_error(PARAMETER_PROBLEM,
- "Bad argument : '%s'", optarg);
- /* ebt_ebt_check_inverse2() did optind++ */
- optind--;
- continue;
- default:
- ebt_check_inverse2(optarg, argc, argv);
-
- if (ebt_command_default(&cs))
- xtables_error(PARAMETER_PROBLEM,
- "Unknown argument: '%s'",
- argv[optind]);
-
- if (command != 'A' && command != 'I' &&
- command != 'D' && command != 'C')
- xtables_error(PARAMETER_PROBLEM,
- "Extensions only for -A, -I, -D and -C");
- }
- ebt_invert = 0;
- }
-
- /* Just in case we didn't catch an error */
- /*if (ebt_errormsg[0] != '\0')
- return -1;
+ const struct builtin_table *t;
+ struct xtables_args args = {
+ .family = h->family,
+ };
+ struct xt_cmd_parse p = {
+ .table = *table,
+ .restore = restore,
+ .line = line,
+ .rule_ranges = true,
+ .ops = &h->ops->cmd_parse,
+ };
+ int ret = 0;
- if (!(table = ebt_find_table(replace->name)))
- ebt_print_error2("Bad table name");*/
+ do_parse(argc, argv, &p, &cs, &args);
- if (command == 'h' && !(flags & OPT_ZERO)) {
- print_help(cs.target, cs.matches, *table);
- ret = 1;
- }
+ h->verbose = p.verbose;
- /* Do the final checks */
- if (command == 'A' || command == 'I' ||
- command == 'D' || command == 'C') {
- for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
- xtables_option_mfcall(xtrm_i->match);
+ t = nft_table_builtin_find(h, p.table);
+ if (!t)
+ xtables_error(VERSION_PROBLEM,
+ "table '%s' does not exist", p.table);
- for (match = cs.match_list; match; match = match->next) {
- if (match->ismatch)
- continue;
-
- xtables_option_tfcall(match->u.watcher);
+ switch (p.command) {
+ case CMD_NEW_CHAIN:
+ case CMD_NEW_CHAIN | CMD_SET_POLICY:
+ ret = nft_cmd_chain_user_add(h, p.chain, p.table);
+ if (!ret || !(p.command & CMD_SET_POLICY))
+ break;
+ /* fall through */
+ case CMD_SET_POLICY:
+ if (!nft_chain_builtin_find(t, p.chain)) {
+ ret = ebt_cmd_user_chain_policy(h, p.table, p.chain,
+ p.policy);
+ break;
}
-
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
- }
- /* So, the extensions can work with the host endian.
- * The kernel does not have to do this of course */
- cs.eb.ethproto = htons(cs.eb.ethproto);
-
- if (command == 'P') {
- if (selected_chain >= NF_BR_NUMHOOKS) {
- ret = ebt_cmd_user_chain_policy(h, *table, chain, policy);
- } else {
- if (strcmp(policy, "RETURN") == 0) {
- xtables_error(PARAMETER_PROBLEM,
- "Policy RETURN only allowed for user defined chains");
- }
- ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
- if (ret < 0)
- xtables_error(PARAMETER_PROBLEM, "Wrong policy");
+ if (strcmp(p.policy, "RETURN") == 0) {
+ xtables_error(PARAMETER_PROBLEM,
+ "Policy RETURN only allowed for user defined chains");
}
- } else if (command == 'L') {
- ret = list_rules(h, chain, *table, rule_nr,
- 0,
- 0,
- /*flags&OPT_EXPANDED*/0,
- flags&LIST_N,
- flags&LIST_C);
+ ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
+ if (ret < 0)
+ xtables_error(PARAMETER_PROBLEM, "Wrong policy");
+ break;
+ case CMD_LIST:
+ case CMD_LIST | CMD_ZERO:
+ case CMD_LIST | CMD_ZERO_NUM:
+ case CMD_LIST_RULES:
+ case CMD_LIST_RULES | CMD_ZERO:
+ case CMD_LIST_RULES | CMD_ZERO_NUM:
+ if (p.command & CMD_LIST)
+ ret = list_rules(h, p.chain, p.table, p.rulenum,
+ cs.options & OPT_VERBOSE,
+ 0,
+ /*cs.options&OPT_EXPANDED*/0,
+ cs.options&OPT_LINENUMBERS,
+ cs.options&OPT_LIST_C);
+ else if (p.command & CMD_LIST_RULES)
+ ret = nft_cmd_rule_list_save(h, p.chain, p.table,
+ p.rulenum - 1,
+ cs.options & OPT_VERBOSE);
+ if (ret && (p.command & CMD_ZERO))
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
+ if (ret && (p.command & CMD_ZERO_NUM))
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
+ p.rulenum - 1);
+ break;
+ case CMD_ZERO:
+ ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
+ break;
+ case CMD_ZERO_NUM:
+ ret = nft_cmd_rule_zero_counters(h, p.chain, p.table,
+ p.rulenum - 1);
+ break;
+ case CMD_FLUSH:
+ ret = nft_cmd_rule_flush(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
+ break;
+ case CMD_APPEND:
+ ret = nft_cmd_rule_append(h, p.chain, p.table, &cs,
+ cs.options & OPT_VERBOSE);
+ break;
+ case CMD_INSERT:
+ ret = nft_cmd_rule_insert(h, p.chain, p.table, &cs,
+ p.rulenum - 1,
+ cs.options & OPT_VERBOSE);
+ break;
+ case CMD_DELETE:
+ case CMD_DELETE_NUM:
+ ret = delete_entry(h, p.chain, p.table, &cs, p.rulenum - 1,
+ p.rulenum_end, cs.options & OPT_VERBOSE);
+ break;
+ case CMD_DELETE_CHAIN:
+ ret = nft_cmd_chain_del(h, p.chain, p.table, 0);
+ break;
+ case CMD_RENAME_CHAIN:
+ ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
+ break;
+ case CMD_INIT_TABLE:
+ ret = nft_cmd_table_flush(h, p.table, false);
+ break;
+ case CMD_CHECK:
+ ret = nft_cmd_rule_check(h, p.chain, p.table,
+ &cs, cs.options & OPT_VERBOSE);
+ break;
+ case CMD_CHANGE_COUNTERS:
+ ret = change_entry_counters(h, p.chain, p.table, &cs,
+ p.rulenum - 1, p.rulenum_end,
+ args.counter_op,
+ cs.options & OPT_VERBOSE);
+ break;
+ case CMD_REPLACE:
+ ret = nft_cmd_rule_replace(h, p.chain, p.table, &cs,
+ p.rulenum - 1,
+ cs.options & OPT_VERBOSE);
+ break;
+ default:
+ /* We should never reach this... */
+ exit_tryhelp(2, line);
}
- if (flags & OPT_ZERO) {
- ret = nft_cmd_chain_zero_counters(h, chain, *table, 0);
- } else if (command == 'F') {
- ret = nft_cmd_rule_flush(h, chain, *table, 0);
- } else if (command == 'A') {
- ret = append_entry(h, chain, *table, &cs, 0, 0, true);
- } else if (command == 'I') {
- ret = append_entry(h, chain, *table, &cs, rule_nr - 1,
- 0, false);
- } else if (command == 'D') {
- ret = delete_entry(h, chain, *table, &cs, rule_nr - 1,
- rule_nr_end, 0);
- } /*else if (replace->command == 'C') {
- ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter);
- if (ebt_errormsg[0] != '\0')
- return -1;
- }*/
ebt_cs_clean(&cs);
return ret;
diff --git a/iptables/xtables-legacy-multi.c b/iptables/xtables-legacy-multi.c
index 3b7905ff..2c719315 100644
--- a/iptables/xtables-legacy-multi.c
+++ b/iptables/xtables-legacy-multi.c
@@ -14,10 +14,6 @@
#include "ip6tables-multi.h"
#endif
-#ifdef ENABLE_NFTABLES
-#include "xtables-multi.h"
-#endif
-
static const struct subcommand multi_subcommands[] = {
#ifdef ENABLE_IPV4
{"iptables", iptables_main},
diff --git a/iptables/xtables-monitor.8.in b/iptables/xtables-monitor.8.in
index b647a79e..ed2c5fb4 100644
--- a/iptables/xtables-monitor.8.in
+++ b/iptables/xtables-monitor.8.in
@@ -43,7 +43,7 @@ Restrict output to IPv6.
.PP
The first line shows a packet entering rule set evaluation.
The protocol number is shown (AF_INET in this case), then a packet
-identifier number that allows to correlate messages coming from rule set evaluation of
+identifier number that allows one to correlate messages coming from rule set evaluation of
this packet. After this, the rule that was matched by the packet is shown.
This is the TRACE rule that turns on tracing events for this packet.
@@ -51,9 +51,9 @@ The second line dumps information about the packet. Incoming interface
and packet headers such as source and destination addresses are shown.
The third line shows that the packet completed traversal of the raw table
-PREROUTING chain, and is returning, followed by use the chain policy to make accept/drop
+PREROUTING chain, and is returning, followed by use of the chain policy to make accept/drop
decision (the example shows accept being applied).
-The fifth line shows that the packet leaves the filter INPUT chain, i.e., no rules in the filter tables
+The fifth line shows that the packet leaves the filter INPUT chain, i.e., no rules in the filter table's
INPUT chain matched the packet.
It then got DROPPED by the policy of the INPUT table, as shown by line six.
The last line shows another packet arriving \-\- the packet id is different.
@@ -81,7 +81,7 @@ by three base hooks INPUT, FORWARD and OUTPUT. The iptables-nftables tools all
chains automatically when needed, so this is expected when a table was not yet initialized or when it is
re-created from scratch by iptables-nftables-restore. Line five shows a new user-defined chain (TCP)
being added, followed by addition a few rules. the last line shows that a new ruleset generation has
-become active, i.e., the rule set changes are now active. This also lists the process id and the programs name.
+become active, i.e., the rule set changes are now active. This also lists the process id and the program name.
.SH LIMITATIONS
.B xtables-monitor
only works with rules added using iptables-nftables, rules added using
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 4008cc00..cf2729d8 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -37,7 +37,6 @@
#include "iptables.h" /* for xtables_globals */
#include "xtables-multi.h"
#include "nft.h"
-#include "nft-arp.h"
struct cb_arg {
uint32_t nfproto;
@@ -106,6 +105,7 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
printf("-0 ");
break;
default:
+ puts("");
goto err_free;
}
@@ -227,12 +227,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_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 +248,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 +273,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 +305,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++)
@@ -339,7 +339,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
inet_ntop(AF_INET, &iph->daddr, addrbuf, sizeof(addrbuf));
printf("DST=%s ", addrbuf);
- printf("LEN=%d TOS=0x%x TTL=%d ID=%d", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id));
+ printf("LEN=%d TOS=0x%x TTL=%d ID=%d ", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id));
if (iph->frag_off & htons(0x8000))
printf("CE ");
if (iph->frag_off & htons(IP_DF))
@@ -362,7 +362,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
printf("OPT (");
for (i = 0; i < optsize; i++)
printf("%02X", op[i]);
- printf(")");
+ printf(") ");
}
break;
}
@@ -436,9 +436,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 +508,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;
}
@@ -612,12 +624,13 @@ int xtables_monitor_main(int argc, char *argv[])
xtables_globals.program_version);
exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
-#endif
+ init_extensions6();
+ init_extensionsa();
+ init_extensionsb();
- if (nft_init(&h, AF_INET, xtables_ipv4)) {
+ if (nft_init(&h, AF_INET)) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h
index 0fedb430..760d3e4f 100644
--- a/iptables/xtables-multi.h
+++ b/iptables/xtables-multi.h
@@ -9,6 +9,7 @@ extern int xtables_ip4_restore_main(int, char **);
extern int xtables_ip6_main(int, char **);
extern int xtables_ip6_save_main(int, char **);
extern int xtables_ip6_restore_main(int, char **);
+extern int xtables_arp_xlate_main(int, char **);
extern int xtables_ip4_xlate_main(int, char **);
extern int xtables_ip6_xlate_main(int, char **);
extern int xtables_eb_xlate_main(int, char **);
@@ -20,8 +21,10 @@ extern int xtables_arp_save_main(int, char **);
extern int xtables_eb_main(int, char **);
extern int xtables_eb_restore_main(int, char **);
extern int xtables_eb_save_main(int, char **);
-extern int xtables_config_main(int, char **);
extern int xtables_monitor_main(int, char **);
+
+extern struct xtables_globals arptables_globals;
+extern struct xtables_globals ebtables_globals;
#endif
#endif /* _XTABLES_MULTI_H */
diff --git a/iptables/xtables-nft-multi.c b/iptables/xtables-nft-multi.c
index e2b7c641..48265d8e 100644
--- a/iptables/xtables-nft-multi.c
+++ b/iptables/xtables-nft-multi.c
@@ -30,6 +30,7 @@ static const struct subcommand multi_subcommands[] = {
{"ip6tables-translate", xtables_ip6_xlate_main},
{"iptables-restore-translate", xtables_ip4_xlate_restore_main},
{"ip6tables-restore-translate", xtables_ip6_xlate_restore_main},
+ {"arptables-translate", xtables_arp_xlate_main},
{"arptables", xtables_arp_main},
{"arptables-nft", xtables_arp_main},
{"arptables-restore", xtables_arp_restore_main},
diff --git a/iptables/xtables-nft.8 b/iptables/xtables-nft.8
index 702bf954..ae54476c 100644
--- a/iptables/xtables-nft.8
+++ b/iptables/xtables-nft.8
@@ -105,15 +105,15 @@ One basic example is creating the skeleton ruleset in nf_tables from the
xtables-nft tools, in a fresh machine:
.nf
- root@machine:~# iptables\-nft \-L
+ root@machine:\(ti# iptables\-nft \-L
[...]
- root@machine:~# ip6tables\-nft \-L
+ root@machine:\(ti# ip6tables\-nft \-L
[...]
- root@machine:~# arptables\-nft \-L
+ root@machine:\(ti# arptables\-nft \-L
[...]
- root@machine:~# ebtables\-nft \-L
+ root@machine:\(ti# ebtables\-nft \-L
[...]
- root@machine:~# nft list ruleset
+ root@machine:\(ti# nft list ruleset
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
@@ -175,12 +175,12 @@ To migrate your complete filter ruleset, in the case of \fBiptables(8)\fP,
you would use:
.nf
- root@machine:~# iptables\-legacy\-save > myruleset # reads from x_tables
- root@machine:~# iptables\-nft\-restore myruleset # writes to nf_tables
+ root@machine:\(ti# iptables\-legacy\-save > myruleset # reads from x_tables
+ root@machine:\(ti# iptables\-nft\-restore myruleset # writes to nf_tables
.fi
or
.nf
- root@machine:~# iptables\-legacy\-save | iptables-translate-restore | less
+ root@machine:\(ti# iptables\-legacy\-save | iptables\-translate\-restore | less
.fi
to see how rules would look like in the nft
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index d2739497..23cd3498 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -115,14 +115,14 @@ static void xtables_restore_parse_line(struct nft_handle *h,
DEBUGP("line %u, table '%s'\n", line, table);
if (!table)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u table name invalid\n",
- xt_params->program_name, line);
+ "%s: line %u table name invalid",
+ xt_params->program_name, line);
state->curtable = nft_table_builtin_find(h, table);
if (!state->curtable)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u table name '%s' invalid\n",
- xt_params->program_name, line, table);
+ "%s: line %u table name '%s' invalid",
+ xt_params->program_name, line, table);
if (p->tablename && (strcmp(p->tablename, table) != 0))
return;
@@ -152,37 +152,33 @@ static void xtables_restore_parse_line(struct nft_handle *h,
DEBUGP("line %u, chain '%s'\n", line, chain);
if (!chain)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u chain name invalid\n",
- xt_params->program_name, line);
+ "%s: line %u chain name invalid",
+ xt_params->program_name, line);
- if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s' (%u chars max)",
- chain, XT_EXTENSION_MAXNAMELEN - 1);
+ xtables_announce_chain(chain);
+ assert_valid_chain_name(chain);
policy = strtok(NULL, " \t\n");
DEBUGP("line %u, policy '%s'\n", line, policy);
if (!policy)
xtables_error(PARAMETER_PROBLEM,
- "%s: line %u policy invalid\n",
- xt_params->program_name, line);
+ "%s: line %u policy invalid",
+ xt_params->program_name, line);
if (nft_chain_builtin_find(state->curtable, chain)) {
- if (counters) {
- char *ctrs;
- ctrs = strtok(NULL, " \t\n");
-
- if (!ctrs || !parse_counters(ctrs, &count))
- xtables_error(PARAMETER_PROBLEM,
- "invalid policy counters for chain '%s'\n",
- chain);
+ char *ctrs = strtok(NULL, " \t\n");
- }
+ if ((!ctrs && counters) ||
+ (ctrs && !parse_counters(ctrs, &count)))
+ xtables_error(PARAMETER_PROBLEM,
+ "invalid policy counters for chain '%s'",
+ chain);
if (cb->chain_set &&
cb->chain_set(h, state->curtable->name,
- chain, policy, &count) < 0) {
+ chain, policy,
+ counters ? &count : NULL) < 0) {
xtables_error(OTHER_PROBLEM,
- "Can't set policy `%s' on `%s' line %u: %s\n",
+ "Can't set policy `%s' on `%s' line %u: %s",
policy, chain, line,
strerror(errno));
}
@@ -191,13 +187,13 @@ static void xtables_restore_parse_line(struct nft_handle *h,
} else if (cb->chain_restore(h, chain, state->curtable->name) < 0 &&
errno != EEXIST) {
xtables_error(PARAMETER_PROBLEM,
- "cannot create chain '%s' (%s)\n",
+ "cannot create chain '%s' (%s)",
chain, strerror(errno));
} else if (h->family == NFPROTO_BRIDGE &&
!ebt_cmd_user_chain_policy(h, state->curtable->name,
chain, policy)) {
xtables_error(OTHER_PROBLEM,
- "Can't set policy `%s' on `%s' line %u: %s\n",
+ "Can't set policy `%s' on `%s' line %u: %s",
policy, chain, line,
strerror(errno));
}
@@ -206,11 +202,15 @@ static void xtables_restore_parse_line(struct nft_handle *h,
char *pcnt = NULL;
char *bcnt = NULL;
char *parsestart = buffer;
+ int i;
add_argv(&state->av_store, xt_params->program_name, 0);
add_argv(&state->av_store, "-t", 0);
add_argv(&state->av_store, state->curtable->name, 0);
+ for (i = 0; !h->noflush && i < verbose; i++)
+ add_argv(&state->av_store, "-v", 0);
+
tokenize_rule_counters(&parsestart, &pcnt, &bcnt, line);
if (counters && pcnt && bcnt) {
add_argv(&state->av_store, "--set-counters", 0);
@@ -247,8 +247,11 @@ static void xtables_restore_parse_line(struct nft_handle *h,
(strcmp(p->tablename, state->curtable->name) != 0))
return;
if (!ret) {
- fprintf(stderr, "%s: line %u failed\n",
- xt_params->program_name, line);
+ fprintf(stderr, "%s: line %u failed",
+ xt_params->program_name, h->error.lineno);
+ if (errno)
+ fprintf(stderr, ": %s.", nft_strerror(errno));
+ fprintf(stderr, "\n");
exit(1);
}
}
@@ -281,7 +284,6 @@ void xtables_restore_parse(struct nft_handle *h,
static int
xtables_restore_main(int family, const char *progname, int argc, char *argv[])
{
- const struct builtin_table *tables;
struct nft_xt_restore_parse p = {
.commit = true,
.cb = &restore_cb,
@@ -310,10 +312,10 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
counters = 1;
break;
case 'v':
- verbose = 1;
+ verbose++;
break;
case 'V':
- printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
+ printf("%s v%s\n", prog_name, prog_vers);
exit(0);
case 't':
p.testing = 1;
@@ -357,27 +359,26 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
p.in = stdin;
}
+ init_extensions();
switch (family) {
case NFPROTO_IPV4:
- case NFPROTO_IPV6: /* fallthough, same table */
- tables = xtables_ipv4;
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
init_extensions4();
-#endif
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
break;
case NFPROTO_ARP:
- tables = xtables_arp;
+ init_extensionsa();
break;
case NFPROTO_BRIDGE:
- tables = xtables_bridge;
+ init_extensionsb();
break;
default:
fprintf(stderr, "Unknown family %d\n", family);
return 1;
}
- if (nft_init(&h, family, tables) < 0) {
+ if (nft_init(&h, family) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -417,6 +418,7 @@ static const struct nft_xt_restore_cb ebt_restore_cb = {
static const struct option ebt_restore_options[] = {
{.name = "noflush", .has_arg = 0, .val = 'n'},
+ {.name = "verbose", .has_arg = 0, .val = 'v'},
{ 0 }
};
@@ -430,15 +432,18 @@ int xtables_eb_restore_main(int argc, char *argv[])
struct nft_handle h;
int c;
- while ((c = getopt_long(argc, argv, "n",
+ while ((c = getopt_long(argc, argv, "nv",
ebt_restore_options, NULL)) != -1) {
switch(c) {
case 'n':
noflush = 1;
break;
+ case 'v':
+ verbose++;
+ break;
default:
fprintf(stderr,
- "Usage: ebtables-restore [ --noflush ]\n");
+ "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n");
exit(1);
break;
}
@@ -455,7 +460,7 @@ int xtables_eb_restore_main(int argc, char *argv[])
static const struct nft_xt_restore_cb arp_restore_cb = {
.commit = nft_commit,
.table_flush = nft_cmd_table_flush,
- .do_command = do_commandarp,
+ .do_command = do_commandx,
.chain_set = nft_cmd_chain_set,
.chain_restore = nft_cmd_chain_restore,
};
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 92b0c911..5a82cac5 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;
@@ -79,12 +78,11 @@ __do_output(struct nft_handle *h, const char *tablename, void *data)
printf("# Table `%s' is incompatible, use 'nft' tool.\n",
tablename);
return 0;
+ } else if (nft_is_table_tainted(h, tablename)) {
+ printf("# Table `%s' contains incompatible base-chains, use 'nft' tool to list them.\n",
+ tablename);
}
- 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 +90,8 @@ __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_cache_sort_chains(h, tablename);
+ nft_chain_foreach(h, tablename, nft_chain_save, h);
nft_rule_save(h, tablename, d->format);
if (d->commit)
printf("COMMIT\n");
@@ -132,7 +131,6 @@ static int
xtables_save_main(int family, int argc, char *argv[],
const char *optstring, const struct option *longopts)
{
- const struct builtin_table *tables;
const char *tablename = NULL;
struct do_output_data d = {
.format = FMT_NOCOUNTS,
@@ -186,7 +184,7 @@ xtables_save_main(int family, int argc, char *argv[],
dump = true;
break;
case 'V':
- printf("%s v%s (nf_tables)\n", prog_name, prog_vers);
+ printf("%s v%s\n", prog_name, prog_vers);
exit(0);
default:
fprintf(stderr,
@@ -201,18 +199,18 @@ xtables_save_main(int family, int argc, char *argv[],
exit(1);
}
+ init_extensions();
switch (family) {
case NFPROTO_IPV4:
- case NFPROTO_IPV6: /* fallthough, same table */
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
init_extensions4();
-#endif
- tables = xtables_ipv4;
+ d.commit = true;
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
d.commit = true;
break;
case NFPROTO_ARP:
- tables = xtables_arp;
+ init_extensionsa();
break;
case NFPROTO_BRIDGE: {
const char *ctr = getenv("EBTABLES_SAVE_COUNTER");
@@ -223,7 +221,7 @@ xtables_save_main(int family, int argc, char *argv[],
d.format &= ~FMT_NOCOUNTS;
d.format |= FMT_C_COUNTS | FMT_EBT_SAVE;
}
- tables = xtables_bridge;
+ init_extensionsb();
break;
}
default:
@@ -231,7 +229,7 @@ xtables_save_main(int family, int argc, char *argv[],
return 1;
}
- if (nft_init(&h, family, tables) < 0) {
+ if (nft_init(&h, family) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -241,6 +239,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-standalone.c b/iptables/xtables-standalone.c
index 7b71db62..117b0c69 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -39,31 +39,53 @@
#include "xtables-multi.h"
#include "nft.h"
+static struct xtables_globals *xtables_globals_lookup(int family)
+{
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ return &xtables_globals;
+ case NFPROTO_ARP:
+ return &arptables_globals;
+ case NFPROTO_BRIDGE:
+ return &ebtables_globals;
+ default:
+ xtables_error(OTHER_PROBLEM, "Unknown family value %d", family);
+ }
+}
+
static int
xtables_main(int family, const char *progname, int argc, char *argv[])
{
- int ret;
char *table = "filter";
struct nft_handle h;
+ int ret;
- xtables_globals.program_name = progname;
- ret = xtables_init_all(&xtables_globals, family);
+ ret = xtables_init_all(xtables_globals_lookup(family), family);
if (ret < 0) {
- fprintf(stderr, "%s/%s Failed to initialize xtables\n",
- xtables_globals.program_name,
- xtables_globals.program_version);
- exit(1);
+ fprintf(stderr, "%s: Failed to initialize xtables\n", progname);
+ exit(1);
}
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
+ xt_params->program_name = progname;
init_extensions();
- init_extensions4();
-#endif
+ switch (family) {
+ case NFPROTO_IPV4:
+ init_extensions4();
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
+ break;
+ case NFPROTO_ARP:
+ init_extensionsa();
+ break;
+ case NFPROTO_BRIDGE:
+ init_extensionsb();
+ break;
+ }
- if (nft_init(&h, family, xtables_ipv4) < 0) {
- fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
- xtables_globals.program_name,
- xtables_globals.program_version,
- strerror(errno));
+ if (nft_init(&h, family) < 0) {
+ fprintf(stderr, "%s: Failed to initialize nft: %s\n",
+ xt_params->program_name, strerror(errno));
exit(EXIT_FAILURE);
}
@@ -95,3 +117,8 @@ int xtables_ip6_main(int argc, char *argv[])
{
return xtables_main(NFPROTO_IPV6, "ip6tables", argc, argv);
}
+
+int xtables_arp_main(int argc, char *argv[])
+{
+ return xtables_main(NFPROTO_ARP, "arptables", argc, argv);
+}
diff --git a/iptables/xtables-translate.8 b/iptables/xtables-translate.8
index 3dc72760..6fbbd617 100644
--- a/iptables/xtables-translate.8
+++ b/iptables/xtables-translate.8
@@ -28,24 +28,34 @@
iptables-translate \(em translation tool to migrate from iptables to nftables
.P
ip6tables-translate \(em translation tool to migrate from ip6tables to nftables
+.P
+ebtables-translate \(em translation tool to migrate from ebtables to nftables
+.P
+arptables-translate \(em translation tool to migrate from arptables to nftables
.SH DESCRIPTION
There is a set of tools to help the system administrator translate a given
-ruleset from \fBiptables(8)\fP and \fBip6tables(8)\fP to \fBnftables(8)\fP.
+ruleset from \fBiptables(8)\fP, \fBip6tables(8)\fP, \fBebtables(8)\fP and
+\fBarptables(8)\fP to \fBnftables(8)\fP.
The available commands are:
.IP \[bu] 2
-iptables-translate
+iptables\-translate
.IP \[bu]
-iptables-restore-translate
+iptables\-restore\-translate
.IP \[bu] 2
-ip6tables-translate
+ip6tables\-translate
.IP \[bu]
-ip6tables-restore-translate
+ip6tables\-restore\-translate
+.IP \[bu] 2
+ebtables\-translate
+.IP \[bu] 2
+arptables\-translate
.SH USAGE
-They take as input the original \fBiptables(8)\fP/\fBip6tables(8)\fP syntax and
-output the native \fBnftables(8)\fP syntax.
+They take as input the original
+\fBiptables(8)\fP/\fBip6tables(8)\fP/\fBebtables(8)\fP/\fBarptables(8)\fP
+syntax and output the native \fBnftables(8)\fP syntax.
The \fBiptables-restore-translate\fP tool reads a ruleset in the syntax
produced by \fBiptables-save(8)\fP. Likewise, the
@@ -63,38 +73,38 @@ Basic operation examples.
Single command translation:
.nf
-root@machine:~# iptables-translate -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
+root@machine:\(ti# iptables\-translate \-A INPUT \-p tcp \-\-dport 22 \-m conntrack \-\-ctstate NEW \-j ACCEPT
nft add rule ip filter INPUT tcp dport 22 ct state new counter accept
-root@machine:~# ip6tables-translate -A FORWARD -i eth0 -o eth3 -p udp -m multiport --dports 111,222 -j ACCEPT
+root@machine:\(ti# ip6tables\-translate \-A FORWARD \-i eth0 \-o eth3 \-p udp \-m multiport \-\-dports 111,222 \-j ACCEPT
nft add rule ip6 filter FORWARD iifname eth0 oifname eth3 meta l4proto udp udp dport { 111,222} counter accept
.fi
Whole ruleset translation:
.nf
-root@machine:~# iptables-save > save.txt
-root@machine:~# cat save.txt
-# Generated by iptables-save v1.6.0 on Sat Dec 24 14:26:40 2016
+root@machine:\(ti# iptables\-save > save.txt
+root@machine:\(ti# cat save.txt
+# Generated by iptables\-save v1.6.0 on Sat Dec 24 14:26:40 2016
*filter
:INPUT ACCEPT [5166:1752111]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [5058:628693]
--A FORWARD -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
+\-A FORWARD \-p tcp \-m tcp \-\-dport 22 \-m conntrack \-\-ctstate NEW \-j ACCEPT
COMMIT
# Completed on Sat Dec 24 14:26:40 2016
-root@machine:~# iptables-restore-translate -f save.txt
-# Translated by iptables-restore-translate v1.6.0 on Sat Dec 24 14:26:59 2016
+root@machine:\(ti# iptables\-restore\-translate \-f save.txt
+# Translated by iptables\-restore\-translate v1.6.0 on Sat Dec 24 14:26:59 2016
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; }
add chain ip filter FORWARD { type filter hook forward priority 0; }
add chain ip filter OUTPUT { type filter hook output priority 0; }
add rule ip filter FORWARD tcp dport 22 ct state new counter accept
-root@machine:~# iptables-restore-translate -f save.txt > ruleset.nft
-root@machine:~# nft -f ruleset.nft
-root@machine:~# nft list ruleset
+root@machine:\(ti# iptables\-restore\-translate \-f save.txt > ruleset.nft
+root@machine:\(ti# nft \-f ruleset.nft
+root@machine:\(ti# nft list ruleset
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
@@ -117,8 +127,7 @@ Some (few) extensions may be not supported (or fully-supported) for whatever
reason (for example, they were considered obsolete, or we didn't have the time
to work on them).
-There are no translations available for \fBebtables(8)\fP and
-\fBarptables(8)\fP.
+There is no translation available for \fBarptables(8)\fP.
To get up-to-date information about this, please head to
\fBhttps://wiki.nftables.org/\fP.
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 575fb320..8ebe523c 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -41,7 +41,9 @@ void xlate_ifname(struct xt_xlate *xl, const char *nftmeta, const char *ifname,
for (i = 0, j = 0; i < ifaclen + 1; i++, j++) {
switch (ifname[i]) {
case '*':
- iface[j++] = '\\';
+ /* asterisk is non-special mid-string */
+ if (i == ifaclen - 1)
+ iface[j++] = '\\';
/* fall through */
default:
iface[j] = ifname[i];
@@ -83,12 +85,10 @@ int xlate_action(const struct iptables_command_state *cs, bool goto_set,
else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
xt_xlate_add(xl, " return");
else if (cs->target->xlate) {
- xt_xlate_add(xl, " ");
struct xt_xlate_tg_params params = {
.ip = (const void *)&cs->fw,
.target = cs->target->t,
.numeric = numeric,
- .escape_quotes = !cs->restore,
};
ret = cs->target->xlate(xl, &params);
}
@@ -115,17 +115,12 @@ int xlate_matches(const struct iptables_command_state *cs, struct xt_xlate *xl)
.ip = (const void *)&cs->fw,
.match = matchp->match->m,
.numeric = numeric,
- .escape_quotes = !cs->restore,
};
if (!matchp->match->xlate)
return 0;
ret = matchp->match->xlate(xl, &params);
-
- if (strcmp(matchp->match->name, "comment") != 0)
- xt_xlate_add(xl, " ");
-
if (!ret)
break;
}
@@ -145,39 +140,55 @@ bool xlate_find_match(const struct iptables_command_state *cs, const char *p_nam
}
const char *family2str[] = {
+ [NFPROTO_ARP] = "arp",
[NFPROTO_IPV4] = "ip",
[NFPROTO_IPV6] = "ip6",
};
static int nft_rule_xlate_add(struct nft_handle *h,
- const struct nft_xt_cmd_parse *p,
+ const struct xt_cmd_parse *p,
const struct iptables_command_state *cs,
bool append)
{
struct xt_xlate *xl = xt_xlate_alloc(10240);
+ const char *tick = cs->restore ? "" : "'";
+ const char *set;
int ret;
- if (append) {
- xt_xlate_add(xl, "add rule %s %s %s ",
- family2str[h->family], p->table, p->chain);
- } else {
- xt_xlate_add(xl, "insert rule %s %s %s ",
- family2str[h->family], p->table, p->chain);
+ xl_xlate_set_family(xl, h->family);
+ ret = h->ops->xlate(cs, xl);
+ if (!ret)
+ goto err_out;
+
+ set = xt_xlate_set_get(xl);
+ if (set[0]) {
+ printf("%sadd set %s %s %s%s\n",
+ tick, family2str[h->family], p->table,
+ xt_xlate_set_get(xl), tick);
+
+ if (!cs->restore && p->command != CMD_NONE)
+ printf("nft ");
}
- ret = h->ops->xlate(cs, xl);
- if (ret)
- printf("%s\n", xt_xlate_get(xl));
+ printf("%s%s rule %s %s %s ",
+ tick,
+ append ? "add" : "insert",
+ family2str[h->family], p->table, p->chain);
+ if (!append && p->rulenum > 1)
+ printf("index %d ", p->rulenum);
+
+ printf("%s%s\n", xt_xlate_rule_get(xl), tick);
+err_out:
xt_xlate_free(xl);
return ret;
}
-static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p,
+static int xlate(struct nft_handle *h, struct xt_cmd_parse *p,
struct iptables_command_state *cs,
struct xtables_args *args, bool append,
int (*cb)(struct nft_handle *h,
- const struct nft_xt_cmd_parse *p,
+ const struct xt_cmd_parse *p,
const struct iptables_command_state *cs,
bool append))
{
@@ -186,6 +197,15 @@ static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p,
for (i = 0; i < args->s.naddrs; i++) {
switch (h->family) {
+ case NFPROTO_ARP:
+ cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+ cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+ for (j = 0; j < args->d.naddrs; j++) {
+ cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+ cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+ ret = cb(h, p, cs, append);
+ }
+ break;
case AF_INET:
cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
@@ -235,17 +255,25 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
char **table, bool restore)
{
int ret = 0;
- struct nft_xt_cmd_parse p = {
+ struct xt_cmd_parse p = {
.table = *table,
.restore = restore,
- .xlate = true,
+ .line = line,
+ .ops = &h->ops->cmd_parse,
+ };
+ struct iptables_command_state cs = {
+ .jumpto = "",
+ .argv = argv,
};
- struct iptables_command_state cs;
+
struct xtables_args args = {
.family = h->family,
};
- do_parse(h, argc, argv, &p, &cs, &args);
+ if (h->ops->init_cs)
+ h->ops->init_cs(&cs);
+
+ do_parse(argc, argv, &p, &cs, &args);
cs.restore = restore;
@@ -319,19 +347,9 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
exit(1);
}
- nft_clear_iptables_command_state(&cs);
-
- if (h->family == AF_INET) {
- free(args.s.addr.v4);
- free(args.s.mask.v4);
- free(args.d.addr.v4);
- free(args.d.mask.v4);
- } else if (h->family == AF_INET6) {
- free(args.s.addr.v6);
- free(args.s.mask.v6);
- free(args.d.addr.v6);
- free(args.d.mask.v6);
- }
+ h->ops->clear_cs(&cs);
+
+ xtables_clear_args(&args);
xtables_free_opts(1);
return ret;
@@ -341,9 +359,10 @@ static void print_usage(const char *name, const char *version)
{
fprintf(stderr, "%s %s "
"(c) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>\n"
- "Usage: %s [-h] [-f]\n"
+ "Usage: %s [-h] [-f <FILE>] [-V]\n"
" [ --help ]\n"
- " [ --file=<FILE> ]\n", name, version, name);
+ " [ --file=<FILE> ]\n"
+ " [ --version ]\n", name, version, name);
exit(1);
}
@@ -451,39 +470,54 @@ static int xtables_xlate_main_common(struct nft_handle *h,
int family,
const char *progname)
{
- const struct builtin_table *tables;
int ret;
xtables_globals.program_name = progname;
xtables_globals.compat_rev = dummy_compat_rev;
- ret = xtables_init_all(&xtables_globals, family);
+
+ switch (family) {
+ case NFPROTO_IPV4:
+ ret = xtables_init_all(&xtables_globals, family);
+ break;
+ case NFPROTO_IPV6:
+ ret = xtables_init_all(&xtables_globals, family);
+ break;
+ case NFPROTO_ARP:
+ arptables_globals.program_name = progname;
+ arptables_globals.compat_rev = dummy_compat_rev;
+ ret = xtables_init_all(&arptables_globals, family);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
if (ret < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
xtables_globals.program_name,
xtables_globals.program_version);
return 1;
}
+ init_extensions();
switch (family) {
case NFPROTO_IPV4:
- case NFPROTO_IPV6: /* fallthrough: same table */
-#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
- init_extensions();
- init_extensions4();
-#endif
- tables = xtables_ipv4;
+ init_extensions4();
+ break;
+ case NFPROTO_IPV6:
+ init_extensions6();
break;
case NFPROTO_ARP:
- tables = xtables_arp;
+ init_extensionsa();
break;
case NFPROTO_BRIDGE:
- tables = xtables_bridge;
+ init_extensionsb();
break;
default:
fprintf(stderr, "Unknown family %d\n", family);
return 1;
}
- if (nft_init(h, family, tables) < 0) {
+ if (nft_init(h, family) < 0) {
fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
xtables_globals.program_name,
xtables_globals.program_version,
@@ -572,6 +606,12 @@ static int xtables_restore_xlate_main(int family, const char *progname,
exit(0);
}
+int xtables_arp_xlate_main(int argc, char *argv[])
+{
+ return xtables_xlate_main(NFPROTO_ARP, "arptables-translate",
+ argc, argv);
+}
+
int xtables_ip4_xlate_main(int argc, char *argv[])
{
return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate",
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 9d2e441e..5d73481c 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -36,6 +36,7 @@
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
+#include <netinet/ether.h>
#include <iptables.h>
#include <xtables.h>
#include <fcntl.h>
@@ -43,11 +44,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'},
@@ -89,224 +85,13 @@ static struct option original_opts[] = {
{NULL},
};
-void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
-
struct xtables_globals xtables_globals = {
.option_offset = 0,
- .program_version = PACKAGE_VERSION,
+ .program_version = PACKAGE_VERSION " (nf_tables)",
.orig_opts = original_opts,
- .exit_err = xtables_exit_error,
.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,
-/* -s */ IPT_INV_SRCIP,
-/* -d */ IPT_INV_DSTIP,
-/* -p */ XT_INV_PROTO,
-/* -j */ 0,
-/* -v */ 0,
-/* -x */ 0,
-/* -i */ IPT_INV_VIA_IN,
-/* -o */ IPT_INV_VIA_OUT,
-/*--line*/ 0,
-/* -c */ 0,
-/* -f */ IPT_INV_FRAG,
-};
-
-#define opts xt_params->opts
-#define prog_name xt_params->program_name
-#define prog_vers xt_params->program_version
-
-static void __attribute__((noreturn))
-exit_tryhelp(int status)
-{
- if (line != -1)
- fprintf(stderr, "Error occurred at line: %d\n", line);
- fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
- prog_name, prog_name);
- xtables_free_opts(1);
- exit(status);
-}
-
-static void
-printhelp(const struct xtables_rule_match *matches)
-{
- printf("%s v%s\n\n"
-"Usage: %s -[ACD] chain rule-specification [options]\n"
-" %s -I chain [rulenum] rule-specification [options]\n"
-" %s -R chain rulenum rule-specification [options]\n"
-" %s -D chain rulenum [options]\n"
-" %s -[LS] [chain [rulenum]] [options]\n"
-" %s -[FZ] [chain] [options]\n"
-" %s -[NX] chain\n"
-" %s -E old-chain-name new-chain-name\n"
-" %s -P chain target [options]\n"
-" %s -h (print this help information)\n\n",
- prog_name, prog_vers, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name,
- prog_name, prog_name, prog_name, prog_name);
-
- printf(
-"Commands:\n"
-"Either long or short options are allowed.\n"
-" --append -A chain Append to chain\n"
-" --check -C chain Check for the existence of a rule\n"
-" --delete -D chain Delete matching rule from chain\n"
-" --delete -D chain rulenum\n"
-" Delete rule rulenum (1 = first) from chain\n"
-" --insert -I chain [rulenum]\n"
-" Insert in chain as rulenum (default 1=first)\n"
-" --replace -R chain rulenum\n"
-" Replace rule rulenum (1 = first) in chain\n"
-" --list -L [chain [rulenum]]\n"
-" List the rules in a chain or all chains\n"
-" --list-rules -S [chain [rulenum]]\n"
-" Print the rules in a chain or all chains\n"
-" --flush -F [chain] Delete all rules in chain or all chains\n"
-" --zero -Z [chain [rulenum]]\n"
-" Zero counters in chain or all chains\n"
-" --new -N chain Create a new user-defined chain\n"
-" --delete-chain\n"
-" -X [chain] Delete a user-defined chain\n"
-" --policy -P chain target\n"
-" Change policy on chain to target\n"
-" --rename-chain\n"
-" -E old-chain new-chain\n"
-" Change chain name, (moving any references)\n"
-
-"Options:\n"
-" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n"
-" --ipv6 -6 Error (line is ignored by iptables-restore)\n"
-"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n"
-"[!] --source -s address[/mask][...]\n"
-" source specification\n"
-"[!] --destination -d address[/mask][...]\n"
-" destination specification\n"
-"[!] --in-interface -i input name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --jump -j target\n"
-" target for rule (may load target extension)\n"
-#ifdef IPT_F_GOTO
-" --goto -g chain\n"
-" jump to chain with no return\n"
-#endif
-" --match -m match\n"
-" extended match (may load extension)\n"
-" --numeric -n numeric output of addresses and ports\n"
-"[!] --out-interface -o output name[+]\n"
-" network interface name ([+] for wildcard)\n"
-" --table -t table table to manipulate (default: `filter')\n"
-" --verbose -v verbose mode\n"
-" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n"
-" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n"
-" default is 1 second\n"
-" --line-numbers print line numbers when listing\n"
-" --exact -x expand numbers (display exact values)\n"
-"[!] --fragment -f match second or further fragments only\n"
-" --modprobe=<command> try to insert modules using this command\n"
-" --set-counters PKTS BYTES set the counter during insert/append\n"
-"[!] --version -V print package version.\n");
-
- print_extension_helps(xtables_targets, matches);
-}
-
-void
-xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
-{
- va_list args;
-
- va_start(args, msg);
- fprintf(stderr, "%s v%s (nf_tables): ", prog_name, prog_vers);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, "\n");
- if (status == PARAMETER_PROBLEM)
- exit_tryhelp(status);
- if (status == VERSION_PROBLEM)
- fprintf(stderr,
- "Perhaps iptables or your kernel needs to be upgraded.\n");
- /* On error paths, make sure that we don't leak memory */
- xtables_free_opts(1);
- 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.
@@ -318,189 +103,6 @@ opt2char(int option)
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
-static void
-set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
- int invert)
-{
- if (*options & option)
- xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed",
- opt2char(option));
- *options |= option;
-
- if (invert) {
- unsigned int i;
- for (i = 0; 1 << i != option; i++);
-
- if (!inverse_for_options[i])
- xtables_error(PARAMETER_PROBLEM,
- "cannot have ! before -%c",
- opt2char(option));
- *invflg |= inverse_for_options[i];
- }
-}
-
-static int
-add_entry(const char *chain,
- const char *table,
- struct iptables_command_state *cs,
- int rulenum, int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose, struct nft_handle *h, bool append)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < s.naddrs; i++) {
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
- for (j = 0; j < d.naddrs; j++) {
- cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
-
- if (append) {
- ret = nft_cmd_rule_append(h, chain, table,
- cs, NULL,
- verbose);
- } else {
- ret = nft_cmd_rule_insert(h, chain, table,
- cs, rulenum,
- verbose);
- }
- }
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src,
- &s.addr.v6[i], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk,
- &s.mask.v6[i], sizeof(struct in6_addr));
- for (j = 0; j < d.naddrs; j++) {
- memcpy(&cs->fw6.ipv6.dst,
- &d.addr.v6[j], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk,
- &d.mask.v6[j], sizeof(struct in6_addr));
- if (append) {
- ret = nft_cmd_rule_append(h, chain, table,
- cs, NULL,
- verbose);
- } else {
- ret = nft_cmd_rule_insert(h, chain, table,
- cs, rulenum,
- verbose);
- }
- }
- }
- }
-
- return ret;
-}
-
-static int
-replace_entry(const char *chain, const char *table,
- struct iptables_command_state *cs,
- unsigned int rulenum,
- int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose, struct nft_handle *h)
-{
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4->s_addr;
- cs->fw.ip.dst.s_addr = d.addr.v4->s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4->s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4->s_addr;
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src, s.addr.v6, sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dst, d.addr.v6, sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk, s.mask.v6, sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk, d.mask.v6, sizeof(struct in6_addr));
- } else
- return 1;
-
- return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
-}
-
-static int
-delete_entry(const char *chain, const char *table,
- struct iptables_command_state *cs,
- int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose,
- struct nft_handle *h)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < s.naddrs; i++) {
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
- for (j = 0; j < d.naddrs; j++) {
- cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_cmd_rule_delete(h, chain,
- table, cs, verbose);
- }
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src,
- &s.addr.v6[i], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk,
- &s.mask.v6[i], sizeof(struct in6_addr));
- for (j = 0; j < d.naddrs; j++) {
- memcpy(&cs->fw6.ipv6.dst,
- &d.addr.v6[j], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk,
- &d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_cmd_rule_delete(h, chain,
- table, cs, verbose);
- }
- }
- }
-
- return ret;
-}
-
-static int
-check_entry(const char *chain, const char *table,
- struct iptables_command_state *cs,
- int family,
- const struct addr_mask s,
- const struct addr_mask d,
- bool verbose, struct nft_handle *h)
-{
- unsigned int i, j;
- int ret = 1;
-
- for (i = 0; i < s.naddrs; i++) {
- if (family == AF_INET) {
- cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
- cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
- for (j = 0; j < d.naddrs; j++) {
- cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
- cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_cmd_rule_check(h, chain,
- table, cs, verbose);
- }
- } else if (family == AF_INET6) {
- memcpy(&cs->fw6.ipv6.src,
- &s.addr.v6[i], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.smsk,
- &s.mask.v6[i], sizeof(struct in6_addr));
- for (j = 0; j < d.naddrs; j++) {
- memcpy(&cs->fw6.ipv6.dst,
- &d.addr.v6[j], sizeof(struct in6_addr));
- memcpy(&cs->fw6.ipv6.dmsk,
- &d.mask.v6[j], sizeof(struct in6_addr));
- ret = nft_cmd_rule_check(h, chain,
- table, cs, verbose);
- }
- }
- }
-
- return ret;
-}
-
static int
list_entries(struct nft_handle *h, const char *chain, const char *table,
int rulenum, int verbose, int numeric, int expanded,
@@ -536,540 +138,61 @@ list_rules(struct nft_handle *h, const char *chain, const char *table,
return nft_cmd_rule_list_save(h, chain, table, rulenum, counters);
}
-void do_parse(struct nft_handle *h, int argc, char *argv[],
- struct nft_xt_cmd_parse *p, struct iptables_command_state *cs,
- struct xtables_args *args)
-{
- struct xtables_match *m;
- struct xtables_rule_match *matchp;
- bool wait_interval_set = false;
- struct timeval wait_interval;
- struct xtables_target *t;
- bool table_set = false;
- int wait = 0;
-
- memset(cs, 0, sizeof(*cs));
- cs->jumpto = "";
- cs->argv = argv;
-
- /* re-set optind to 0 in case do_command4 gets called
- * a second time */
- optind = 0;
-
- /* clear mflags in case do_command4 gets called a second time
- * (we clear the global list of all matches for security)*/
- for (m = xtables_matches; m; m = m->next)
- m->mflags = 0;
-
- for (t = xtables_targets; t; t = t->next) {
- t->tflags = 0;
- t->used = 0;
- }
-
- /* Suppress error messages: we may add new options if we
- demand-load a protocol. */
- opterr = 0;
-
- opts = xt_params->orig_opts;
- while ((cs->c = getopt_long(argc, argv,
- "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
- opts, NULL)) != -1) {
- switch (cs->c) {
- /*
- * Command selection
- */
- case 'A':
- add_command(&p->command, CMD_APPEND, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- break;
-
- case 'C':
- add_command(&p->command, CMD_CHECK, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- break;
-
- case 'D':
- add_command(&p->command, CMD_DELETE, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv)) {
- p->rulenum = parse_rulenumber(argv[optind++]);
- p->command = CMD_DELETE_NUM;
- }
- break;
-
- case 'R':
- add_command(&p->command, CMD_REPLACE, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a rule number",
- cmd2char(CMD_REPLACE));
- break;
-
- case 'I':
- add_command(&p->command, CMD_INSERT, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- else
- p->rulenum = 1;
- break;
-
- case 'L':
- add_command(&p->command, CMD_LIST,
- CMD_ZERO | CMD_ZERO_NUM, cs->invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'S':
- add_command(&p->command, CMD_LIST_RULES,
- CMD_ZERO|CMD_ZERO_NUM, cs->invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- if (xs_has_arg(argc, argv))
- p->rulenum = parse_rulenumber(argv[optind++]);
- break;
-
- case 'F':
- add_command(&p->command, CMD_FLUSH, CMD_NONE,
- cs->invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- break;
-
- case 'Z':
- add_command(&p->command, CMD_ZERO,
- CMD_LIST|CMD_LIST_RULES, cs->invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- if (xs_has_arg(argc, argv)) {
- p->rulenum = parse_rulenumber(argv[optind++]);
- p->command = CMD_ZERO_NUM;
- }
- break;
-
- case 'N':
- if (optarg && (*optarg == '-' || *optarg == '!'))
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *optarg);
- if (xtables_find_target(optarg, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
- add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- break;
-
- case 'X':
- add_command(&p->command, CMD_DELETE_CHAIN, CMD_NONE,
- cs->invert);
- if (optarg)
- p->chain = optarg;
- else if (xs_has_arg(argc, argv))
- p->chain = argv[optind++];
- break;
-
- case 'E':
- add_command(&p->command, CMD_RENAME_CHAIN, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->newname = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires old-chain-name and "
- "new-chain-name",
- cmd2char(CMD_RENAME_CHAIN));
- break;
-
- case 'P':
- add_command(&p->command, CMD_SET_POLICY, CMD_NONE,
- cs->invert);
- p->chain = optarg;
- if (xs_has_arg(argc, argv))
- p->policy = argv[optind++];
- else
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires a chain and a policy",
- cmd2char(CMD_SET_POLICY));
- break;
-
- case 'h':
- if (!optarg)
- optarg = argv[optind];
-
- /* iptables -p icmp -h */
- if (!cs->matches && cs->protocol)
- xtables_find_match(cs->protocol,
- XTF_TRY_LOAD, &cs->matches);
-
- printhelp(cs->matches);
- p->command = CMD_NONE;
- return;
-
- /*
- * Option selection
- */
- case 'p':
- set_option(&cs->options, OPT_PROTOCOL,
- &args->invflags, cs->invert);
-
- /* Canonicalize into lower case */
- for (cs->protocol = optarg; *cs->protocol; cs->protocol++)
- *cs->protocol = tolower(*cs->protocol);
-
- cs->protocol = optarg;
- args->proto = xtables_parse_protocol(cs->protocol);
-
- if (args->proto == 0 &&
- (args->invflags & XT_INV_PROTO))
- xtables_error(PARAMETER_PROBLEM,
- "rule would never match protocol");
-
- /* This needs to happen here to parse extensions */
- h->ops->proto_parse(cs, args);
- break;
-
- case 's':
- set_option(&cs->options, OPT_SOURCE,
- &args->invflags, cs->invert);
- args->shostnetworkmask = optarg;
- break;
-
- case 'd':
- set_option(&cs->options, OPT_DESTINATION,
- &args->invflags, cs->invert);
- args->dhostnetworkmask = optarg;
- break;
-
-#ifdef IPT_F_GOTO
- case 'g':
- set_option(&cs->options, OPT_JUMP, &args->invflags,
- cs->invert);
- args->goto_set = true;
- cs->jumpto = xt_parse_target(optarg);
- break;
-#endif
-
- case 'j':
- set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags,
- cs->invert);
- command_jump(cs, optarg);
- break;
-
-
- case 'i':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs->options, OPT_VIANAMEIN,
- &args->invflags, cs->invert);
- xtables_parse_interface(optarg,
- args->iniface,
- args->iniface_mask);
- break;
-
- case 'o':
- if (*optarg == '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Empty interface is likely to be "
- "undesired");
- set_option(&cs->options, OPT_VIANAMEOUT,
- &args->invflags, cs->invert);
- xtables_parse_interface(optarg,
- args->outiface,
- args->outiface_mask);
- break;
-
- case 'f':
- if (args->family == AF_INET6) {
- xtables_error(PARAMETER_PROBLEM,
- "`-f' is not supported in IPv6, "
- "use -m frag instead");
- }
- set_option(&cs->options, OPT_FRAGMENT, &args->invflags,
- cs->invert);
- args->flags |= IPT_F_FRAG;
- break;
-
- case 'v':
- if (!p->verbose)
- set_option(&cs->options, OPT_VERBOSE,
- &args->invflags, cs->invert);
- p->verbose++;
- break;
-
- case 'm':
- command_match(cs);
- break;
-
- case 'n':
- set_option(&cs->options, OPT_NUMERIC, &args->invflags,
- cs->invert);
- break;
-
- case 't':
- if (cs->invert)
- xtables_error(PARAMETER_PROBLEM,
- "unexpected ! flag before --table");
- if (p->restore && table_set)
- xtables_error(PARAMETER_PROBLEM,
- "The -t option (seen in line %u) cannot be used in %s.\n",
- line, xt_params->program_name);
- if (!nft_table_builtin_find(h, optarg))
- xtables_error(VERSION_PROBLEM,
- "table '%s' does not exist",
- optarg);
- p->table = optarg;
- table_set = true;
- break;
-
- case 'x':
- set_option(&cs->options, OPT_EXPANDED, &args->invflags,
- cs->invert);
- break;
-
- case 'V':
- if (cs->invert)
- printf("Not %s ;-)\n", prog_vers);
- else
- printf("%s v%s (nf_tables)\n",
- prog_name, prog_vers);
- exit(0);
-
- case 'w':
- if (p->restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-w' from "
- "iptables-restore");
- }
-
- wait = parse_wait_time(argc, argv);
- break;
-
- case 'W':
- if (p->restore) {
- xtables_error(PARAMETER_PROBLEM,
- "You cannot use `-W' from "
- "iptables-restore");
- }
-
- parse_wait_interval(argc, argv, &wait_interval);
- wait_interval_set = true;
- break;
-
- case '0':
- set_option(&cs->options, OPT_LINENUMBERS,
- &args->invflags, cs->invert);
- break;
-
- case 'M':
- xtables_modprobe_program = optarg;
- break;
-
- case 'c':
- set_option(&cs->options, OPT_COUNTERS, &args->invflags,
- cs->invert);
- args->pcnt = optarg;
- args->bcnt = strchr(args->pcnt + 1, ',');
- if (args->bcnt)
- args->bcnt++;
- if (!args->bcnt && xs_has_arg(argc, argv))
- args->bcnt = argv[optind++];
- if (!args->bcnt)
- xtables_error(PARAMETER_PROBLEM,
- "-%c requires packet and byte counter",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(args->pcnt, "%llu", &args->pcnt_cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c packet counter not numeric",
- opt2char(OPT_COUNTERS));
-
- if (sscanf(args->bcnt, "%llu", &args->bcnt_cnt) != 1)
- xtables_error(PARAMETER_PROBLEM,
- "-%c byte counter not numeric",
- opt2char(OPT_COUNTERS));
- break;
-
- case '4':
- if (args->family == AF_INET)
- break;
-
- if (p->restore && args->family == AF_INET6)
- return;
-
- exit_tryhelp(2);
-
- case '6':
- if (args->family == AF_INET6)
- break;
-
- if (p->restore && args->family == AF_INET)
- return;
-
- exit_tryhelp(2);
-
- case 1: /* non option */
- if (optarg[0] == '!' && optarg[1] == '\0') {
- if (cs->invert)
- xtables_error(PARAMETER_PROBLEM,
- "multiple consecutive ! not"
- " allowed");
- cs->invert = true;
- optarg[0] = '\0';
- continue;
- }
- fprintf(stderr, "Bad argument `%s'\n", optarg);
- exit_tryhelp(2);
-
- default:
- if (command_default(cs, &xtables_globals) == 1)
- /* cf. ip6tables.c */
- continue;
- break;
- }
- cs->invert = false;
- }
-
- if (strcmp(p->table, "nat") == 0 &&
- ((p->policy != NULL && strcmp(p->policy, "DROP") == 0) ||
- (cs->jumpto != NULL && strcmp(cs->jumpto, "DROP") == 0)))
- xtables_error(PARAMETER_PROBLEM,
- "\nThe \"nat\" table is not intended for filtering, "
- "the use of DROP is therefore inhibited.\n\n");
-
- if (!wait && wait_interval_set)
- xtables_error(PARAMETER_PROBLEM,
- "--wait-interval only makes sense with --wait\n");
-
- for (matchp = cs->matches; matchp; matchp = matchp->next)
- xtables_option_mfcall(matchp->match);
- if (cs->target != NULL)
- xtables_option_tfcall(cs->target);
-
- /* Fix me: must put inverse options checking here --MN */
-
- if (optind < argc)
- xtables_error(PARAMETER_PROBLEM,
- "unknown arguments found on commandline");
- if (!p->command)
- xtables_error(PARAMETER_PROBLEM, "no command specified");
- if (cs->invert)
- xtables_error(PARAMETER_PROBLEM,
- "nothing appropriate following !");
-
- /* Set only if required, needed by xtables-restore */
- if (h->family == AF_UNSPEC)
- h->family = args->family;
-
- h->ops->post_parse(p->command, cs, args);
-
- if (p->command == CMD_REPLACE &&
- (args->s.naddrs != 1 || args->d.naddrs != 1))
- xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
- "specify a unique address");
-
- generic_opt_check(p->command, cs->options);
-
- if (p->chain != NULL && strlen(p->chain) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- p->chain, XT_EXTENSION_MAXNAMELEN);
-
- if (p->command == CMD_APPEND ||
- p->command == CMD_DELETE ||
- p->command == CMD_DELETE_NUM ||
- p->command == CMD_CHECK ||
- p->command == CMD_INSERT ||
- p->command == CMD_REPLACE) {
- if (strcmp(p->chain, "PREROUTING") == 0
- || strcmp(p->chain, "INPUT") == 0) {
- /* -o not valid with incoming packets. */
- if (cs->options & OPT_VIANAMEOUT)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEOUT),
- p->chain);
- }
-
- if (strcmp(p->chain, "POSTROUTING") == 0
- || strcmp(p->chain, "OUTPUT") == 0) {
- /* -i not valid with outgoing packets */
- if (cs->options & OPT_VIANAMEIN)
- xtables_error(PARAMETER_PROBLEM,
- "Can't use -%c with %s\n",
- opt2char(OPT_VIANAMEIN),
- p->chain);
- }
- }
-}
-
int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
bool restore)
{
int ret = 1;
- struct nft_xt_cmd_parse p = {
+ struct xt_cmd_parse p = {
.table = *table,
.restore = restore,
+ .line = line,
+ .ops = &h->ops->cmd_parse,
+ };
+ struct iptables_command_state cs = {
+ .jumpto = "",
+ .argv = argv,
};
- struct iptables_command_state cs;
struct xtables_args args = {
.family = h->family,
};
- do_parse(h, argc, argv, &p, &cs, &args);
+ if (h->ops->init_cs)
+ h->ops->init_cs(&cs);
+
+ do_parse(argc, argv, &p, &cs, &args);
+ h->verbose = p.verbose;
+ if (!nft_table_builtin_find(h, p.table))
+ xtables_error(VERSION_PROBLEM,
+ "table '%s' does not exist",
+ p.table);
switch (p.command) {
case CMD_APPEND:
- ret = add_entry(p.chain, p.table, &cs, 0, h->family,
- args.s, args.d,
- cs.options & OPT_VERBOSE, h, true);
+ ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args,
+ cs.options & OPT_VERBOSE, true,
+ p.rulenum - 1);
break;
case CMD_DELETE:
- ret = delete_entry(p.chain, p.table, &cs, h->family,
- args.s, args.d,
- cs.options & OPT_VERBOSE, h);
+ ret = h->ops->delete_entry(h, p.chain, p.table, &cs, &args,
+ cs.options & OPT_VERBOSE);
break;
case CMD_DELETE_NUM:
ret = nft_cmd_rule_delete_num(h, p.chain, p.table,
p.rulenum - 1, p.verbose);
break;
case CMD_CHECK:
- ret = check_entry(p.chain, p.table, &cs, h->family,
- args.s, args.d,
- cs.options & OPT_VERBOSE, h);
+ ret = h->ops->check_entry(h, p.chain, p.table, &cs, &args,
+ cs.options & OPT_VERBOSE);
break;
case CMD_REPLACE:
- ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1,
- h->family, args.s, args.d,
- cs.options & OPT_VERBOSE, h);
+ ret = h->ops->replace_entry(h, p.chain, p.table, &cs, &args,
+ cs.options & OPT_VERBOSE,
+ p.rulenum - 1);
break;
case CMD_INSERT:
- ret = add_entry(p.chain, p.table, &cs, p.rulenum - 1,
- h->family, args.s, args.d,
- cs.options&OPT_VERBOSE, h, false);
+ ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args,
+ cs.options & OPT_VERBOSE, false,
+ p.rulenum - 1);
break;
case CMD_FLUSH:
ret = nft_cmd_rule_flush(h, p.chain, p.table,
@@ -1120,8 +243,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
ret = nft_cmd_chain_user_add(h, p.chain, p.table);
break;
case CMD_DELETE_CHAIN:
- ret = nft_cmd_chain_user_del(h, p.chain, p.table,
- cs.options & OPT_VERBOSE);
+ ret = nft_cmd_chain_del(h, p.chain, p.table,
+ cs.options & OPT_VERBOSE);
break;
case CMD_RENAME_CHAIN:
ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
@@ -1134,24 +257,14 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
break;
default:
/* We should never reach this... */
- exit_tryhelp(2);
+ exit_tryhelp(2, line);
}
*table = p.table;
- nft_clear_iptables_command_state(&cs);
+ h->ops->clear_cs(&cs);
- if (h->family == AF_INET) {
- free(args.s.addr.v4);
- free(args.s.mask.v4);
- free(args.d.addr.v4);
- free(args.d.mask.v4);
- } else if (h->family == AF_INET6) {
- free(args.s.addr.v6);
- free(args.s.mask.v6);
- free(args.d.addr.v6);
- free(args.d.mask.v6);
- }
+ xtables_clear_args(&args);
xtables_free_opts(1);
return ret;
diff --git a/libipq/Makefile.am b/libipq/Makefile.am
index 9e3a2ca6..68da15fe 100644
--- a/libipq/Makefile.am
+++ b/libipq/Makefile.am
@@ -2,10 +2,11 @@
AM_CFLAGS = ${regular_CFLAGS}
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include
+AM_LDFLAGS = ${regular_LDFLAGS}
libipq_la_SOURCES = libipq.c
lib_LTLIBRARIES = libipq.la
-man_MANS = ipq_create_handle.3 ipq_destroy_handle.3 ipq_errstr.3 \
+dist_man_MANS = ipq_create_handle.3 ipq_destroy_handle.3 ipq_errstr.3 \
ipq_get_msgerr.3 ipq_get_packet.3 ipq_message_type.3 \
ipq_perror.3 ipq_read.3 ipq_set_mode.3 ipq_set_verdict.3 \
libipq.3
diff --git a/libipq/ipq_create_handle.3 b/libipq/ipq_create_handle.3
index 11ef95c4..ebe46daa 100644
--- a/libipq/ipq_create_handle.3
+++ b/libipq/ipq_create_handle.3
@@ -24,7 +24,7 @@ ipq_create_handle, ipq_destroy_handle \(em create and destroy libipq handles.
.br
.B #include <libipq.h>
.sp
-.BI "struct ipq_handle *ipq_create_handle(u_int32_t " flags ", u_int32_t " protocol ");"
+.BI "struct ipq_handle *ipq_create_handle(uint32_t " flags ", uint32_t " protocol ");"
.br
.BI "int ipq_destroy_handle(struct ipq_handle *" h );
.SH DESCRIPTION
diff --git a/libipq/ipq_set_mode.3 b/libipq/ipq_set_mode.3
index 0edd3c00..e206886c 100644
--- a/libipq/ipq_set_mode.3
+++ b/libipq/ipq_set_mode.3
@@ -24,7 +24,7 @@ ipq_set_mode \(em set the ip_queue queuing mode
.br
.B #include <libipq.h>
.sp
-.BI "int ipq_set_mode(const struct ipq_handle *" h ", u_int8_t " mode ", size_t " range );
+.BI "int ipq_set_mode(const struct ipq_handle *" h ", uint8_t " mode ", size_t " range );
.SH DESCRIPTION
The
.B ipq_set_mode
diff --git a/libiptc/Makefile.am b/libiptc/Makefile.am
index 464a0696..d8fe169e 100644
--- a/libiptc/Makefile.am
+++ b/libiptc/Makefile.am
@@ -2,6 +2,7 @@
AM_CFLAGS = ${regular_CFLAGS}
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include ${kinclude_CPPFLAGS}
+AM_LDFLAGS = ${regular_LDFLAGS}
pkgconfig_DATA = libiptc.pc libip4tc.pc libip6tc.pc
@@ -10,3 +11,5 @@ libip4tc_la_SOURCES = libip4tc.c
libip4tc_la_LDFLAGS = -version-info 2:0:0
libip6tc_la_SOURCES = libip6tc.c
libip6tc_la_LDFLAGS = -version-info 2:0:0
+
+EXTRA_DIST = libiptc.c linux_list.h
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index ceeb017b..9712a363 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -606,6 +606,15 @@ static int iptcc_chain_index_delete_chain(struct chain_head *c, struct xtc_handl
if (index_ptr == &c->list) { /* Chain used as index ptr */
+ /* If this is the last chain in the list, its index bucket just
+ * became empty. Adjust the size to avoid a NULL-pointer deref
+ * later.
+ */
+ if (next == &h->chains) {
+ h->chain_index_sz--;
+ return 0;
+ }
+
/* See if its possible to avoid a rebuild, by shifting
* to next pointer. Its possible if the next pointer
* is located in the same index bucket.
@@ -813,7 +822,7 @@ static int __iptcc_p_del_policy(struct xtc_handle *h, unsigned int num)
/* save counter and counter_map information */
h->chain_iterator_cur->counter_map.maptype =
- COUNTER_MAP_ZEROED;
+ COUNTER_MAP_NORMAL_MAP;
h->chain_iterator_cur->counter_map.mappos = num-1;
memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
sizeof(h->chain_iterator_cur->counters));
@@ -1309,16 +1318,10 @@ retry:
return NULL;
}
- sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
+ sockfd = socket(TC_AF, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
if (sockfd < 0)
return NULL;
- if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
- fprintf(stderr, "Could not set close on exec: %s\n",
- strerror(errno));
- abort();
- }
-
s = sizeof(info);
strcpy(info.name, tablename);
@@ -2381,12 +2384,16 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
return 0;
}
+ handle->num_chains--;
+
/* This only unlinks "c" from the list, thus no free(c) */
iptcc_chain_index_delete_chain(c, handle);
/* Change the name of the chain */
strncpy(c->name, newname, sizeof(IPT_CHAINLABEL) - 1);
+ handle->num_chains++;
+
/* Insert sorted into to list again */
iptc_insert_chain(handle, c);
@@ -2545,8 +2552,8 @@ TC_COMMIT(struct xtc_handle *handle)
+ sizeof(STRUCT_COUNTERS) * new_number;
/* These are the old counters we will get from kernel */
- repl->counters = malloc(sizeof(STRUCT_COUNTERS)
- * handle->info.num_entries);
+ repl->counters = calloc(handle->info.num_entries,
+ sizeof(STRUCT_COUNTERS));
if (!repl->counters) {
errno = ENOMEM;
goto out_free_repl;
diff --git a/libiptc/linux_stddef.h b/libiptc/linux_stddef.h
deleted file mode 100644
index 56416f10..00000000
--- a/libiptc/linux_stddef.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _LINUX_STDDEF_H
-#define _LINUX_STDDEF_H
-
-#undef NULL
-#if defined(__cplusplus)
-#define NULL 0
-#else
-#define NULL ((void *)0)
-#endif
-
-#undef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- *
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-/*
- * Check at compile time that something is of a particular type.
- * Always evaluates to 1 so you may use it easily in comparisons.
- */
-#define typecheck(type,x) \
-({ type __dummy; \
- typeof(x) __dummy2; \
- (void)(&__dummy == &__dummy2); \
- 1; \
-})
-
-
-#endif
diff --git a/libxtables/Makefile.am b/libxtables/Makefile.am
index 8ff6b0ca..2f4a12e5 100644
--- a/libxtables/Makefile.am
+++ b/libxtables/Makefile.am
@@ -1,7 +1,8 @@
# -*- Makefile -*-
AM_CFLAGS = ${regular_CFLAGS}
-AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir}/iptables ${kinclude_CPPFLAGS}
+AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_srcdir}/include -I${top_srcdir}/iptables -I${top_srcdir} ${kinclude_CPPFLAGS}
+AM_LDFLAGS = ${regular_LDFLAGS}
lib_LTLIBRARIES = libxtables.la
libxtables_la_SOURCES = xtables.c xtoptions.c getethertype.c
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 7152c657..f2fcc5c2 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <netinet/ether.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/statfs.h>
@@ -48,6 +49,7 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <libiptc/libxtc.h>
+#include <libiptc/linux_list.h>
#ifndef NO_SHARED_LIBS
#include <dlfcn.h>
@@ -62,7 +64,6 @@
#endif
#include <getopt.h>
#include "iptables/internal.h"
-#include "xshared.h"
#define NPROTO 255
@@ -70,6 +71,10 @@
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
#endif
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
/* we need this for ip6?tables-restore. ip6?tables-restore.c sets line to the
* current line of the input file, in order to give a more precise error
* message. ip6?tables itself doesn't need this, so it is initialized to the
@@ -89,15 +94,25 @@ void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, "\n");
+ if (status == PARAMETER_PROBLEM) {
+ if (line != -1)
+ fprintf(stderr, "Error occurred at line: %d\n", line);
+ fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
+ xt_params->program_name, xt_params->program_name);
+ } else if (status == VERSION_PROBLEM) {
+ fprintf(stderr,
+ "Perhaps %s or your kernel needs to be upgraded.\n",
+ xt_params->program_name);
+ }
+ /* On error paths, make sure that we don't leak memory */
+ xtables_free_opts(1);
exit(status);
}
void xtables_free_opts(int unused)
{
- if (xt_params->opts != xt_params->orig_opts) {
- free(xt_params->opts);
- xt_params->opts = NULL;
- }
+ free(xt_params->opts);
+ xt_params->opts = NULL;
}
struct option *xtables_merge_options(struct option *orig_opts,
@@ -242,8 +257,83 @@ static void dlreg_free(void)
}
#endif
+struct notarget {
+ struct hlist_node node;
+ char name[];
+};
+
+#define NOTARGET_HSIZE 512
+static struct hlist_head notargets[NOTARGET_HSIZE];
+
+static void notargets_hlist_init(void)
+{
+ int i;
+
+ for (i = 0; i < NOTARGET_HSIZE; i++)
+ INIT_HLIST_HEAD(&notargets[i]);
+}
+
+static void notargets_hlist_free(void)
+{
+ struct hlist_node *pos, *n;
+ struct notarget *cur;
+ int i;
+
+ for (i = 0; i < NOTARGET_HSIZE; i++) {
+ hlist_for_each_entry_safe(cur, pos, n, &notargets[i], node) {
+ hlist_del(&cur->node);
+ free(cur);
+ }
+ }
+}
+
+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 notarget *notargets_hlist_lookup(const char *name)
+{
+ uint32_t key = djb_hash(name) % NOTARGET_HSIZE;
+ struct hlist_node *node;
+ struct notarget *cur;
+
+ hlist_for_each_entry(cur, node, &notargets[key], node) {
+ if (!strcmp(name, cur->name))
+ return cur;
+ }
+ return NULL;
+}
+
+static void notargets_hlist_insert(const char *name)
+{
+ struct notarget *cur;
+
+ if (!name)
+ return;
+
+ cur = xtables_malloc(sizeof(*cur) + strlen(name) + 1);
+ strcpy(cur->name, name);
+ hlist_add_head(&cur->node, &notargets[djb_hash(name) % NOTARGET_HSIZE]);
+}
+
+void xtables_announce_chain(const char *name)
+{
+ if (!notargets_hlist_lookup(name))
+ notargets_hlist_insert(name);
+}
+
void xtables_init(void)
{
+ /* xtables cannot be used with setuid in a safe way. */
+ if (getuid() != geteuid())
+ _exit(111);
+
xtables_libdir = getenv("XTABLES_LIBDIR");
if (xtables_libdir != NULL)
return;
@@ -267,6 +357,8 @@ void xtables_init(void)
return;
}
xtables_libdir = XTABLES_LIBDIR;
+
+ notargets_hlist_init();
}
void xtables_fini(void)
@@ -274,6 +366,7 @@ void xtables_fini(void)
#ifndef NO_SHARED_LIBS
dlreg_free();
#endif
+ notargets_hlist_free();
}
void xtables_set_nfproto(uint8_t nfproto)
@@ -368,20 +461,27 @@ void *xtables_realloc(void *ptr, size_t size)
return p;
}
+char *xtables_strdup(const char *s)
+{
+ char *dup = strdup(s);
+
+ if (!dup) {
+ perror("ip[6]tables: strdup failed");
+ exit(1);
+ }
+
+ return dup;
+}
+
static char *get_modprobe(void)
{
int procfile;
char *ret;
int count;
- procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
+ procfile = open(PROC_SYS_MODPROBE, O_RDONLY | O_CLOEXEC);
if (procfile < 0)
return NULL;
- if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
- fprintf(stderr, "Could not set close on exec: %s\n",
- strerror(errno));
- exit(1);
- }
ret = malloc(PATH_MAX);
if (ret) {
@@ -478,23 +578,23 @@ int xtables_load_ko(const char *modprobe, bool quiet)
}
/**
- * xtables_strtou{i,l} - string to number conversion
+ * xtables_strtoul_base - string to number conversion
* @s: input string
* @end: like strtoul's "end" pointer
* @value: pointer for result
* @min: minimum accepted value
* @max: maximum accepted value
+ * @base: assumed base of value
*
* If @end is NULL, we assume the caller wants a "strict strtoul", and hence
* "15a" is rejected.
* In either case, the value obtained is compared for min-max compliance.
- * Base is always 0, i.e. autodetect depending on @s.
*
* Returns true/false whether number was accepted. On failure, *value has
* undefined contents.
*/
-bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
- uintmax_t min, uintmax_t max)
+bool xtables_strtoul_base(const char *s, char **end, uintmax_t *value,
+ uintmax_t min, uintmax_t max, unsigned int base)
{
uintmax_t v;
const char *p;
@@ -506,7 +606,7 @@ bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
;
if (*p == '-')
return false;
- v = strtoumax(s, &my_end, 0);
+ v = strtoumax(s, &my_end, base);
if (my_end == s)
return false;
if (end != NULL)
@@ -523,6 +623,12 @@ bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
return false;
}
+bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
+ uintmax_t min, uintmax_t max)
+{
+ return xtables_strtoul_base(s, end, value, min, max, 0);
+}
+
bool xtables_strtoui(const char *s, char **end, unsigned int *value,
unsigned int min, unsigned int max)
{
@@ -668,6 +774,8 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_match **dptr;
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
+ bool found = false;
+ bool seen = false;
if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -686,7 +794,10 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_match(ptr, prev)) {
+ seen = true;
+ if (!found &&
+ xtables_fully_register_pending_match(ptr, prev)) {
+ found = true;
prev = ptr;
continue;
} else if (prev) {
@@ -697,6 +808,11 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
dptr = &((*dptr)->next);
}
+ if (seen && !found)
+ fprintf(stderr,
+ "Warning: Extension %s is not supported, missing kernel module?\n",
+ name);
+
for (ptr = xtables_matches; ptr; ptr = ptr->next) {
if (extension_cmp(name, ptr->name, ptr->family)) {
struct xtables_match *clone;
@@ -788,6 +904,8 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
struct xtables_target *prev = NULL;
struct xtables_target **dptr;
struct xtables_target *ptr;
+ bool found = false;
+ bool seen = false;
/* Standard target? */
if (strcmp(name, "") == 0
@@ -796,13 +914,20 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
|| strcmp(name, XTC_LABEL_QUEUE) == 0
|| strcmp(name, XTC_LABEL_RETURN) == 0)
name = "standard";
+ /* known non-target? */
+ else if (notargets_hlist_lookup(name) &&
+ tryload != XTF_LOAD_MUST_SUCCEED)
+ return NULL;
/* Trigger delayed initialization */
for (dptr = &xtables_pending_targets; *dptr; ) {
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_target(ptr, prev)) {
+ seen = true;
+ if (!found &&
+ xtables_fully_register_pending_target(ptr, prev)) {
+ found = true;
prev = ptr;
continue;
} else if (prev) {
@@ -813,6 +938,11 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
dptr = &((*dptr)->next);
}
+ if (seen && !found)
+ fprintf(stderr,
+ "Warning: Extension %s is not supported, missing kernel module?\n",
+ name);
+
for (ptr = xtables_targets; ptr; ptr = ptr->next) {
if (extension_cmp(name, ptr->name, ptr->family)) {
struct xtables_target *clone;
@@ -859,6 +989,8 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (ptr)
ptr->used = 1;
+ else
+ notargets_hlist_insert(name);
return ptr;
}
@@ -890,7 +1022,7 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
socklen_t s = sizeof(rev);
int max_rev, sockfd;
- sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
+ sockfd = socket(afinfo->family, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
if (sockfd < 0) {
if (errno == EPERM) {
/* revision 0 is always supported. */
@@ -906,12 +1038,6 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
exit(1);
}
- if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
- fprintf(stderr, "Could not set close on exec: %s\n",
- strerror(errno));
- exit(1);
- }
-
xtables_load_ko(xtables_modprobe_program, true);
strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
@@ -923,7 +1049,12 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
/* Definitely don't support this? */
if (errno == ENOENT || errno == EPROTONOSUPPORT) {
close(sockfd);
- return 0;
+ /* Pretend revision 0 support for better error messaging */
+ if (revision == 0)
+ fprintf(stderr,
+ "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
+ name);
+ return (revision == 0);
} else if (errno == ENOPROTOOPT) {
close(sockfd);
/* Assume only revision 0 support (old kernel) */
@@ -1287,6 +1418,10 @@ void xtables_rule_matches_free(struct xtables_rule_match **matches)
free(matchp->match->m);
matchp->match->m = NULL;
}
+ if (matchp->match->udata_size) {
+ free(matchp->match->udata);
+ matchp->match->udata = NULL;
+ }
if (matchp->match == matchp->match->next) {
free(matchp->match);
matchp->match = NULL;
@@ -1378,7 +1513,7 @@ void xtables_param_act(unsigned int status, const char *p1, ...)
const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
{
- static char buf[20];
+ static char buf[16];
const unsigned char *bytep = (const void *)&addrp->s_addr;
sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
@@ -1430,16 +1565,11 @@ int xtables_ipmask_to_cidr(const struct in_addr *mask)
int i;
maskaddr = ntohl(mask->s_addr);
- /* shortcut for /32 networks */
- if (maskaddr == 0xFFFFFFFFL)
- return 32;
- i = 32;
- bits = 0xFFFFFFFEL;
- while (--i >= 0 && maskaddr != bits)
- bits <<= 1;
- if (i >= 0)
- return i;
+ for (i = 32, bits = (uint32_t)-1; i >= 0; i--, bits <<= 1) {
+ if (bits == maskaddr)
+ return i;
+ }
/* this mask cannot be converted to CIDR notation */
return -1;
@@ -1812,9 +1942,8 @@ const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
{
static struct in6_addr ap;
- int err;
- if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
+ if (inet_pton(AF_INET6, num, &ap) == 1)
return &ap;
return NULL;
@@ -2067,12 +2196,15 @@ const struct xtables_pprot xtables_chain_protos[] = {
{"udp", IPPROTO_UDP},
{"udplite", IPPROTO_UDPLITE},
{"icmp", IPPROTO_ICMP},
- {"icmpv6", IPPROTO_ICMPV6},
{"ipv6-icmp", IPPROTO_ICMPV6},
+ {"icmpv6", IPPROTO_ICMPV6},
{"esp", IPPROTO_ESP},
{"ah", IPPROTO_AH},
+ {"mobility-header", IPPROTO_MH},
{"ipv6-mh", IPPROTO_MH},
{"mh", IPPROTO_MH},
+ {"dccp", IPPROTO_DCCP},
+ {"ipcomp", IPPROTO_COMP},
{"all", 0},
{NULL},
};
@@ -2086,23 +2218,15 @@ xtables_parse_protocol(const char *s)
if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
return proto;
- /* first deal with the special case of 'all' to prevent
- * people from being able to redefine 'all' in nsswitch
- * and/or provoke expensive [not working] ldap/nis/...
- * lookups */
- if (strcmp(s, "all") == 0)
- return 0;
+ for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
+ if (strcmp(s, xtables_chain_protos[i].name) == 0)
+ return xtables_chain_protos[i].num;
+ }
pent = getprotobyname(s);
if (pent != NULL)
return pent->p_proto;
- for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
- if (xtables_chain_protos[i].name == NULL)
- continue;
- if (strcmp(s, xtables_chain_protos[i].name) == 0)
- return xtables_chain_protos[i].num;
- }
xt_params->exit_err(PARAMETER_PROBLEM,
"unknown protocol \"%s\" specified", s);
return -1;
@@ -2137,6 +2261,77 @@ void xtables_print_num(uint64_t number, unsigned int format)
printf(FMT("%4lluT ","%lluT "), (unsigned long long)number);
}
+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;
@@ -2250,32 +2445,35 @@ void get_kernel_version(void)
#include <linux/netfilter/nf_tables.h>
+enum xt_xlate_type {
+ XT_XLATE_RULE = 0,
+ XT_XLATE_SET,
+ __XT_XLATE_MAX
+};
+
struct xt_xlate {
- struct {
+ struct xt_xlate_buf {
char *data;
int size;
int rem;
int off;
- } buf;
+ } buf[__XT_XLATE_MAX];
char comment[NFT_USERDATA_MAXLEN];
+ int family;
};
struct xt_xlate *xt_xlate_alloc(int size)
{
- struct xt_xlate *xl;
-
- xl = malloc(sizeof(struct xt_xlate));
- if (xl == NULL)
- xtables_error(RESOURCE_PROBLEM, "OOM");
-
- xl->buf.data = malloc(size);
- if (xl->buf.data == NULL)
- xtables_error(RESOURCE_PROBLEM, "OOM");
+ struct xt_xlate *xl = xtables_malloc(sizeof(struct xt_xlate));
+ int i;
- xl->buf.data[0] = '\0';
- xl->buf.size = size;
- xl->buf.rem = size;
- xl->buf.off = 0;
+ for (i = 0; i < __XT_XLATE_MAX; i++) {
+ xl->buf[i].data = xtables_malloc(size);
+ xl->buf[i].data[0] = '\0';
+ xl->buf[i].size = size;
+ xl->buf[i].rem = size;
+ xl->buf[i].off = 0;
+ }
xl->comment[0] = '\0';
return xl;
@@ -2283,23 +2481,85 @@ struct xt_xlate *xt_xlate_alloc(int size)
void xt_xlate_free(struct xt_xlate *xl)
{
- free(xl->buf.data);
+ int i;
+
+ for (i = 0; i < __XT_XLATE_MAX; i++)
+ free(xl->buf[i].data);
+
free(xl);
}
-void xt_xlate_add(struct xt_xlate *xl, const char *fmt, ...)
+static bool isbrace(char c)
{
- va_list ap;
+ switch (c) {
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ return true;
+ }
+ return false;
+}
+
+static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type,
+ bool space, const char *fmt, va_list ap)
+{
+ struct xt_xlate_buf *buf = &xl->buf[type];
+ char tmpbuf[1024] = "";
int len;
- va_start(ap, fmt);
- len = vsnprintf(xl->buf.data + xl->buf.off, xl->buf.rem, fmt, ap);
- if (len < 0 || len >= xl->buf.rem)
+ len = vsnprintf(tmpbuf, 1024, fmt, ap);
+ if (len < 0 || len >= buf->rem - 1)
xtables_error(RESOURCE_PROBLEM, "OOM");
+ if (space && buf->off &&
+ !isspace(buf->data[buf->off - 1]) &&
+ (isalnum(tmpbuf[0]) || isbrace(tmpbuf[0]))) {
+ buf->data[buf->off] = ' ';
+ buf->off++;
+ buf->rem--;
+ }
+ sprintf(buf->data + buf->off, "%s", tmpbuf);
+ buf->rem -= len;
+ buf->off += len;
+}
+
+void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_RULE, true, fmt, ap);
+ va_end(ap);
+}
+
+void xt_xlate_rule_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_RULE, false, fmt, ap);
+ va_end(ap);
+}
+
+void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_SET, true, fmt, ap);
+ va_end(ap);
+}
+
+void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_SET, false, fmt, ap);
va_end(ap);
- xl->buf.rem -= len;
- xl->buf.off += len;
}
void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment)
@@ -2313,7 +2573,27 @@ const char *xt_xlate_get_comment(struct xt_xlate *xl)
return xl->comment[0] ? xl->comment : NULL;
}
+void xl_xlate_set_family(struct xt_xlate *xl, uint8_t family)
+{
+ xl->family = family;
+}
+
+uint8_t xt_xlate_get_family(struct xt_xlate *xl)
+{
+ return xl->family;
+}
+
const char *xt_xlate_get(struct xt_xlate *xl)
{
- return xl->buf.data;
+ struct xt_xlate_buf *buf = &xl->buf[XT_XLATE_RULE];
+
+ while (buf->off && isspace(buf->data[buf->off - 1]))
+ buf->data[--buf->off] = '\0';
+
+ return buf->data;
+}
+
+const char *xt_xlate_set_get(struct xt_xlate *xl)
+{
+ return xl->buf[XT_XLATE_SET].data;
}
diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c
index d329f2ff..774d0ee6 100644
--- a/libxtables/xtoptions.c
+++ b/libxtables/xtoptions.c
@@ -21,7 +21,6 @@
#include <arpa/inet.h>
#include <netinet/ip.h>
#include "xtables.h"
-#include "xshared.h"
#ifndef IPTOS_NORMALSVC
# define IPTOS_NORMALSVC 0
#endif
@@ -58,7 +57,6 @@ static const size_t xtopt_psize[] = {
[XTTYPE_STRING] = -1,
[XTTYPE_SYSLOGLEVEL] = sizeof(uint8_t),
[XTTYPE_HOST] = sizeof(union nf_inet_addr),
- [XTTYPE_HOSTMASK] = sizeof(union nf_inet_addr),
[XTTYPE_PROTOCOL] = sizeof(uint8_t),
[XTTYPE_PORT] = sizeof(uint16_t),
[XTTYPE_PORTRC] = sizeof(uint16_t[2]),
@@ -67,6 +65,20 @@ static const size_t xtopt_psize[] = {
};
/**
+ * Return a sanitized afinfo->family value, covering for NFPROTO_ARP
+ */
+static uint8_t afinfo_family(void)
+{
+ switch (afinfo->family) {
+ case NFPROTO_ARP:
+ case NFPROTO_BRIDGE:
+ return NFPROTO_IPV4;
+ default:
+ return afinfo->family;
+ }
+}
+
+/**
* Creates getopt options from the x6-style option map, and assigns each a
* getopt id.
*/
@@ -74,56 +86,22 @@ struct option *
xtables_options_xfrm(struct option *orig_opts, struct option *oldopts,
const struct xt_option_entry *entry, unsigned int *offset)
{
- unsigned int num_orig, num_old = 0, num_new, i;
+ int num_new, i;
struct option *merge, *mp;
- if (entry == NULL)
- return oldopts;
- for (num_orig = 0; orig_opts[num_orig].name != NULL; ++num_orig)
- ;
- if (oldopts != NULL)
- for (num_old = 0; oldopts[num_old].name != NULL; ++num_old)
- ;
for (num_new = 0; entry[num_new].name != NULL; ++num_new)
;
- /*
- * Since @oldopts also has @orig_opts already (and does so at the
- * start), skip these entries.
- */
- if (oldopts != NULL) {
- oldopts += num_orig;
- num_old -= num_orig;
+ mp = xtables_calloc(num_new + 1, sizeof(*mp));
+ for (i = 0; i < num_new; i++) {
+ mp[i].name = entry[i].name;
+ mp[i].has_arg = entry[i].type != XTTYPE_NONE;
+ mp[i].val = entry[i].id;
}
- merge = malloc(sizeof(*mp) * (num_orig + num_old + num_new + 1));
- if (merge == NULL)
- return NULL;
+ merge = xtables_merge_options(orig_opts, oldopts, mp, offset);
- /* Let the base options -[ADI...] have precedence over everything */
- memcpy(merge, orig_opts, sizeof(*mp) * num_orig);
- mp = merge + num_orig;
-
- /* Second, the new options */
- xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
- *offset = xt_params->option_offset;
-
- for (i = 0; i < num_new; ++i, ++mp, ++entry) {
- mp->name = entry->name;
- mp->has_arg = entry->type != XTTYPE_NONE;
- mp->flag = NULL;
- mp->val = entry->id + *offset;
- }
-
- /* Third, the old options */
- if (oldopts != NULL) {
- memcpy(mp, oldopts, sizeof(*mp) * num_old);
- mp += num_old;
- }
- xtables_free_opts(0);
-
- /* Clear trailing entry */
- memset(mp, 0, sizeof(*mp));
+ free(mp);
return merge;
}
@@ -170,6 +148,14 @@ static size_t xtopt_esize_by_type(enum xt_option_type type)
}
}
+static uint64_t htonll(uint64_t val)
+{
+ uint32_t high = val >> 32;
+ uint32_t low = val & UINT32_MAX;
+
+ return (uint64_t)htonl(low) << 32 | htonl(high);
+}
+
/**
* Require a simple integer.
*/
@@ -184,7 +170,8 @@ static void xtopt_parse_int(struct xt_option_call *cb)
if (cb->entry->max != 0)
lmax = cb->entry->max;
- if (!xtables_strtoul(cb->arg, NULL, &value, lmin, lmax))
+ if (!xtables_strtoul_base(cb->arg, NULL, &value,
+ lmin, lmax, cb->entry->base))
xt_params->exit_err(PARAMETER_PROBLEM,
"%s: bad value for option \"--%s\", "
"or out of range (%ju-%ju).\n",
@@ -196,14 +183,20 @@ static void xtopt_parse_int(struct xt_option_call *cb)
*(uint8_t *)XTOPT_MKPTR(cb) = cb->val.u8;
} else if (entry->type == XTTYPE_UINT16) {
cb->val.u16 = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u16 = htons(cb->val.u16);
if (entry->flags & XTOPT_PUT)
*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.u16;
} else if (entry->type == XTTYPE_UINT32) {
cb->val.u32 = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u32 = htonl(cb->val.u32);
if (entry->flags & XTOPT_PUT)
*(uint32_t *)XTOPT_MKPTR(cb) = cb->val.u32;
} else if (entry->type == XTTYPE_UINT64) {
cb->val.u64 = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u64 = htonll(cb->val.u64);
if (entry->flags & XTOPT_PUT)
*(uint64_t *)XTOPT_MKPTR(cb) = cb->val.u64;
}
@@ -238,17 +231,25 @@ static void xtopt_parse_float(struct xt_option_call *cb)
static void xtopt_mint_value_to_cb(struct xt_option_call *cb, uintmax_t value)
{
const struct xt_option_entry *entry = cb->entry;
+ uint8_t i = cb->nvals;
- if (cb->nvals >= ARRAY_SIZE(cb->val.u32_range))
+ if (i >= ARRAY_SIZE(cb->val.u32_range))
return;
- if (entry->type == XTTYPE_UINT8RC)
- cb->val.u8_range[cb->nvals] = value;
- else if (entry->type == XTTYPE_UINT16RC)
- cb->val.u16_range[cb->nvals] = value;
- else if (entry->type == XTTYPE_UINT32RC)
- cb->val.u32_range[cb->nvals] = value;
- else if (entry->type == XTTYPE_UINT64RC)
- cb->val.u64_range[cb->nvals] = value;
+ if (entry->type == XTTYPE_UINT8RC) {
+ cb->val.u8_range[i] = value;
+ } else if (entry->type == XTTYPE_UINT16RC) {
+ cb->val.u16_range[i] = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u16_range[i] = htons(cb->val.u16_range[i]);
+ } else if (entry->type == XTTYPE_UINT32RC) {
+ cb->val.u32_range[i] = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u32_range[i] = htonl(cb->val.u32_range[i]);
+ } else if (entry->type == XTTYPE_UINT64RC) {
+ cb->val.u64_range[i] = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u64_range[i] = htonll(cb->val.u64_range[i]);
+ }
}
/**
@@ -288,13 +289,16 @@ static void xtopt_parse_mint(struct xt_option_call *cb)
const struct xt_option_entry *entry = cb->entry;
const char *arg;
size_t esize = xtopt_esize_by_type(entry->type);
- const uintmax_t lmax = xtopt_max_by_type(entry->type);
+ uintmax_t lmax = xtopt_max_by_type(entry->type);
+ uintmax_t value, lmin = entry->min;
void *put = XTOPT_MKPTR(cb);
unsigned int maxiter;
- uintmax_t value;
char *end = "";
char sep = ':';
+ if (entry->max && entry->max < lmax)
+ lmax = entry->max;
+
maxiter = entry->size / esize;
if (maxiter == 0)
maxiter = ARRAY_SIZE(cb->val.u32_range);
@@ -311,18 +315,19 @@ static void xtopt_parse_mint(struct xt_option_call *cb)
if (*arg == '\0' || *arg == sep) {
/* Default range components when field not spec'd. */
end = (char *)arg;
- value = (cb->nvals == 1) ? lmax : 0;
+ value = (cb->nvals == 1) ? lmax : lmin;
} else {
- if (!xtables_strtoul(arg, &end, &value, 0, lmax))
+ if (!xtables_strtoul(arg, &end, &value, lmin, lmax))
xt_params->exit_err(PARAMETER_PROBLEM,
"%s: bad value for option \"--%s\" near "
- "\"%s\", or out of range (0-%ju).\n",
- cb->ext_name, entry->name, arg, lmax);
+ "\"%s\", or out of range (%ju-%ju).\n",
+ cb->ext_name, entry->name, arg, lmin, lmax);
if (*end != '\0' && *end != sep)
xt_params->exit_err(PARAMETER_PROBLEM,
"%s: Argument to \"--%s\" has "
"unexpected characters near \"%s\".\n",
cb->ext_name, entry->name, end);
+ lmin = value;
}
xtopt_mint_value_to_cb(cb, value);
++cb->nvals;
@@ -497,7 +502,7 @@ static socklen_t xtables_sa_hostlen(unsigned int afproto)
*/
static void xtopt_parse_host(struct xt_option_call *cb)
{
- struct addrinfo hints = {.ai_family = afinfo->family};
+ struct addrinfo hints = {.ai_family = afinfo_family()};
unsigned int adcount = 0;
struct addrinfo *res, *p;
int ret;
@@ -508,7 +513,7 @@ static void xtopt_parse_host(struct xt_option_call *cb)
"getaddrinfo: %s\n", gai_strerror(ret));
memset(&cb->val.hmask, 0xFF, sizeof(cb->val.hmask));
- cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
+ cb->val.hlen = (afinfo_family() == NFPROTO_IPV4) ? 32 : 128;
for (p = res; p != NULL; p = p->ai_next) {
if (adcount == 0) {
@@ -602,11 +607,9 @@ static void xtopt_parse_mport(struct xt_option_call *cb)
const struct xt_option_entry *entry = cb->entry;
char *lo_arg, *wp_arg, *arg;
unsigned int maxiter;
- int value;
+ int value, prev = 0;
- wp_arg = lo_arg = strdup(cb->arg);
- if (lo_arg == NULL)
- xt_params->exit_err(RESOURCE_PROBLEM, "strdup");
+ wp_arg = lo_arg = xtables_strdup(cb->arg);
maxiter = entry->size / esize;
if (maxiter == 0)
@@ -634,6 +637,11 @@ static void xtopt_parse_mport(struct xt_option_call *cb)
xt_params->exit_err(PARAMETER_PROBLEM,
"Port \"%s\" does not resolve to "
"anything.\n", arg);
+ if (value < prev)
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "Port range %d-%d is negative.\n",
+ prev, value);
+ prev = value;
if (entry->flags & XTOPT_NBO)
value = htons(value);
if (cb->nvals < ARRAY_SIZE(cb->val.port_range))
@@ -653,7 +661,7 @@ static void xtopt_parse_mport(struct xt_option_call *cb)
static int xtopt_parse_mask(struct xt_option_call *cb)
{
- struct addrinfo hints = {.ai_family = afinfo->family,
+ struct addrinfo hints = {.ai_family = afinfo_family(),
.ai_flags = AI_NUMERICHOST };
struct addrinfo *res;
int ret;
@@ -665,7 +673,7 @@ static int xtopt_parse_mask(struct xt_option_call *cb)
memcpy(&cb->val.hmask, xtables_sa_host(res->ai_addr, res->ai_family),
xtables_sa_hostlen(res->ai_family));
- switch(afinfo->family) {
+ switch(afinfo_family()) {
case AF_INET:
cb->val.hlen = xtables_ipmask_to_cidr(&cb->val.hmask.in);
break;
@@ -687,7 +695,7 @@ static void xtopt_parse_plen(struct xt_option_call *cb)
const struct xt_option_entry *entry = cb->entry;
unsigned int prefix_len = 128; /* happiness is a warm gcc */
- cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
+ cb->val.hlen = (afinfo_family() == NFPROTO_IPV4) ? 32 : 128;
if (!xtables_strtoui(cb->arg, NULL, &prefix_len, 0, cb->val.hlen)) {
/* Is this mask expressed in full format? e.g. 255.255.255.0 */
if (xtopt_parse_mask(cb))
@@ -714,6 +722,10 @@ static void xtopt_parse_plenmask(struct xt_option_call *cb)
xtopt_parse_plen(cb);
+ /* may not be convertible to CIDR notation */
+ if (cb->val.hlen == (uint8_t)-1)
+ goto out_put;
+
memset(mask, 0xFF, sizeof(union nf_inet_addr));
/* This shifting is AF-independent. */
if (cb->val.hlen == 0) {
@@ -734,6 +746,7 @@ static void xtopt_parse_plenmask(struct xt_option_call *cb)
mask[1] = htonl(mask[1]);
mask[2] = htonl(mask[2]);
mask[3] = htonl(mask[3]);
+out_put:
if (entry->flags & XTOPT_PUT)
memcpy(XTOPT_MKPTR(cb), mask, sizeof(union nf_inet_addr));
}
@@ -747,9 +760,7 @@ static void xtopt_parse_hostmask(struct xt_option_call *cb)
xtopt_parse_host(cb);
return;
}
- work = strdup(orig_arg);
- if (work == NULL)
- xt_params->exit_err(PARAMETER_PROBLEM, "strdup");
+ work = xtables_strdup(orig_arg);
p = strchr(work, '/'); /* by def this can't be NULL now */
*p++ = '\0';
/*
@@ -763,6 +774,7 @@ static void xtopt_parse_hostmask(struct xt_option_call *cb)
cb->arg = p;
xtopt_parse_plenmask(cb);
cb->arg = orig_arg;
+ free(work);
}
static void xtopt_parse_ethermac(struct xt_option_call *cb)
@@ -789,6 +801,15 @@ static void xtopt_parse_ethermac(struct xt_option_call *cb)
xt_params->exit_err(PARAMETER_PROBLEM, "Invalid MAC address specified.");
}
+static void xtopt_parse_ethermacmask(struct xt_option_call *cb)
+{
+ memset(cb->val.ethermacmask, 0xff, ETH_ALEN);
+ if (xtables_parse_mac_and_mask(cb->arg, cb->val.ethermac,
+ cb->val.ethermacmask))
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "Invalid MAC/mask address specified.");
+}
+
static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_UINT8] = xtopt_parse_int,
[XTTYPE_UINT16] = xtopt_parse_int,
@@ -811,6 +832,7 @@ static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_PLEN] = xtopt_parse_plen,
[XTTYPE_PLENMASK] = xtopt_parse_plenmask,
[XTTYPE_ETHERMAC] = xtopt_parse_ethermac,
+ [XTTYPE_ETHERMACMASK]= xtopt_parse_ethermacmask,
};
/**
@@ -928,7 +950,7 @@ void xtables_option_tpcall(unsigned int c, char **argv, bool invert,
cb.entry = xtables_option_lookup(t->x6_options, c);
if (cb.entry == NULL)
xtables_error(OTHER_PROBLEM,
- "Extension does not know id %u\n", c);
+ "Extension does not know id %u", c);
cb.arg = optarg;
cb.invert = invert;
cb.ext_name = t->name;
@@ -964,7 +986,7 @@ void xtables_option_mpcall(unsigned int c, char **argv, bool invert,
cb.entry = xtables_option_lookup(m->x6_options, c);
if (cb.entry == NULL)
xtables_error(OTHER_PROBLEM,
- "Extension does not know id %u\n", c);
+ "Extension does not know id %u", c);
cb.arg = optarg;
cb.invert = invert;
cb.ext_name = m->name;
@@ -1138,11 +1160,7 @@ struct xtables_lmap *xtables_lmap_init(const char *file)
goto out;
}
lmap_this->id = id;
- lmap_this->name = strdup(cur);
- if (lmap_this->name == NULL) {
- free(lmap_this);
- goto out;
- }
+ lmap_this->name = xtables_strdup(cur);
lmap_this->next = NULL;
if (lmap_prev != NULL)
diff --git a/utils/.gitignore b/utils/.gitignore
index 6300812b..e508bb32 100644
--- a/utils/.gitignore
+++ b/utils/.gitignore
@@ -2,3 +2,4 @@
/nfnl_osf.8
/nfbpf_compile
/nfbpf_compile.8
+/nfsynproxy
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 42bd9737..34056514 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -2,16 +2,17 @@
AM_CFLAGS = ${regular_CFLAGS}
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include \
- -I${top_srcdir}/include ${libnfnetlink_CFLAGS}
+ -I${top_srcdir}/include ${libnfnetlink_CFLAGS} ${libpcap_CFLAGS}
+AM_LDFLAGS = ${regular_LDFLAGS}
sbin_PROGRAMS =
-pkgdata_DATA =
+dist_pkgdata_DATA =
man_MANS =
if HAVE_LIBNFNETLINK
man_MANS += nfnl_osf.8
sbin_PROGRAMS += nfnl_osf
-pkgdata_DATA += pf.os
+dist_pkgdata_DATA += pf.os
nfnl_osf_LDADD = ${libnfnetlink_LIBS}
@@ -24,12 +25,12 @@ endif
if ENABLE_BPFC
man_MANS += nfbpf_compile.8
sbin_PROGRAMS += nfbpf_compile
-nfbpf_compile_LDADD = -lpcap
+nfbpf_compile_LDADD = ${libpcap_LIBS}
endif
if ENABLE_SYNCONF
sbin_PROGRAMS += nfsynproxy
-nfsynproxy_LDADD = -lpcap
+nfsynproxy_LDADD = ${libpcap_LIBS}
endif
CLEANFILES = nfnl_osf.8 nfbpf_compile.8
diff --git a/utils/nfbpf_compile.8.in b/utils/nfbpf_compile.8.in
index d02979a5..b19d4fbb 100644
--- a/utils/nfbpf_compile.8.in
+++ b/utils/nfbpf_compile.8.in
@@ -1,7 +1,7 @@
.TH NFBPF_COMPILE 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@"
.SH NAME
-nfbpf_compile \- generate bytecode for use with xt_bpf
+nfbpf_compile \(em generate bytecode for use with xt_bpf
.SH SYNOPSIS
.ad l
diff --git a/utils/nfbpf_compile.c b/utils/nfbpf_compile.c
index 2c46c7b0..c9e763dc 100644
--- a/utils/nfbpf_compile.c
+++ b/utils/nfbpf_compile.c
@@ -17,6 +17,7 @@ int main(int argc, char **argv)
struct bpf_program program;
struct bpf_insn *ins;
int i, dlt = DLT_RAW;
+ pcap_t *pcap;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: %s [link] '<program>'\n\n"
@@ -36,9 +37,15 @@ int main(int argc, char **argv)
}
}
- if (pcap_compile_nopcap(65535, dlt, &program, argv[argc - 1], 1,
+ pcap = pcap_open_dead(dlt, 65535);
+ if (!pcap) {
+ fprintf(stderr, "Memory allocation failure\n");
+ return 1;
+ }
+ if (pcap_compile(pcap, &program, argv[argc - 1], 1,
PCAP_NETMASK_UNKNOWN)) {
fprintf(stderr, "Compilation error\n");
+ pcap_close(pcap);
return 1;
}
@@ -50,6 +57,7 @@ int main(int argc, char **argv)
printf("%u %u %u %u\n", ins->code, ins->jt, ins->jf, ins->k);
pcap_freecode(&program);
+ pcap_close(pcap);
return 0;
}
diff --git a/utils/nfnl_osf.8.in b/utils/nfnl_osf.8.in
index 140b5c3f..1ef0c387 100644
--- a/utils/nfnl_osf.8.in
+++ b/utils/nfnl_osf.8.in
@@ -1,7 +1,7 @@
.TH NFNL_OSF 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@"
.SH NAME
-nfnl_osf \- OS fingerprint loader utility
+nfnl_osf \(em OS fingerprint loader utility
.SH SYNOPSIS
.ad l
@@ -16,7 +16,7 @@ nfnl_osf \- OS fingerprint loader utility
.SH DESCRIPTION
The
.B nfnl_osf
-utility allows to load a set of operating system signatures into the kernel for
+utility allows one to load a set of operating system signatures into the kernel for
later matching against using iptables'
.B osf
match.
diff --git a/xlate-test.py b/xlate-test.py
index 4c014f9b..b6a78bb2 100755
--- a/xlate-test.py
+++ b/xlate-test.py
@@ -7,7 +7,14 @@ import shlex
import argparse
from subprocess import Popen, PIPE
-keywords = ("iptables-translate", "ip6tables-translate", "ebtables-translate")
+def run_proc(args, shell = False, input = None):
+ """A simple wrapper around Popen, returning (rc, stdout, stderr)"""
+ process = Popen(args, text = True, shell = shell,
+ stdin = PIPE, stdout = PIPE, stderr = PIPE)
+ output, error = process.communicate(input)
+ return (process.returncode, output, error)
+
+keywords = ("iptables-translate", "ip6tables-translate", "arptables-translate", "ebtables-translate")
xtables_nft_multi = 'xtables-nft-multi'
if sys.stdout.isatty():
@@ -33,82 +40,246 @@ def green(string):
return colors["green"] + string + colors["end"]
+def test_one_xlate(name, sourceline, expected, result):
+ cmd = [xtables_nft_multi] + shlex.split(sourceline)
+ rc, output, error = run_proc(cmd)
+ if rc != 0:
+ result.append(name + ": " + red("Error: ") + "Call failed: " + " ".join(cmd))
+ result.append(error)
+ return False
+
+ translation = output.rstrip(" \n")
+ if translation != expected:
+ result.append(name + ": " + red("Fail"))
+ result.append(magenta("src: ") + sourceline.rstrip(" \n"))
+ result.append(magenta("exp: ") + expected)
+ result.append(magenta("res: ") + translation + "\n")
+ return False
+
+ return True
+
+def test_one_replay(name, sourceline, expected, result):
+ global args
+
+ searchline = None
+ if sourceline.find(';') >= 0:
+ sourceline, searchline = sourceline.split(';')
+
+ srcwords = shlex.split(sourceline)
+
+ srccmd = srcwords[0]
+ ipt = srccmd.split('-')[0]
+ table_idx = -1
+ chain_idx = -1
+ table_name = "filter"
+ chain_name = None
+ for idx in range(1, len(srcwords)):
+ if srcwords[idx] in ["-A", "-I", "--append", "--insert"]:
+ chain_idx = idx
+ chain_name = srcwords[idx + 1]
+ elif srcwords[idx] in ["-t", "--table"]:
+ table_idx = idx
+ table_name = srcwords[idx + 1]
+
+ if not chain_name:
+ return True # nothing to do?
+
+ if searchline is None:
+ # adjust sourceline as required
+ checkcmd = srcwords[:]
+ checkcmd[0] = ipt
+ checkcmd[chain_idx] = "--check"
+ else:
+ checkcmd = [ipt, "-t", table_name]
+ checkcmd += ["--check", chain_name, searchline]
+
+ fam = ""
+ if srccmd.startswith("ip6"):
+ fam = "ip6 "
+ elif srccmd.startswith("arp"):
+ fam = "arp "
+ elif srccmd.startswith("ebt"):
+ fam = "bridge "
+
+ expected = [ l.removeprefix("nft ").strip(" '") for l in expected.split("\n") ]
+ nft_input = [
+ "flush ruleset",
+ "add table " + fam + table_name,
+ "add chain " + fam + table_name + " " + chain_name,
+ ] + expected
+
+ rc, output, error = run_proc([args.nft, "-f", "-"], shell = False, input = "\n".join(nft_input))
+ if rc != 0:
+ result.append(name + ": " + red("Replay Fail"))
+ result.append(args.nft + " call failed: " + error.rstrip('\n'))
+ for line in nft_input:
+ result.append(magenta("input: ") + line)
+ return False
+
+ rc, output, error = run_proc([xtables_nft_multi] + checkcmd)
+ if rc != 0:
+ result.append(name + ": " + red("Check Fail"))
+ result.append(magenta("check: ") + " ".join(checkcmd))
+ result.append(magenta("error: ") + error)
+ rc, output, error = run_proc([xtables_nft_multi, ipt + "-save"])
+ for l in output.split("\n"):
+ result.append(magenta("ipt: ") + l)
+ rc, output, error = run_proc([args.nft, "list", "ruleset"])
+ for l in output.split("\n"):
+ result.append(magenta("nft: ") + l)
+ return False
+
+ return True
+
+
def run_test(name, payload):
global xtables_nft_multi
+ global args
+
test_passed = True
tests = passed = failed = errors = 0
result = []
- for line in payload:
- if line.startswith(keywords):
+ line = payload.readline()
+ while line:
+ if not line.startswith(keywords):
+ line = payload.readline()
+ continue
+
+ sourceline = replayline = line.rstrip("\n")
+ if line.find(';') >= 0:
+ sourceline = line.split(';')[0]
+
+ expected = payload.readline().rstrip(" \n")
+ next_expected = payload.readline()
+ if next_expected.startswith("nft"):
+ expected += "\n" + next_expected.rstrip(" \n")
+ line = payload.readline()
+ else:
+ line = next_expected
+
+ tests += 1
+ if test_one_xlate(name, sourceline, expected, result):
+ passed += 1
+ else:
+ errors += 1
+ test_passed = False
+ continue
+
+ if args.replay:
tests += 1
- process = Popen([ xtables_nft_multi ] + shlex.split(line), stdout=PIPE, stderr=PIPE)
- (output, error) = process.communicate()
- if process.returncode == 0:
- translation = output.decode("utf-8").rstrip(" \n")
- expected = next(payload).rstrip(" \n")
- if translation != expected:
- test_passed = False
- failed += 1
- result.append(name + ": " + red("Fail"))
- result.append(magenta("src: ") + line.rstrip(" \n"))
- result.append(magenta("exp: ") + expected)
- result.append(magenta("res: ") + translation + "\n")
- test_passed = False
- else:
- passed += 1
+ if test_one_replay(name, replayline, expected, result):
+ passed += 1
else:
- test_passed = False
errors += 1
- result.append(name + ": " + red("Error: ") + "iptables-translate failure")
- result.append(error.decode("utf-8"))
- if (passed == tests) and not args.test:
+ test_passed = False
+
+ rc, output, error = run_proc([args.nft, "flush", "ruleset"])
+ if rc != 0:
+ result.append(name + ": " + red("Fail"))
+ result.append("nft flush ruleset call failed: " + error)
+
+ if (passed == tests):
print(name + ": " + green("OK"))
if not test_passed:
- print("\n".join(result))
- if args.test:
- print("1 test file, %d tests, %d tests passed, %d tests failed, %d errors" % (tests, passed, failed, errors))
- else:
- return tests, passed, failed, errors
+ print("\n".join(result), file=sys.stderr)
+ return tests, passed, failed, errors
def load_test_files():
test_files = total_tests = total_passed = total_error = total_failed = 0
- for test in sorted(os.listdir("extensions")):
- if test.endswith(".txlate"):
- with open("extensions/" + test, "r") as payload:
- tests, passed, failed, errors = run_test(test, payload)
- test_files += 1
- total_tests += tests
- total_passed += passed
- total_failed += failed
- total_error += errors
+ tests = sorted(os.listdir("extensions"))
+ for test in ['extensions/' + f for f in tests if f.endswith(".txlate")]:
+ with open(test, "r") as payload:
+ tests, passed, failed, errors = run_test(test, payload)
+ test_files += 1
+ total_tests += tests
+ total_passed += passed
+ total_failed += failed
+ total_error += errors
+ return (test_files, total_tests, total_passed, total_failed, total_error)
- print("%d test files, %d tests, %d tests passed, %d tests failed, %d errors" % (test_files, total_tests, total_passed, total_failed, total_error))
+def spawn_netns():
+ # prefer unshare module
+ try:
+ import unshare
+ unshare.unshare(unshare.CLONE_NEWNET)
+ return True
+ except:
+ pass
+
+ # sledgehammer style:
+ # - call ourselves prefixed by 'unshare -n' if found
+ # - pass extra --no-netns parameter to avoid another recursion
+ try:
+ import shutil
+
+ unshare = shutil.which("unshare")
+ if unshare is None:
+ return False
+
+ sys.argv.append("--no-netns")
+ os.execv(unshare, [unshare, "-n", sys.executable] + sys.argv)
+ except:
+ pass
+
+ return False
+
def main():
global xtables_nft_multi
+
+ if args.replay:
+ if os.getuid() != 0:
+ print("Replay test requires root, sorry", file=sys.stderr)
+ return
+ if not args.no_netns and not spawn_netns():
+ print("Cannot run in own namespace, connectivity might break",
+ file=sys.stderr)
+
if not args.host:
os.putenv("XTABLES_LIBDIR", os.path.abspath("extensions"))
xtables_nft_multi = os.path.abspath(os.path.curdir) \
+ '/iptables/' + xtables_nft_multi
- if args.test:
- if not args.test.endswith(".txlate"):
- args.test += ".txlate"
+ files = tests = passed = failed = errors = 0
+ for test in args.test:
+ if not test.endswith(".txlate"):
+ test += ".txlate"
try:
- with open(args.test, "r") as payload:
- run_test(args.test, payload)
+ with open(test, "r") as payload:
+ t, p, f, e = run_test(test, payload)
+ files += 1
+ tests += t
+ passed += p
+ failed += f
+ errors += e
except IOError:
- print(red("Error: ") + "test file does not exist")
+ print(red("Error: ") + "test file does not exist", file=sys.stderr)
+ return 99
+
+ if files == 0:
+ files, tests, passed, failed, errors = load_test_files()
+
+ if files > 1:
+ file_word = "files"
else:
- load_test_files()
+ file_word = "file"
+ print("%d test %s, %d tests, %d tests passed, %d tests failed, %d errors"
+ % (files, file_word, tests, passed, failed, errors))
+ return passed - tests
parser = argparse.ArgumentParser()
parser.add_argument('-H', '--host', action='store_true',
help='Run tests against installed binaries')
-parser.add_argument("test", nargs="?", help="run only the specified test file")
+parser.add_argument('-R', '--replay', action='store_true',
+ help='Replay tests to check iptables-nft parser')
+parser.add_argument('-n', '--nft', type=str, default='nft',
+ help='Replay using given nft binary (default: \'%(default)s\')')
+parser.add_argument('--no-netns', action='store_true',
+ help='Do not run testsuite in own network namespace')
+parser.add_argument("test", nargs="*", help="run only the specified test file(s)")
args = parser.parse_args()
-main()
+sys.exit(main())