Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Pkg Iptables
Commits
290749d4
Commit
290749d4
authored
Dec 03, 2019
by
Arturo Borrero Gonzalez
Browse files
New upstream version 1.8.4
parent
89c92f0c
Changes
87
Expand all
Show whitespace changes
Inline
Side-by-side
extensions/libxt_owner.man
View file @
290749d4
...
...
@@ -15,5 +15,9 @@ given user. You may also specify a numerical UID, or an UID range.
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
supplementary groups of a process.
.TP
[\fB!\fP] \fB\-\-socket\-exists\fP
Matches if the packet is associated with a socket.
extensions/libxt_owner.t
View file @
290749d4
...
...
@@ -8,5 +8,9 @@
-
m owner --uid-o
wner
0
-
10
--
gid
-
owner
0
-
10
;
=
;
OK
-
m owner ! --uid-o
wner
root
;
-
m owner ! --uid-o
wner
0
;
OK
-
m owner --soc
ket
-
exists
;
=
;
OK
-
m owner --gid-o
wner
0
-
10
--
suppl
-
groups
;
=
;
OK
-
m owner --suppl-groups
--
gid
-
owner
0
-
10
;;
FAIL
-
m owner --gid-o
wner
0
-
10
!
--
suppl
-
groups
;;
FAIL
-
m owner --suppl-groups
;;
FAIL
:
INPUT
-
m owner --uid-o
wner
root
;;
FAIL
include/Makefile.in
View file @
290749d4
...
...
@@ -92,10 +92,10 @@ host_triplet = @host@
@ENABLE_LIBIPQ_TRUE@
am__append_1
=
libipq/libipq.h
subdir
=
include
ACLOCAL_M4
=
$(top_srcdir)
/aclocal.m4
am__aclocal_m4_deps
=
$(top_srcdir)
/m4/
ax_check_linker_flags
.m4
\
$(top_srcdir)
/m4/l
ibtool
.m4
$(top_srcdir)
/m4/lt
options
.m4
\
$(top_srcdir)
/m4/lt
sugar
.m4
$(top_srcdir)
/m4/lt
version
.m4
\
$(top_srcdir)
/m4/lt~obsolete.m4
$(top_srcdir)
/configure.ac
am__aclocal_m4_deps
=
$(top_srcdir)
/m4/
libtool
.m4
\
$(top_srcdir)
/m4/l
toptions
.m4
$(top_srcdir)
/m4/lt
sugar
.m4
\
$(top_srcdir)
/m4/lt
version
.m4
$(top_srcdir)
/m4/lt
~obsolete
.m4
\
$(top_srcdir)
/configure.ac
am__configure_deps
=
$(am__aclocal_m4_deps)
$(CONFIGURE_DEPENDENCIES)
\
$(ACLOCAL_M4)
DIST_COMMON
=
$(srcdir)
/Makefile.am
$(am__include_HEADERS_DIST)
\
...
...
@@ -208,9 +208,6 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM
=
@INSTALL_STRIP_PROGRAM@
LD
=
@LD@
LDFLAGS
=
@LDFLAGS@
LEX
=
@LEX@
LEXLIB
=
@LEXLIB@
LEX_OUTPUT_ROOT
=
@LEX_OUTPUT_ROOT@
LIBOBJS
=
@LIBOBJS@
LIBS
=
@LIBS@
LIBTOOL
=
@LIBTOOL@
...
...
@@ -244,8 +241,6 @@ SET_MAKE = @SET_MAKE@
SHELL
=
@SHELL@
STRIP
=
@STRIP@
VERSION
=
@VERSION@
YACC
=
@YACC@
YFLAGS
=
@YFLAGS@
abs_builddir
=
@abs_builddir@
abs_srcdir
=
@abs_srcdir@
abs_top_builddir
=
@abs_top_builddir@
...
...
@@ -290,7 +285,6 @@ kinclude_CPPFLAGS = @kinclude_CPPFLAGS@
ksourcedir
=
@ksourcedir@
libdir
=
@libdir@
libexecdir
=
@libexecdir@
libiptc_LDFLAGS2
=
@libiptc_LDFLAGS2@
libmnl_CFLAGS
=
@libmnl_CFLAGS@
libmnl_LIBS
=
@libmnl_LIBS@
libnetfilter_conntrack_CFLAGS
=
@libnetfilter_conntrack_CFLAGS@
...
...
include/iptables/internal.h
.in
→
include/iptables/internal.h
View file @
290749d4
#ifndef IPTABLES_INTERNAL_H
#define IPTABLES_INTERNAL_H 1
#define IPTABLES_VERSION "@PACKAGE_VERSION@"
/**
* Program's own name and version.
*/
...
...
include/linux/netfilter/xt_nfacct.h
View file @
290749d4
...
...
@@ -14,4 +14,9 @@ struct xt_nfacct_match_info {
struct
nf_acct
*
nfacct
;
};
struct
xt_nfacct_match_info_v1
{
char
name
[
NFACCT_NAME_MAX
];
struct
nf_acct
*
nfacct
__attribute__
((
aligned
(
8
)));
};
#endif
/* _XT_NFACCT_MATCH_H */
include/linux/netfilter/xt_owner.h
View file @
290749d4
...
...
@@ -7,6 +7,7 @@ enum {
XT_OWNER_UID
=
1
<<
0
,
XT_OWNER_GID
=
1
<<
1
,
XT_OWNER_SOCKET
=
1
<<
2
,
XT_OWNER_SUPPL_GROUPS
=
1
<<
3
,
};
struct
xt_owner_match_info
{
...
...
iptables-test.py
View file @
290749d4
#!/usr/bin/python
#!/usr/bin/
env
python
#
# (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
#
...
...
@@ -10,6 +10,7 @@
# This software has been sponsored by Sophos Astaro <http://www.sophos.com>
#
from
__future__
import
print_function
import
sys
import
os
import
subprocess
...
...
@@ -45,7 +46,7 @@ def print_error(reason, filename=None, lineno=None):
'''
Prints an error with nice colors, indicating file and line number.
'''
print
(
filename
+
": "
+
Colors
.
RED
+
"ERROR"
+
print
(
filename
+
": "
+
Colors
.
RED
+
"ERROR"
+
Colors
.
ENDC
+
": line %d (%s)"
%
(
lineno
,
reason
))
...
...
@@ -140,7 +141,7 @@ def run_test(iptables, rule, rule_save, res, filename, lineno, netns):
return
-
1
# find the rule
matching
=
out
.
find
(
rule_save
)
matching
=
out
.
find
(
rule_save
.
encode
(
'utf-8'
)
)
if
matching
<
0
:
reason
=
"cannot find: "
+
iptables
+
" -I "
+
rule
print_error
(
reason
,
filename
,
lineno
)
...
...
@@ -166,7 +167,7 @@ def execute_cmd(cmd, filename, lineno):
if
cmd
.
startswith
(
'iptables '
)
or
cmd
.
startswith
(
'ip6tables '
)
or
cmd
.
startswith
(
'ebtables '
)
or
cmd
.
startswith
(
'arptables '
):
cmd
=
os
.
path
.
abspath
(
os
.
path
.
curdir
)
+
"/iptables/"
+
EXECUTEABLE
+
" "
+
cmd
print
>>
log_file
,
"command: %s"
%
cmd
print
(
"command: {}"
.
format
(
cmd
),
file
=
log_file
)
ret
=
subprocess
.
call
(
cmd
,
shell
=
True
,
universal_newlines
=
True
,
stderr
=
subprocess
.
STDOUT
,
stdout
=
log_file
)
log_file
.
flush
()
...
...
@@ -249,7 +250,7 @@ def run_test_file(filename, netns):
continue
if
len
(
chain_array
)
==
0
:
print
"broken test, missing chain, leaving"
print
(
"broken test, missing chain, leaving"
)
sys
.
exit
()
test_passed
=
True
...
...
@@ -282,7 +283,7 @@ def run_test_file(filename, netns):
if
netns
:
execute_cmd
(
"ip netns del ____iptables-container-test"
,
filename
,
0
)
if
total_test_passed
:
print
filename
+
": "
+
Colors
.
GREEN
+
"OK"
+
Colors
.
ENDC
print
(
filename
+
": "
+
Colors
.
GREEN
+
"OK"
+
Colors
.
ENDC
)
f
.
close
()
return
tests
,
passed
...
...
@@ -302,7 +303,7 @@ def show_missing():
missing
=
[
test_name
(
i
)
for
i
in
libfiles
if
not
test_name
(
i
)
in
testfiles
]
print
'
\n
'
.
join
(
missing
)
print
(
'
\n
'
.
join
(
missing
)
)
#
...
...
@@ -313,6 +314,8 @@ def main():
parser
.
add_argument
(
'filename'
,
nargs
=
'?'
,
metavar
=
'path/to/file.t'
,
help
=
'Run only this test'
)
parser
.
add_argument
(
'-H'
,
'--host'
,
action
=
'store_true'
,
help
=
'Run tests against installed binaries'
)
parser
.
add_argument
(
'-l'
,
'--legacy'
,
action
=
'store_true'
,
help
=
'Test iptables-legacy'
)
parser
.
add_argument
(
'-m'
,
'--missing'
,
action
=
'store_true'
,
...
...
@@ -336,11 +339,13 @@ def main():
EXECUTEABLE
=
"xtables-nft-multi"
if
os
.
getuid
()
!=
0
:
print
"You need to be root to run this, sorry"
print
(
"You need to be root to run this, sorry"
)
return
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"
)))
os
.
putenv
(
"PATH"
,
"%s/iptables:%s"
%
(
os
.
path
.
abspath
(
os
.
path
.
curdir
),
os
.
getenv
(
"PATH"
)))
test_files
=
0
tests
=
0
...
...
@@ -351,13 +356,17 @@ def main():
try
:
log_file
=
open
(
LOGFILE
,
'w'
)
except
IOError
:
print
"Couldn't open log file %s"
%
LOGFILE
print
(
"Couldn't open log file %s"
%
LOGFILE
)
return
file_list
=
[
os
.
path
.
join
(
EXTENSIONS_PATH
,
i
)
for
i
in
os
.
listdir
(
EXTENSIONS_PATH
)]
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
:
...
...
@@ -365,8 +374,7 @@ def main():
passed
+=
file_passed
test_files
+=
1
print
(
"%d test files, %d unit tests, %d passed"
%
(
test_files
,
tests
,
passed
))
print
(
"%d test files, %d unit tests, %d passed"
%
(
test_files
,
tests
,
passed
))
if
__name__
==
'__main__'
:
...
...
iptables/.gitignore
View file @
290749d4
...
...
@@ -3,6 +3,7 @@
/ip6tables-restore
/ip6tables-static
/ip6tables-translate.8
/ip6tables-restore-translate.8
/iptables
/iptables.8
/iptables-extensions.8
...
...
@@ -13,14 +14,12 @@
/iptables-restore.8
/iptables-static
/iptables-translate.8
/iptables-restore-translate.8
/iptables-xml
/iptables-xml.1
/xtables-multi
/xtables-legacy-multi
/xtables-nft-multi
/xtables-config-parser.c
/xtables-config-parser.h
/xtables-config-syntax.c
/xtables-monitor.8
/xtables.pc
iptables/Makefile.am
View file @
290749d4
...
...
@@ -2,7 +2,6 @@
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_YFLAGS
=
-d
BUILT_SOURCES
=
...
...
@@ -27,7 +26,6 @@ xtables_legacy_multi_LDADD += ../libxtables/libxtables.la -lm
# iptables using nf_tables api
if
ENABLE_NFTABLES
BUILT_SOURCES
+=
xtables-config-parser.h
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
...
...
@@ -35,19 +33,16 @@ if ENABLE_STATIC
xtables_nft_multi_CFLAGS
+=
-DALL_INCLUSIVE
endif
xtables_nft_multi_CFLAGS
+=
-DENABLE_NFTABLES
-DENABLE_IPV4
-DENABLE_IPV6
xtables_nft_multi_SOURCES
+=
xtables-config-parser.y xtables-config-syntax.l
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
\
xtables-monitor.c
nft-cache.c
\
xtables-arp-standalone.c xtables-arp.c
\
nft-bridge.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
# yacc and lex generate dirty code
xtables_nft_multi-xtables-config-parser.o xtables_nft_multi-xtables-config-syntax.o
:
AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls
xtables_nft_multi_SOURCES
+=
xshared.c
xtables_nft_multi_LDADD
+=
../libxtables/libxtables.la
-lm
endif
...
...
@@ -58,17 +53,17 @@ sbin_PROGRAMS += xtables-nft-multi
endif
man_MANS
=
iptables.8 iptables-restore.8 iptables-save.8
\
iptables-xml.1 ip6tables.8 ip6tables-restore.8
\
ip6tables-save.8 iptables-extensions.8
\
xtables-nft.8 xtables-translate.8 xtables-legacy.8
\
iptables-translate.8 ip6tables-translate.8
\
xtables-monitor.8
ip6tables-save.8 iptables-extensions.8
if
ENABLE_NFTABLES
man_MANS
+=
arptables-nft.8 arptables-nft-restore.8 arptables-nft-save.8
\
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
endif
CLEANFILES
=
iptables.8 xtables-monitor.8
\
iptables-translate.8 ip6tables-translate.8
\
xtables-config-parser.c xtables-config-syntax.c
iptables-translate.8 ip6tables-translate.8
vx_bin_links
=
iptables-xml
if
ENABLE_IPV4
...
...
@@ -98,7 +93,7 @@ iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../e
-e
'/@MATCH@/ r ../extensions/matches.man'
\
-e
'/@TARGET@/ r ../extensions/targets.man'
$<
>
$@
;
iptables-translate.8 ip6tables-translate.8
:
iptables-translate.8 ip6tables-translate.8
iptables-restore-translate.8 ip6tables-restore-translate.8
:
${AM_VERBOSE_GEN}
echo
'.so man8/xtables-translate.8'
>
$@
pkgconfig_DATA
=
xtables.pc
...
...
iptables/Makefile.in
View file @
290749d4
This diff is collapsed.
Click to expand it.
iptables/ebtables-nft.8
View file @
290749d4
...
...
@@ -522,35 +522,39 @@ 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
checked for type.
.\" .SS among
.\" Match a MAC address or MAC/IP address pair versus a list of MAC addresses
.\" and MAC/IP address pairs.
.\" A list entry has the following format:
.\" .IR xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip][,] ". Multiple"
.\" list entries are separated by a comma, specifying an IP address corresponding to
.\" the MAC address is optional. Multiple MAC/IP address pairs with the same MAC address
.\" 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"
.\" 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"
.\" 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"
.\" Same as
.\" .BR --among-dst " but the list is read in from the specified file."
.\" .TP
.\" .BR "--among-src-file " "[!] \fIfile\fP"
.\" Same as
.\" .BR --among-src " but the list is read in from the specified file."
.SS among
Match a MAC address or MAC/IP address pair versus a list of MAC addresses
and MAC/IP address pairs.
A list entry has the following format:
.IR xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip][,] ". Multiple"
list entries are separated by a comma, specifying an IP address corresponding to
the MAC address is optional. Multiple MAC/IP address pairs with the same MAC address
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"
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"
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"
Same as
.BR --among-dst " but the list is read in from the specified file."
.TP
.BR "--among-src-file " "[!] \fIfile\fP"
Same as
.BR --among-src " but the list is read in from the specified file."
.PP
Note that in this implementation of ebtables, among lists uses must be
internally homogeneous regarding whether IP addresses are present or not. Mixed
use of MAC addresses and MAC/IP address pairs is not supported yet.
.SS arp
Specify (R)ARP fields. The protocol must be specified as
.IR ARP " or " RARP .
...
...
@@ -1108,8 +1112,8 @@ arp message and the hardware address length in the arp header is 6 bytes.
The version of ebtables this man page ships with does not support the
.B broute
table. Also there is no support for
.B
R among " and "
string
match
es
. And finally, this list is probably not complete.
.B string
match. And finally, this list is probably not complete.
.SH SEE ALSO
.BR xtables-nft "(8), " iptables "(8), " ip (8)
.PP
...
...
iptables/ip6tables.c
View file @
290749d4
...
...
@@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
#include <getopt.h>
#include <string.h>
#include <netdb.h>
...
...
@@ -45,33 +45,6 @@
#include "ip6tables-multi.h"
#include "xshared.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define CMD_NONE 0x0000U
#define CMD_INSERT 0x0001U
#define CMD_DELETE 0x0002U
#define CMD_DELETE_NUM 0x0004U
#define CMD_REPLACE 0x0008U
#define CMD_APPEND 0x0010U
#define CMD_LIST 0x0020U
#define CMD_FLUSH 0x0040U
#define CMD_ZERO 0x0080U
#define CMD_NEW_CHAIN 0x0100U
#define CMD_DELETE_CHAIN 0x0200U
#define CMD_SET_POLICY 0x0400U
#define CMD_RENAME_CHAIN 0x0800U
#define CMD_LIST_RULES 0x1000U
#define CMD_ZERO_NUM 0x2000U
#define CMD_CHECK 0x4000U
#define NUMBER_OF_CMD 16
static
const
char
cmdflags
[]
=
{
'I'
,
'D'
,
'D'
,
'R'
,
'A'
,
'L'
,
'F'
,
'Z'
,
'N'
,
'X'
,
'P'
,
'E'
,
'S'
,
'Z'
,
'C'
};
#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
static
const
char
optflags
[]
=
{
'n'
,
's'
,
'd'
,
'p'
,
'j'
,
'v'
,
'x'
,
'i'
,
'o'
,
'0'
,
'c'
};
...
...
@@ -121,7 +94,7 @@ static struct option original_opts[] = {
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
=
IPTABLES
_VERSION
,
.
program_version
=
PACKAGE
_VERSION
,
.
orig_opts
=
original_opts
,
.
exit_err
=
ip6tables_exit_error
,
.
compat_rev
=
xtables_compatible_revision
,
...
...
@@ -175,12 +148,6 @@ static const unsigned int inverse_for_options[NUMBER_OF_OPT] =
#define opts ip6tables_globals.opts
#define prog_name ip6tables_globals.program_name
#define prog_vers ip6tables_globals.program_version
/* A few hardcoded protocols for 'all' and in case the user has no
/etc/protocols */
struct
pprot
{
const
char
*
name
;
uint8_t
num
;
};
static
void
__attribute__
((
noreturn
))
exit_tryhelp
(
int
status
)
...
...
@@ -342,27 +309,6 @@ opt2char(int option)
return
*
ptr
;
}
static
char
cmd2char
(
int
option
)
{
const
char
*
ptr
;
for
(
ptr
=
cmdflags
;
option
>
1
;
option
>>=
1
,
ptr
++
);
return
*
ptr
;
}
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
)));
*
cmd
|=
newcmd
;
}
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
...
...
@@ -381,19 +327,6 @@ static int is_exthdr(uint16_t proto)
proto
==
IPPROTO_DSTOPTS
);
}
/* Can't be zero. */
static
int
parse_rulenumber
(
const
char
*
rule
)
{
unsigned
int
rulenum
;
if
(
!
xtables_strtoui
(
rule
,
NULL
,
&
rulenum
,
1
,
INT_MAX
))
xtables_error
(
PARAMETER_PROBLEM
,
"Invalid rule number `%s'"
,
rule
);
return
rulenum
;
}
static
void
parse_chain
(
const
char
*
chainname
)
{
...
...
@@ -1228,6 +1161,7 @@ int do_command6(int argc, char *argv[], char **table,
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 */
...
...
@@ -1508,7 +1442,12 @@ int do_command6(int argc, char *argv[], char **table,
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'
:
...
...
@@ -1578,7 +1517,7 @@ int do_command6(int argc, char *argv[], char **table,
xtables_error
(
PARAMETER_PROBLEM
,
"multiple consecutive ! not"
" allowed"
);
cs
.
invert
=
TRUE
;
cs
.
invert
=
true
;
optarg
[
0
]
=
'\0'
;
continue
;
}
...
...
@@ -1590,12 +1529,12 @@ int do_command6(int argc, char *argv[], char **table,
/*
* If new options were loaded, we must retry
* getopt immediately and not allow
* cs.invert=
FALSE
to be executed.
* cs.invert=
false
to be executed.
*/
continue
;
break
;
}
cs
.
invert
=
FALSE
;
cs
.
invert
=
false
;
}
if
(
!
wait
&&
wait_interval_set
)
...
...
iptables/iptables-restore.c
View file @
290749d4
...
...
@@ -4,7 +4,7 @@
*
* This code is distributed under the terms of GNU GPL v2
*/
#include "config.h"
#include <getopt.h>
#include <errno.h>
#include <stdbool.h>
...
...
@@ -43,7 +43,7 @@ static const struct option options[] = {
static
void
print_usage
(
const
char
*
name
,
const
char
*
version
)
{
fprintf
(
stderr
,
"Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]
\n
"
fprintf
(
stderr
,
"Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]
[file]
\n
"
" [ --counters ]
\n
"
" [ --verbose ]
\n
"
" [ --version]
\n
"
...
...
@@ -70,7 +70,7 @@ struct iptables_restore_cb {
};
static
struct
xtc_handle
*
create_handle
(
struct
iptables_restore_cb
*
cb
,
const
char
*
tablename
)
create_handle
(
const
struct
iptables_restore_cb
*
cb
,
const
char
*
tablename
)
{
struct
xtc_handle
*
handle
;
...
...
@@ -82,18 +82,19 @@ create_handle(struct iptables_restore_cb *cb, const char *tablename)
handle
=
cb
->
ops
->
init
(
tablename
);
}
if
(
!
handle
)
{
if
(
!
handle
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: unable to initialize "
"table '%s'
\n
"
,
xt_params
->
program_name
,
tablename
);
exit
(
1
);
}
return
handle
;
}
static
int
ip46tables_restore_main
(
struct
iptables_restore_cb
*
cb
,
int
argc
,
char
*
argv
[])
ip46tables_restore_main
(
const
struct
iptables_restore_cb
*
cb
,
int
argc
,
char
*
argv
[])
{
struct
xtc_handle
*
handle
=
NULL
;
struct
argv_store
av_store
=
{};
char
buffer
[
10240
];
int
c
,
lock
;
char
curtable
[
XT_TABLE_MAXNAMELEN
+
1
]
=
{};
...
...
@@ -125,7 +126,7 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
break
;
case
'h'
:
print_usage
(
xt_params
->
program_name
,
IPTABLES
_VERSION
);
PACKAGE
_VERSION
);
exit
(
0
);
case
'n'
:
noflush
=
1
;
...
...
@@ -207,12 +208,11 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
table
=
strtok
(
buffer
+
1
,
"
\t\n
"
);
DEBUGP
(
"line %u, table '%s'
\n
"
,
line
,
table
);
if
(
!
table
)
{
if
(
!
table
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: line %u table name invalid
\n
"
,
xt_params
->
program_name
,
line
);
exit
(
1
);
}
strncpy
(
curtable
,
table
,
XT_TABLE_MAXNAMELEN
);
curtable
[
XT_TABLE_MAXNAMELEN
]
=
'\0'
;
...
...
@@ -248,12 +248,10 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
chain
=
strtok
(
buffer
+
1
,
"
\t\n
"
);
DEBUGP
(
"line %u, chain '%s'
\n
"
,
line
,
chain
);
if
(
!
chain
)
{
if
(
!
chain
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: line %u chain name invalid
\n
"
,
xt_params
->
program_name
,
line
);
exit
(
1
);
}
if
(
strlen
(
chain
)
>=
XT_EXTENSION_MAXNAMELEN
)
xtables_error
(
PARAMETER_PROBLEM
,
...
...
@@ -281,12 +279,10 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
policy
=
strtok
(
NULL
,
"
\t\n
"
);
DEBUGP
(
"line %u, policy '%s'
\n
"
,
line
,
policy
);
if
(
!
policy
)
{
if
(
!
policy
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: line %u policy invalid
\n
"
,
xt_params
->
program_name
,
line
);
exit
(
1
);
}
if
(
strcmp
(
policy
,
"-"
)
!=
0
)
{
struct
xt_counters
count
=
{};
...
...
@@ -316,61 +312,31 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
ret
=
1
;
}
else
if
(
in_table
)
{
int
a
;
char
*
pcnt
=
NULL
;
char
*
bcnt
=
NULL
;
char
*
parsestart
;
char
*
parsestart
=
buffer
;
if
(
buffer
[
0
]
==
'['
)
{
/* we have counters in our input */
char
*
ptr
=
strchr
(
buffer
,
']'
);
if
(
!
ptr
)
xtables_error
(
PARAMETER_PROBLEM
,
"Bad line %u: need ]
\n
"
,
line
);
pcnt
=
strtok
(
buffer
+
1
,
":"
);
if
(
!
pcnt
)
xtables_error
(
PARAMETER_PROBLEM
,
"Bad line %u: need :
\n
"
,
line
);
bcnt
=
strtok
(
NULL
,
"]"
);
if
(
!
bcnt
)
xtables_error
(
PARAMETER_PROBLEM
,
"Bad line %u: need ]
\n
"
,
line
);
/* start command parsing after counter */
parsestart
=
ptr
+
1
;
}
else
{
/* start command parsing at start of line */
parsestart
=
buffer
;
}
add_argv
(
argv
[
0
],
0
);
add_argv
(
"-t"
,
0
);
add_argv
(
curtable
,
0
);
add_argv
(
&
av_store
,
argv
[
0
],
0
);
add_argv
(
&
av_store
,
"-t"
,
0
);
add_argv
(
&
av_store
,
curtable
,
0
);
tokenize_rule_counters
(
&
parsestart
,
&
pcnt
,
&
bcnt
,
line
);
if
(
counters
&&
pcnt
&&
bcnt
)
{
add_argv
(
"--set-counters"
,
0
);
add_argv
(
(
char
*
)
pcnt
,
0
);
add_argv
(
(
char
*
)
bcnt
,
0
);
add_argv
(
&
av_store
,
"--set-counters"
,
0
);
add_argv
(
&
av_store
,
pcnt
,
0
);
add_argv
(
&
av_store
,
bcnt
,
0
);
}
add_param_to_argv
(
parsestart
,
line
);
add_param_to_argv
(
&
av_store
,
parsestart
,
line
);
DEBUGP
(
"calling do_command(%u, argv, &%s, handle):
\n
"
,
newargc
,
curtable
);
for
(
a
=
0
;
a
<
newargc
;
a
++
)
DEBUGP
(
"argv[%u]: %s
\n
"
,
a
,
newargv
[
a
]);
av_store
.
argc
,
curtable
);
debug_print_argv
(
&
av_store
);
ret
=
cb
->
do_command
(
newargc
,
new
argv
,
&
new
argv
[
2
],
&
handle
,
true
);
ret
=
cb
->
do_command
(
av_store
.
argc
,
av_store
.
argv
,
&
av_store
.
argv
[
2
],
&
handle
,
true
);
free_argv
();
free_argv
(
&
av_store
);
fflush
(
stdout
);
}
if
(
tablename
&&
strcmp
(
tablename
,
curtable
)
!=
0
)
...
...
@@ -393,7 +359,7 @@ ip46tables_restore_main(struct iptables_restore_cb *cb, int argc, char *argv[])
#if defined ENABLE_IPV4
struct
iptables_restore_cb
ipt_restore_cb
=
{
static
const
struct
iptables_restore_cb
ipt_restore_cb
=
{
.
ops
=
&
iptc_ops
,
.
for_each_chain
=
for_each_chain4
,
.
flush_entries
=
flush_entries4
,
...
...
@@ -424,7 +390,7 @@ iptables_restore_main(int argc, char *argv[])
#endif
#if defined ENABLE_IPV6
struct
iptables_restore_cb
ip6t_restore_cb
=
{
static
const
struct
iptables_restore_cb
ip6t_restore_cb
=
{
.
ops
=
&
ip6tc_ops
,
.
for_each_chain
=
for_each_chain6
,
.
flush_entries
=
flush_entries6
,
...
...
iptables/iptables-save.c
View file @
290749d4
...
...
@@ -5,6 +5,7 @@
* This code is distributed under the terms of GNU GPL v2
*
*/
#include "config.h"
#include <getopt.h>
#include <errno.h>
#include <stdio.h>
...
...
@@ -90,7 +91,7 @@ static int do_output(struct iptables_save_cb *cb, const char *tablename)
time_t
now
=
time
(
NULL
);
printf
(
"# Generated by %s v%s on %s"
,
xt_params
->
program_name
,
IPTABLES
_VERSION
,
ctime
(
&
now
));
xt_params
->
program_name
,
PACKAGE
_VERSION
,
ctime
(
&
now
));
printf
(
"*%s
\n
"
,
tablename
);
/* Dump out chain names first,
...
...
iptables/iptables-xml.c
View file @
290749d4
...
...
@@ -5,7 +5,7 @@
*
* This code is distributed under the terms of GNU GPL v2
*/
#include "config.h"
#include <getopt.h>
#include <errno.h>
#include <string.h>
...
...
@@ -20,7 +20,7 @@
struct
xtables_globals
iptables_xml_globals
=
{
.
option_offset
=
0
,
.
program_version
=
IPTABLES
_VERSION
,
.
program_version
=
PACKAGE
_VERSION
,
.
program_name
=
"iptables-xml"
,
};
#define prog_name iptables_xml_globals.program_name
...
...
@@ -208,12 +208,11 @@ needChain(char *chain)
static
void
saveChain
(
char
*
chain
,
char
*
policy
,
struct
xt_counters
*
ctr
)
{
if
(
nextChain
>=
maxChains
)
{
if
(
nextChain
>=
maxChains
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: line %u chain name invalid
\n
"
,
prog_name
,
line
);
exit
(
1
);
};
chains
[
nextChain
].
chain
=
strdup
(
chain
);
chains
[
nextChain
].
policy
=
strdup
(
policy
);
chains
[
nextChain
].
count
=
*
ctr
;
...
...
@@ -441,7 +440,7 @@ do_rule_part(char *leveltag1, char *leveltag2, int part, int argc,
}
static
int
compareRules
(
void
)
compareRules
(
int
newargc
,
char
*
newargv
[],
int
oldargc
,
char
*
oldargv
[]
)
{
/* Compare arguments up to -j or -g for match.
* NOTE: We don't want to combine actions if there were no criteria
...
...
@@ -490,11 +489,13 @@ compareRules(void)
/* has a nice parsed rule starting with -A */
static
void
do_rule
(
char
*
pcnt
,
char
*
bcnt
,
int
argc
,
char
*
argv
[],
int
argvattr
[])
do_rule
(
char
*
pcnt
,
char
*
bcnt
,
int
argc
,
char
*
argv
[],
int
argvattr
[],
int
oldargc
,
char
*
oldargv
[])
{
/* are these conditions the same as the previous rule?
* If so, skip arg straight to -j or -g */
if
(
combine
&&
argc
>
2
&&
!
isTarget
(
argv
[
2
])
&&
compareRules
())
{
if
(
combine
&&
argc
>
2
&&
!
isTarget
(
argv
[
2
])
&&
compareRules
(
argc
,
argv
,
oldargc
,
oldargv
))
{
xmlComment
(
"Combine action from next rule"
);
}
else
{
...
...
@@ -540,6 +541,7 @@ do_rule(char *pcnt, char *bcnt, int argc, char *argv[], int argvattr[])
int
iptables_xml_main
(
int
argc
,
char
*
argv
[])
{
struct
argv_store
last_rule
=
{},
cur_rule
=
{};
char
buffer
[
10240
];
int
c
;
FILE
*
in
;
...
...
@@ -557,7 +559,7 @@ iptables_xml_main(int argc, char *argv[])
verbose
=
1
;
break
;
case
'h'
:
print_usage
(
"iptables-xml"
,
IPTABLES
_VERSION
);
print_usage
(
"iptables-xml"
,
PACKAGE
_VERSION
);
break
;
}
}
...
...
@@ -606,12 +608,11 @@ iptables_xml_main(int argc, char *argv[])
table
=
strtok
(
buffer
+
1
,
"
\t\n
"
);
DEBUGP
(
"line %u, table '%s'
\n
"
,
line
,
table
);
if
(
!
table
)
{
if
(
!
table
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: line %u table name invalid
\n
"
,
prog_name
,
line
);
exit
(
1
);
}
openTable
(
table
);
ret
=
1
;
...
...
@@ -623,23 +624,19 @@ iptables_xml_main(int argc, char *argv[])
chain
=
strtok
(
buffer
+
1
,
"
\t\n
"
);
DEBUGP
(
"line %u, chain '%s'
\n
"
,
line
,
chain
);
if
(
!
chain
)
{
if
(
!
chain
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: line %u chain name invalid
\n
"
,
prog_name
,
line
);
exit
(
1
);
}
DEBUGP
(
"Creating new chain '%s'
\n
"
,
chain
);
policy
=
strtok
(
NULL
,
"
\t\n
"
);
DEBUGP
(
"line %u, policy '%s'
\n
"
,
line
,
policy
);
if
(
!
policy
)
{
if
(
!
policy
)
xtables_error
(
PARAMETER_PROBLEM
,
"%s: line %u policy invalid
\n
"
,
prog_name
,
line
);
exit
(
1
);
}
ctrs
=
strtok
(
NULL
,
"
\t\n
"
);
parse_counters
(
ctrs
,
&
count
);
...
...
@@ -650,126 +647,32 @@ iptables_xml_main(int argc, char *argv[])
unsigned
int
a
;
char
*
pcnt
=
NULL
;
char
*
bcnt
=
NULL
;
char
*
parsestart
;
char
*
parsestart
=
buffer
;
char
*
chain
=
NULL
;
/* the parser */
char
*
param_start
,
*
curchar
;
int
quote_open
,
quoted
;
char
param_buffer
[
1024
];
if
(
buffer
[
0
]
==
'['
)
{
/* we have counters in our input */
char
*
ptr
=
strchr
(
buffer
,
']'
);
if
(
!
ptr
)
xtables_error
(
PARAMETER_PROBLEM
,
"Bad line %u: need ]
\n
"
,
line
);
pcnt
=
strtok
(
buffer
+
1
,
":"
);
if
(
!
pcnt
)
xtables_error
(
PARAMETER_PROBLEM
,
"Bad line %u: need :
\n
"
,
line
);
bcnt
=
strtok
(
NULL
,
"]"
);
if
(
!
bcnt
)
xtables_error
(
PARAMETER_PROBLEM
,
"Bad line %u: need ]
\n
"
,
line
);
tokenize_rule_counters
(
&
parsestart
,
&
pcnt
,
&
bcnt
,
line
);
add_param_to_argv
(
&
cur_rule
,
parsestart
,
line
);
/* start command parsing after counter */
parsestart
=
ptr
+
1
;
}
else
{
/* start command parsing at start of line */
parsestart
=
buffer
;
}
/* This is a 'real' parser crafted in artist mode
* not hacker mode. If the author can live with that
* then so can everyone else */
quote_open
=
0
;
/* We need to know which args were quoted so we
can preserve quote */
quoted
=
0
;
param_start
=
parsestart
;
for
(
curchar
=
parsestart
;
*
curchar
;
curchar
++
)
{
if
(
*
curchar
==
'"'
)
{
/* quote_open cannot be true if there
* was no previous character. Thus,
* curchar-1 has to be within bounds */
if
(
quote_open
&&
*
(
curchar
-
1
)
!=
'\\'
)
{
quote_open
=
0
;
*
curchar
=
' '
;
}
else
{
quote_open
=
1
;
quoted
=
1
;
param_start
++
;
}
}
if
(
*
curchar
==
' '
||
*
curchar
==
'\t'
||
*
curchar
==
'\n'
)
{
int
param_len
=
curchar
-
param_start
;
if
(
quote_open
)
continue
;
DEBUGP
(
"calling do_command4(%u, argv, &%s, handle):
\n
"
,
cur_rule
.
argc
,
curTable
);
debug_print_argv
(
&
cur_rule
);
if
(
!
param_len
)
{
/* two spaces? */
param_start
++
;
for
(
a
=
1
;
a
<
cur_rule
.
argc
;
a
++
)
{
if
(
strcmp
(
cur_rule
.
argv
[
a
-
1
],
"-A"
))
continue
;
chain
=
cur_rule
.
argv
[
a
];
break
;
}
/* end of one parameter */
strncpy
(
param_buffer
,
param_start
,
param_len
);
*
(
param_buffer
+
param_len
)
=
'\0'
;
/* check if table name specified */
if
((
param_buffer
[
0
]
==
'-'
&&
param_buffer
[
1
]
!=
'-'
&&
strchr
(
param_buffer
,
't'
))
||
(
!
strncmp
(
param_buffer
,
"--t"
,
3
)
&&
!
strncmp
(
param_buffer
,
"--table"
,
strlen
(
param_buffer
))))
{
xtables_error
(
PARAMETER_PROBLEM
,
"Line %u seems to have a "
"-t table option.
\n
"
,
line
);
exit
(
1
);
}
add_argv
(
param_buffer
,
quoted
);
if
(
newargc
>=
2
&&
0
==
strcmp
(
newargv
[
newargc
-
2
],
"-A"
))
chain
=
newargv
[
newargc
-
1
];
quoted
=
0
;
param_start
+=
param_len
+
1
;
}
else
{
/* regular character, skip */
}
}
DEBUGP
(
"calling do_command4(%u, argv, &%s, handle):
\n
"
,
newargc
,
curTable
);
for
(
a
=
0
;
a
<
newargc
;
a
++
)
DEBUGP
(
"argv[%u]: %s
\n
"
,
a
,
newargv
[
a
]);
if
(
!
chain
)
{
fprintf
(
stderr
,
"%s: line %u failed - no chain found
\n
"
,
prog_name
,
line
);
exit
(
1
);
}
needChain
(
chain
);
// Should we explicitly look for -A
do_rule
(
pcnt
,
bcnt
,
newargc
,
newargv
,
newargvattr
);
do_rule
(
pcnt
,
bcnt
,
cur_rule
.
argc
,
cur_rule
.
argv
,
cur_rule
.
argvattr
,
last_rule
.
argc
,
last_rule
.
argv
);
save_argv
();
save_argv
(
&
last_rule
,
&
cur_rule
);
ret
=
1
;
}
if
(
!
ret
)
{
...
...
@@ -786,7 +689,7 @@ iptables_xml_main(int argc, char *argv[])
fclose
(
in
);
printf
(
"</iptables-rules>
\n
"
);
free_argv
();
free_argv
(
&
last_rule
);
return
0
;
}
iptables/iptables.c
View file @
290749d4
...
...
@@ -24,7 +24,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
#include <getopt.h>
#include <string.h>
#include <netdb.h>
...
...
@@ -41,33 +41,6 @@
#include <fcntl.h>
#include "xshared.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define CMD_NONE 0x0000U
#define CMD_INSERT 0x0001U
#define CMD_DELETE 0x0002U
#define CMD_DELETE_NUM 0x0004U
#define CMD_REPLACE 0x0008U
#define CMD_APPEND 0x0010U
#define CMD_LIST 0x0020U
#define CMD_FLUSH 0x0040U
#define CMD_ZERO 0x0080U
#define CMD_NEW_CHAIN 0x0100U
#define CMD_DELETE_CHAIN 0x0200U
#define CMD_SET_POLICY 0x0400U
#define CMD_RENAME_CHAIN 0x0800U
#define CMD_LIST_RULES 0x1000U
#define CMD_ZERO_NUM 0x2000U
#define CMD_CHECK 0x4000U
#define NUMBER_OF_CMD 16
static
const
char
cmdflags
[]
=
{
'I'
,
'D'
,
'D'
,
'R'
,
'A'
,
'L'
,
'F'
,
'Z'
,
'N'
,
'X'
,
'P'
,
'E'
,
'S'
,
'Z'
,
'C'
};
#define OPT_FRAGMENT 0x00800U
#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
static
const
char
optflags
[]
...
...
@@ -120,7 +93,7 @@ void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __a
struct
xtables_globals
iptables_globals
=
{
.
option_offset
=
0
,
.
program_version
=
IPTABLES
_VERSION
,
.
program_version
=
PACKAGE
_VERSION
,
.
orig_opts
=
original_opts
,
.
exit_err
=
iptables_exit_error
,
.
compat_rev
=
xtables_compatible_revision
,
...
...
@@ -335,27 +308,6 @@ opt2char(int option)
return
*
ptr
;
}
static
char
cmd2char
(
int
option
)
{
const
char
*
ptr
;
for
(
ptr
=
cmdflags
;
option
>
1
;
option
>>=
1
,
ptr
++
);
return
*
ptr
;
}
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
)));
*
cmd
|=
newcmd
;
}
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
...
...
@@ -366,18 +318,6 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds,
*/
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
/* Can't be zero. */
static
int
parse_rulenumber
(
const
char
*
rule
)
{
unsigned
int
rulenum
;
if
(
!
xtables_strtoui
(
rule
,
NULL
,
&
rulenum
,
1
,
INT_MAX
))
xtables_error
(
PARAMETER_PROBLEM
,
"Invalid rule number `%s'"
,
rule
);
return
rulenum
;
}
static
void
parse_chain
(
const
char
*
chainname
)
...
...
@@ -1217,6 +1157,7 @@ int do_command4(int argc, char *argv[], char **table,
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 */
...
...
@@ -1494,7 +1435,12 @@ int do_command4(int argc, char *argv[], char **table,
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'
:
...
...
@@ -1564,7 +1510,7 @@ int do_command4(int argc, char *argv[], char **table,
xtables_error
(
PARAMETER_PROBLEM
,
"multiple consecutive ! not"
" allowed"
);
cs
.
invert
=
TRUE
;
cs
.
invert
=
true
;
optarg
[
0
]
=
'\0'
;
continue
;
}
...
...
@@ -1577,7 +1523,7 @@ int do_command4(int argc, char *argv[], char **table,
continue
;
break
;
}
cs
.
invert
=
FALSE
;
cs
.
invert
=
false
;
}
if
(
!
wait
&&
wait_interval_set
)
...
...
iptables/nft-arp.c
View file @
290749d4
...
...
@@ -114,29 +114,6 @@ mask_to_dotted(const struct in_addr *mask)
return
buf
;
}
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
void
print_mac_and_mask
(
const
unsigned
char
*
mac
,
const
unsigned
char
*
mask
,
int
l
)
{
int
i
;
print_mac
(
mac
,
l
);
for
(
i
=
0
;
i
<
l
;
i
++
)
if
(
mask
[
i
]
!=
255
)
break
;
if
(
i
==
l
)
return
;
printf
(
"/"
);
print_mac
(
mask
,
l
);
}
static
bool
need_devaddr
(
struct
arpt_devaddr_info
*
info
)
{
int
i
;
...
...
@@ -149,7 +126,7 @@ static bool need_devaddr(struct arpt_devaddr_info *info)
return
false
;
}
static
int
nft_arp_add
(
struct
nftnl_rule
*
r
,
void
*
data
)
static
int
nft_arp_add
(
struct
nft_handle
*
h
,
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
iptables_command_state
*
cs
=
data
;
struct
arpt_entry
*
fw
=
&
cs
->
arp
;
...
...
@@ -506,8 +483,8 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
printf
(
"%s%s"
,
sep
,
fw
->
arp
.
invflags
&
ARPT_INV_SRCDEVADDR
?
"! "
:
""
);
printf
(
"--src-mac "
);
print_mac_and_mask
((
unsigned
char
*
)
fw
->
arp
.
src_devaddr
.
addr
,
(
unsigned
char
*
)
fw
->
arp
.
src_devaddr
.
mask
,
ETH_ALEN
);
xtables_
print_mac_and_mask
((
unsigned
char
*
)
fw
->
arp
.
src_devaddr
.
addr
,
(
unsigned
char
*
)
fw
->
arp
.
src_devaddr
.
mask
);
sep
=
" "
;
after_devsrc:
...
...
@@ -532,8 +509,8 @@ after_devsrc:
printf
(
"%s%s"
,
sep
,
fw
->
arp
.
invflags
&
ARPT_INV_TGTDEVADDR
?
"! "
:
""
);
printf
(
"--dst-mac "
);
print_mac_and_mask
((
unsigned
char
*
)
fw
->
arp
.
tgt_devaddr
.
addr
,
(
unsigned
char
*
)
fw
->
arp
.
tgt_devaddr
.
mask
,
ETH_ALEN
);
xtables_
print_mac_and_mask
((
unsigned
char
*
)
fw
->
arp
.
tgt_devaddr
.
addr
,
(
unsigned
char
*
)
fw
->
arp
.
tgt_devaddr
.
mask
);
sep
=
" "
;
after_devdst:
...
...
@@ -605,14 +582,15 @@ nft_arp_save_rule(const void *data, unsigned int format)
}
static
void
nft_arp_print_rule
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
)
nft_arp_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
(
"%u "
,
num
);
nft_rule_to_iptables_command_state
(
r
,
&
cs
);
nft_rule_to_iptables_command_state
(
h
,
r
,
&
cs
);
nft_arp_print_rule_details
(
&
cs
,
format
);
print_matches_and_target
(
&
cs
,
format
);
...
...
@@ -655,7 +633,7 @@ static bool nft_arp_is_same(const void *data_a,
(
unsigned
char
*
)
b
->
arp
.
outiface_mask
);
}
static
bool
nft_arp_rule_find
(
struct
nft_
family_ops
*
ops
,
struct
nftnl_rule
*
r
,
static
bool
nft_arp_rule_find
(
struct
nft_
handle
*
h
,
struct
nftnl_rule
*
r
,
void
*
data
)
{
const
struct
iptables_command_state
*
cs
=
data
;
...
...
@@ -663,7 +641,7 @@ static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
bool
ret
=
false
;
/* Delete by matching rule case */
nft_rule_to_iptables_command_state
(
r
,
&
this
);
nft_rule_to_iptables_command_state
(
h
,
r
,
&
this
);
if
(
!
nft_arp_is_same
(
&
cs
->
arp
,
&
this
.
arp
))
goto
out
;
...
...
@@ -676,7 +654,7 @@ static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
ret
=
true
;
out:
ops
->
clear_cs
(
&
this
);
h
->
ops
->
clear_cs
(
&
this
);
return
ret
;
}
...
...
iptables/nft-bridge.c
View file @
290749d4
...
...
@@ -17,12 +17,13 @@
#include <libiptc/libxtc.h>
#include <linux/netfilter/nf_tables.h>
#include <libnftnl/set.h>
#include "nft-shared.h"
#include "nft-bridge.h"
#include "nft-cache.h"
#include "nft.h"
static
bool
ebt_legacy_counter_fmt
;
void
ebt_cs_clean
(
struct
iptables_command_state
*
cs
)
{
struct
ebt_match
*
m
,
*
nm
;
...
...
@@ -128,7 +129,8 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
return
add_action
(
r
,
cs
,
false
);
}
static
int
nft_bridge_add
(
struct
nftnl_rule
*
r
,
void
*
data
)
static
int
nft_bridge_add
(
struct
nft_handle
*
h
,
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
iptables_command_state
*
cs
=
data
;
struct
ebt_match
*
iter
;
...
...
@@ -184,7 +186,7 @@ static int nft_bridge_add(struct nftnl_rule *r, void *data)
for
(
iter
=
cs
->
match_list
;
iter
;
iter
=
iter
->
next
)
{
if
(
iter
->
ismatch
)
{
if
(
add_match
(
r
,
iter
->
u
.
match
->
m
))
if
(
add_match
(
h
,
r
,
iter
->
u
.
match
->
m
))
break
;
}
else
{
if
(
add_target
(
r
,
iter
->
u
.
watcher
->
t
))
...
...
@@ -292,6 +294,212 @@ static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto,
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
);
struct
nftnl_set_list
*
slist
;
slist
=
nft_set_list_get
(
ctx
->
h
,
ctx
->
table
,
set_name
);
if
(
slist
)
return
nftnl_set_list_lookup_byname
(
slist
,
set_name
);
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
)
{
...
...
@@ -334,11 +542,12 @@ static void nft_bridge_parse_target(struct xtables_target *t, void *data)
cs
->
target
=
t
;
}
static
void
nft_rule_to_ebtables_command_state
(
const
struct
nftnl_rule
*
r
,
static
void
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
(
r
,
cs
);
nft_rule_to_iptables_command_state
(
h
,
r
,
cs
);
}
static
void
print_iface
(
const
char
*
option
,
const
char
*
name
,
bool
invert
)
...
...
@@ -422,22 +631,6 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
printf
(
"%s "
,
ent
->
e_name
);
}
static
void
nft_bridge_save_counters
(
const
void
*
data
)
{
const
char
*
ctr
;
if
(
ebt_legacy_counter_fmt
)
return
;
ctr
=
getenv
(
"EBTABLES_SAVE_COUNTER"
);
if
(
ctr
)
{
ebt_legacy_counter_fmt
=
true
;
return
;
}
save_counters
(
data
);
}
static
void
nft_bridge_save_rule
(
const
void
*
data
,
unsigned
int
format
)
{
const
struct
iptables_command_state
*
cs
=
data
;
...
...
@@ -474,29 +667,30 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
cs
->
target
->
print
(
&
cs
->
fw
,
cs
->
target
->
t
,
format
&
FMT_NUMERIC
);
}
if
((
format
&
(
FMT_NOCOUNTS
|
FMT_C_COUNTS
))
==
FMT_C_COUNTS
)
{
if
(
format
&
FMT_EBT_SAVE
)
printf
(
" -c %"
PRIu64
" %"
PRIu64
""
,
(
uint64_t
)
cs
->
counters
.
pcnt
,
(
uint64_t
)
cs
->
counters
.
bcnt
);
if
(
!
(
format
&
FMT_NOCOUNTS
))
else
printf
(
" , pcnt = %"
PRIu64
" -- bcnt = %"
PRIu64
""
,
(
uint64_t
)
cs
->
counters
.
pcnt
,
(
uint64_t
)
cs
->
counters
.
bcnt
);
}
if
(
!
(
format
&
FMT_NONEWLINE
))
fputc
(
'\n'
,
stdout
);
}
static
void
nft_bridge_print_rule
(
struct
nft
nl_ru
le
*
r
,
unsigned
int
num
,
unsigned
int
format
)
static
void
nft_bridge_print_rule
(
struct
nft
_hand
le
*
h
,
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
)
{
struct
iptables_command_state
cs
=
{};
if
(
format
&
FMT_LINENUMBERS
)
printf
(
"%d "
,
num
);
nft_rule_to_ebtables_command_state
(
r
,
&
cs
);
nft_rule_to_ebtables_command_state
(
h
,
r
,
&
cs
);
nft_bridge_save_rule
(
&
cs
,
format
);
ebt_cs_clean
(
&
cs
);
}
...
...
@@ -553,14 +747,14 @@ static bool nft_bridge_is_same(const void *data_a, const void *data_b)
return
strcmp
(
a
->
in
,
b
->
in
)
==
0
&&
strcmp
(
a
->
out
,
b
->
out
)
==
0
;
}
static
bool
nft_bridge_rule_find
(
struct
nft_
family_ops
*
ops
,
struct
nftnl_rule
*
r
,
static
bool
nft_bridge_rule_find
(
struct
nft_
handle
*
h
,
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
iptables_command_state
*
cs
=
data
;
struct
iptables_command_state
this
=
{};
bool
ret
=
false
;
nft_rule_to_ebtables_command_state
(
r
,
&
this
);
nft_rule_to_ebtables_command_state
(
h
,
r
,
&
this
);
DEBUGP
(
"comparing with... "
);
...
...
@@ -584,7 +778,7 @@ static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nftnl_rule *
ret
=
true
;
out:
ops
->
clear_cs
(
&
this
);
h
->
ops
->
clear_cs
(
&
this
);
return
ret
;
}
...
...
@@ -757,13 +951,14 @@ struct nft_family_ops nft_family_ops_bridge = {
.
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
,
.
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_counters
=
nft_bridge_
save_counters
,
.
save_counters
=
save_counters
,
.
save_chain
=
nft_bridge_save_chain
,
.
post_parse
=
NULL
,
.
rule_to_cs
=
nft_rule_to_ebtables_command_state
,
...
...
iptables/nft-bridge.h
View file @
290749d4
...
...
@@ -122,4 +122,60 @@ void ebt_add_watcher(struct xtables_target *watcher,
struct
iptables_command_state
*
cs
);
int
ebt_command_default
(
struct
iptables_command_state
*
cs
);
struct
nft_among_pair
{
struct
ether_addr
ether
;
struct
in_addr
in
__attribute__
((
aligned
(
4
)));
};
struct
nft_among_data
{
struct
{
size_t
cnt
;
bool
inv
;
bool
ip
;
}
src
,
dst
;
/* first source, then dest pairs */
struct
nft_among_pair
pairs
[
0
];
};
/* initialize fields, return offset into pairs array to write pairs to */
static
inline
size_t
nft_among_prepare_data
(
struct
nft_among_data
*
data
,
bool
dst
,
size_t
cnt
,
bool
inv
,
bool
ip
)
{
size_t
poff
;
if
(
dst
)
{
data
->
dst
.
cnt
=
cnt
;
data
->
dst
.
inv
=
inv
;
data
->
dst
.
ip
=
ip
;
poff
=
data
->
src
.
cnt
;
}
else
{
data
->
src
.
cnt
=
cnt
;
data
->
src
.
inv
=
inv
;
data
->
src
.
ip
=
ip
;
poff
=
0
;
memmove
(
data
->
pairs
+
cnt
,
data
->
pairs
,
data
->
dst
.
cnt
*
sizeof
(
*
data
->
pairs
));
}
return
poff
;
}
static
inline
void
nft_among_insert_pair
(
struct
nft_among_pair
*
pairs
,
size_t
*
pcount
,
const
struct
nft_among_pair
*
new
)
{
int
i
;
/* nftables automatically sorts set elements from smallest to largest,
* insert sorted so extension comparison works */
for
(
i
=
0
;
i
<
*
pcount
;
i
++
)
{
if
(
memcmp
(
new
,
&
pairs
[
i
],
sizeof
(
*
new
))
<
0
)
break
;
}
memmove
(
&
pairs
[
i
+
1
],
&
pairs
[
i
],
sizeof
(
*
pairs
)
*
(
*
pcount
-
i
));
memcpy
(
&
pairs
[
i
],
new
,
sizeof
(
*
new
));
(
*
pcount
)
++
;
}
#endif
iptables/nft-cache.c
0 → 100644
View file @
290749d4
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* 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 <assert.h>
#include <errno.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter/nf_tables.h>
#include <libmnl/libmnl.h>
#include <libnftnl/gen.h>
#include <libnftnl/set.h>
#include <libnftnl/table.h>
#include "nft.h"
#include "nft-cache.h"
static
int
genid_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
{
uint32_t
*
genid
=
data
;
struct
nftnl_gen
*
gen
;
gen
=
nftnl_gen_alloc
();
if
(
!
gen
)
return
MNL_CB_ERROR
;
if
(
nftnl_gen_nlmsg_parse
(
nlh
,
gen
)
<
0
)
goto
out
;
*
genid
=
nftnl_gen_get_u32
(
gen
,
NFTNL_GEN_ID
);
nftnl_gen_free
(
gen
);
return
MNL_CB_STOP
;
out:
nftnl_gen_free
(
gen
);
return
MNL_CB_ERROR
;
}
static
void
mnl_genid_get
(
struct
nft_handle
*
h
,
uint32_t
*
genid
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
struct
nlmsghdr
*
nlh
;
int
ret
;
nlh
=
nftnl_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETGEN
,
0
,
0
,
h
->
seq
);
ret
=
mnl_talk
(
h
,
nlh
,
genid_cb
,
genid
);
if
(
ret
==
0
)
return
;
xtables_error
(
RESOURCE_PROBLEM
,
"Could not fetch rule set generation id: %s
\n
"
,
nft_strerror
(
errno
));
}
static
int
nftnl_table_list_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
{
struct
nftnl_table
*
t
;
struct
nftnl_table_list
*
list
=
data
;
t
=
nftnl_table_alloc
();
if
(
t
==
NULL
)
goto
err
;
if
(
nftnl_table_nlmsg_parse
(
nlh
,
t
)
<
0
)
goto
out
;
nftnl_table_list_add_tail
(
t
,
list
);
return
MNL_CB_OK
;
out:
nftnl_table_free
(
t
);
err:
return
MNL_CB_OK
;
}
static
int
fetch_table_cache
(
struct
nft_handle
*
h
)
{
char
buf
[
16536
];
struct
nlmsghdr
*
nlh
;
struct
nftnl_table_list
*
list
;
int
ret
;
if
(
h
->
cache
->
tables
)
return
0
;
list
=
nftnl_table_list_alloc
();
if
(
list
==
NULL
)
return
0
;
nlh
=
nftnl_rule_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETTABLE
,
h
->
family
,
NLM_F_DUMP
,
h
->
seq
);
ret
=
mnl_talk
(
h
,
nlh
,
nftnl_table_list_cb
,
list
);
if
(
ret
<
0
&&
errno
==
EINTR
)
assert
(
nft_restart
(
h
)
>=
0
);
h
->
cache
->
tables
=
list
;
return
1
;
}
struct
nftnl_chain_list_cb_data
{
struct
nft_handle
*
h
;
const
struct
builtin_table
*
t
;
};
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
;
const
char
*
tname
,
*
cname
;
struct
nftnl_chain
*
c
;
c
=
nftnl_chain_alloc
();
if
(
c
==
NULL
)
goto
err
;
if
(
nftnl_chain_nlmsg_parse
(
nlh
,
c
)
<
0
)
goto
out
;
tname
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_TABLE
);
if
(
!
t
)
{
t
=
nft_table_builtin_find
(
h
,
tname
);
if
(
!
t
)
goto
out
;
}
else
if
(
strcmp
(
t
->
name
,
tname
))
{
goto
out
;
}
list
=
h
->
cache
->
table
[
t
->
type
].
chains
;
cname
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_NAME
);
if
(
nftnl_chain_list_lookup_byname
(
list
,
cname
))
goto
out
;
nftnl_chain_list_add_tail
(
c
,
list
);
return
MNL_CB_OK
;
out:
nftnl_chain_free
(
c
);
err:
return
MNL_CB_OK
;
}
struct
nftnl_set_list_cb_data
{
struct
nft_handle
*
h
;
const
struct
builtin_table
*
t
;
};
static
int
nftnl_set_list_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
{
struct
nftnl_set_list_cb_data
*
d
=
data
;
const
struct
builtin_table
*
t
=
d
->
t
;
struct
nftnl_set_list
*
list
;
struct
nft_handle
*
h
=
d
->
h
;
const
char
*
tname
,
*
sname
;
struct
nftnl_set
*
s
;
s
=
nftnl_set_alloc
();
if
(
s
==
NULL
)
return
MNL_CB_OK
;
if
(
nftnl_set_nlmsg_parse
(
nlh
,
s
)
<
0
)
goto
out_free
;
tname
=
nftnl_set_get_str
(
s
,
NFTNL_SET_TABLE
);
if
(
!
t
)
t
=
nft_table_builtin_find
(
h
,
tname
);
else
if
(
strcmp
(
t
->
name
,
tname
))
goto
out_free
;
if
(
!
t
)
goto
out_free
;
list
=
h
->
cache
->
table
[
t
->
type
].
sets
;
sname
=
nftnl_set_get_str
(
s
,
NFTNL_SET_NAME
);
if
(
nftnl_set_list_lookup_byname
(
list
,
sname
))
goto
out_free
;
nftnl_set_list_add_tail
(
s
,
list
);
return
MNL_CB_OK
;
out_free:
nftnl_set_free
(
s
);
return
MNL_CB_OK
;
}
static
int
set_elem_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
{
return
nftnl_set_elems_nlmsg_parse
(
nlh
,
data
)
?
-
1
:
MNL_CB_OK
;
}
static
bool
set_has_elements
(
struct
nftnl_set
*
s
)
{
struct
nftnl_set_elems_iter
*
iter
;
bool
ret
=
false
;
iter
=
nftnl_set_elems_iter_create
(
s
);
if
(
iter
)
{
ret
=
!!
nftnl_set_elems_iter_cur
(
iter
);
nftnl_set_elems_iter_destroy
(
iter
);
}
return
ret
;
}
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
;
if
(
set_has_elements
(
s
))
return
0
;
nlh
=
nftnl_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETSETELEM
,
h
->
family
,
NLM_F_DUMP
,
h
->
seq
);
nftnl_set_elems_nlmsg_build_payload
(
nlh
,
s
);
return
mnl_talk
(
h
,
nlh
,
set_elem_cb
,
s
);
}
static
int
fetch_set_cache
(
struct
nft_handle
*
h
,
const
struct
builtin_table
*
t
,
const
char
*
set
)
{
struct
nftnl_set_list_cb_data
d
=
{
.
h
=
h
,
.
t
=
t
,
};
struct
nlmsghdr
*
nlh
;
char
buf
[
16536
];
int
i
,
ret
;
if
(
!
t
)
{
for
(
i
=
0
;
i
<
NFT_TABLE_MAX
;
i
++
)
{
enum
nft_table_type
type
=
h
->
tables
[
i
].
type
;
if
(
!
h
->
tables
[
i
].
name
)
continue
;
h
->
cache
->
table
[
type
].
sets
=
nftnl_set_list_alloc
();
if
(
!
h
->
cache
->
table
[
type
].
sets
)
return
-
1
;
}
}
else
if
(
!
h
->
cache
->
table
[
t
->
type
].
sets
)
{
h
->
cache
->
table
[
t
->
type
].
sets
=
nftnl_set_list_alloc
();
}
if
(
t
&&
set
)
{
struct
nftnl_set
*
s
=
nftnl_set_alloc
();
if
(
!
s
)
return
-
1
;
nlh
=
nftnl_set_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETSET
,
h
->
family
,
NLM_F_ACK
,
h
->
seq
);
nftnl_set_set_str
(
s
,
NFTNL_SET_TABLE
,
t
->
name
);
nftnl_set_set_str
(
s
,
NFTNL_SET_NAME
,
set
);
nftnl_set_nlmsg_build_payload
(
nlh
,
s
);
nftnl_set_free
(
s
);
}
else
{
nlh
=
nftnl_set_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETSET
,
h
->
family
,
NLM_F_DUMP
,
h
->
seq
);
}
ret
=
mnl_talk
(
h
,
nlh
,
nftnl_set_list_cb
,
&
d
);
if
(
ret
<
0
&&
errno
==
EINTR
)
{
assert
(
nft_restart
(
h
)
>=
0
);
return
ret
;
}
if
(
t
&&
set
)
{
struct
nftnl_set
*
s
;
s
=
nftnl_set_list_lookup_byname
(
h
->
cache
->
table
[
t
->
type
].
sets
,
set
);
set_fetch_elem_cb
(
s
,
h
);
}
else
if
(
t
)
{
nftnl_set_list_foreach
(
h
->
cache
->
table
[
t
->
type
].
sets
,
set_fetch_elem_cb
,
h
);
}
else
{
for
(
i
=
0
;
i
<
NFT_TABLE_MAX
;
i
++
)
{
enum
nft_table_type
type
=
h
->
tables
[
i
].
type
;
if
(
!
h
->
tables
[
i
].
name
)
continue
;
nftnl_set_list_foreach
(
h
->
cache
->
table
[
type
].
sets
,
set_fetch_elem_cb
,
h
);
}
}
return
ret
;
}
static
int
fetch_chain_cache
(
struct
nft_handle
*
h
,
const
struct
builtin_table
*
t
,
const
char
*
chain
)
{
struct
nftnl_chain_list_cb_data
d
=
{
.
h
=
h
,
.
t
=
t
,
};
char
buf
[
16536
];
struct
nlmsghdr
*
nlh
;
int
i
,
ret
;
if
(
!
t
)
{
for
(
i
=
0
;
i
<
NFT_TABLE_MAX
;
i
++
)
{
enum
nft_table_type
type
=
h
->
tables
[
i
].
type
;
if
(
!
h
->
tables
[
i
].
name
)
continue
;
if
(
h
->
cache
->
table
[
type
].
chains
)
continue
;
h
->
cache
->
table
[
type
].
chains
=
nftnl_chain_list_alloc
();
if
(
!
h
->
cache
->
table
[
type
].
chains
)
return
-
1
;
}
}
else
if
(
!
h
->
cache
->
table
[
t
->
type
].
chains
)
{
h
->
cache
->
table
[
t
->
type
].
chains
=
nftnl_chain_list_alloc
();
if
(
!
h
->
cache
->
table
[
t
->
type
].
chains
)
return
-
1
;
}
if
(
t
&&
chain
)
{
struct
nftnl_chain
*
c
=
nftnl_chain_alloc
();
if
(
!
c
)
return
-
1
;
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETCHAIN
,
h
->
family
,
NLM_F_ACK
,
h
->
seq
);
nftnl_chain_set_str
(
c
,
NFTNL_CHAIN_TABLE
,
t
->
name
);
nftnl_chain_set_str
(
c
,
NFTNL_CHAIN_NAME
,
chain
);
nftnl_chain_nlmsg_build_payload
(
nlh
,
c
);
nftnl_chain_free
(
c
);
}
else
{
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETCHAIN
,
h
->
family
,
NLM_F_DUMP
,
h
->
seq
);
}
ret
=
mnl_talk
(
h
,
nlh
,
nftnl_chain_list_cb
,
&
d
);
if
(
ret
<
0
&&
errno
==
EINTR
)
assert
(
nft_restart
(
h
)
>=
0
);
return
ret
;
}
static
int
nftnl_rule_list_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
{
struct
nftnl_chain
*
c
=
data
;
struct
nftnl_rule
*
r
;
r
=
nftnl_rule_alloc
();
if
(
r
==
NULL
)
return
MNL_CB_OK
;
if
(
nftnl_rule_nlmsg_parse
(
nlh
,
r
)
<
0
)
{
nftnl_rule_free
(
r
);
return
MNL_CB_OK
;
}
nftnl_chain_rule_add_tail
(
r
,
c
);
return
MNL_CB_OK
;
}
static
int
nft_rule_list_update
(
struct
nftnl_chain
*
c
,
void
*
data
)
{
struct
nft_handle
*
h
=
data
;
char
buf
[
16536
];
struct
nlmsghdr
*
nlh
;
struct
nftnl_rule
*
rule
;
int
ret
;
if
(
nftnl_rule_lookup_byindex
(
c
,
0
))
return
0
;
rule
=
nftnl_rule_alloc
();
if
(
!
rule
)
return
-
1
;
nftnl_rule_set_str
(
rule
,
NFTNL_RULE_TABLE
,
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_TABLE
));
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
);
nftnl_rule_nlmsg_build_payload
(
nlh
,
rule
);
ret
=
mnl_talk
(
h
,
nlh
,
nftnl_rule_list_cb
,
c
);
if
(
ret
<
0
&&
errno
==
EINTR
)
assert
(
nft_restart
(
h
)
>=
0
);
nftnl_rule_free
(
rule
);
if
(
h
->
family
==
NFPROTO_BRIDGE
)
nft_bridge_chain_postprocess
(
h
,
c
);
return
0
;
}
static
int
fetch_rule_cache
(
struct
nft_handle
*
h
,
const
struct
builtin_table
*
t
,
const
char
*
chain
)
{
int
i
;
if
(
t
)
{
struct
nftnl_chain_list
*
list
;
struct
nftnl_chain
*
c
;
list
=
h
->
cache
->
table
[
t
->
type
].
chains
;
if
(
chain
)
{
c
=
nftnl_chain_list_lookup_byname
(
list
,
chain
);
return
nft_rule_list_update
(
c
,
h
);
}
return
nftnl_chain_list_foreach
(
list
,
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
))
return
-
1
;
}
return
0
;
}
static
void
__nft_build_cache
(
struct
nft_handle
*
h
,
enum
nft_cache_level
level
,
const
struct
builtin_table
*
t
,
const
char
*
set
,
const
char
*
chain
)
{
uint32_t
genid_start
,
genid_stop
;
if
(
level
<=
h
->
cache_level
)
return
;
retry:
mnl_genid_get
(
h
,
&
genid_start
);
if
(
h
->
cache_level
&&
genid_start
!=
h
->
nft_genid
)
flush_chain_cache
(
h
,
NULL
);
switch
(
h
->
cache_level
)
{
case
NFT_CL_NONE
:
fetch_table_cache
(
h
);
if
(
level
==
NFT_CL_TABLES
)
break
;
/* fall through */
case
NFT_CL_TABLES
:
fetch_chain_cache
(
h
,
t
,
chain
);
if
(
level
==
NFT_CL_CHAINS
)
break
;
/* fall through */
case
NFT_CL_CHAINS
:
fetch_set_cache
(
h
,
t
,
set
);
if
(
level
==
NFT_CL_SETS
)
break
;
/* fall through */
case
NFT_CL_SETS
:
fetch_rule_cache
(
h
,
t
,
chain
);
if
(
level
==
NFT_CL_RULES
)
break
;
/* fall through */
case
NFT_CL_RULES
:
break
;
}
mnl_genid_get
(
h
,
&
genid_stop
);
if
(
genid_start
!=
genid_stop
)
{
flush_chain_cache
(
h
,
NULL
);
goto
retry
;
}
if
(
!
t
&&
!
chain
)
h
->
cache_level
=
level
;
else
if
(
h
->
cache_level
<
NFT_CL_TABLES
)
h
->
cache_level
=
NFT_CL_TABLES
;
h
->
nft_genid
=
genid_start
;
}
void
nft_build_cache
(
struct
nft_handle
*
h
,
struct
nftnl_chain
*
c
)
{
const
struct
builtin_table
*
t
;
const
char
*
table
,
*
chain
;
if
(
!
c
)
return
__nft_build_cache
(
h
,
NFT_CL_RULES
,
NULL
,
NULL
,
NULL
);
table
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_TABLE
);
chain
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_NAME
);
t
=
nft_table_builtin_find
(
h
,
table
);
__nft_build_cache
(
h
,
NFT_CL_RULES
,
t
,
NULL
,
chain
);
}
void
nft_fake_cache
(
struct
nft_handle
*
h
)
{
int
i
;
fetch_table_cache
(
h
);
for
(
i
=
0
;
i
<
NFT_TABLE_MAX
;
i
++
)
{
enum
nft_table_type
type
=
h
->
tables
[
i
].
type
;
if
(
!
h
->
tables
[
i
].
name
)
continue
;
h
->
cache
->
table
[
type
].
chains
=
nftnl_chain_list_alloc
();
}
h
->
cache_level
=
NFT_CL_RULES
;
mnl_genid_get
(
h
,
&
h
->
nft_genid
);
}
static
void
__nft_flush_cache
(
struct
nft_handle
*
h
)
{
if
(
!
h
->
cache_index
)
{
h
->
cache_index
++
;
h
->
cache
=
&
h
->
__cache
[
h
->
cache_index
];
}
else
{
flush_chain_cache
(
h
,
NULL
);
}
}
static
int
____flush_rule_cache
(
struct
nftnl_rule
*
r
,
void
*
data
)
{
nftnl_rule_list_del
(
r
);
nftnl_rule_free
(
r
);
return
0
;
}
static
int
__flush_rule_cache
(
struct
nftnl_chain
*
c
,
void
*
data
)
{
return
nftnl_rule_foreach
(
c
,
____flush_rule_cache
,
NULL
);
}
int
flush_rule_cache
(
struct
nft_handle
*
h
,
const
char
*
table
,
struct
nftnl_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
);
}
static
int
__flush_chain_cache
(
struct
nftnl_chain
*
c
,
void
*
data
)
{
nftnl_chain_list_del
(
c
);
nftnl_chain_free
(
c
);
return
0
;
}
static
int
__flush_set_cache
(
struct
nftnl_set
*
s
,
void
*
data
)
{
nftnl_set_list_del
(
s
);
nftnl_set_free
(
s
);
return
0
;
}
static
int
flush_cache
(
struct
nft_handle
*
h
,
struct
nft_cache
*
c
,
const
char
*
tablename
)
{
const
struct
builtin_table
*
table
;
int
i
;
if
(
tablename
)
{
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
);
if
(
c
->
table
[
table
->
type
].
sets
)
nftnl_set_list_foreach
(
c
->
table
[
table
->
type
].
sets
,
__flush_set_cache
,
NULL
);
return
0
;
}
for
(
i
=
0
;
i
<
NFT_TABLE_MAX
;
i
++
)
{
if
(
h
->
tables
[
i
].
name
==
NULL
)
continue
;
if
(
!
c
->
table
[
i
].
chains
)
continue
;
nftnl_chain_list_free
(
c
->
table
[
i
].
chains
);
c
->
table
[
i
].
chains
=
NULL
;
if
(
c
->
table
[
i
].
sets
)
nftnl_set_list_free
(
c
->
table
[
i
].
sets
);
c
->
table
[
i
].
sets
=
NULL
;
}
nftnl_table_list_free
(
c
->
tables
);
c
->
tables
=
NULL
;
return
1
;
}
void
flush_chain_cache
(
struct
nft_handle
*
h
,
const
char
*
tablename
)
{
if
(
!
h
->
cache_level
)
return
;
if
(
flush_cache
(
h
,
h
->
cache
,
tablename
))
h
->
cache_level
=
NFT_CL_NONE
;
}
void
nft_rebuild_cache
(
struct
nft_handle
*
h
)
{
enum
nft_cache_level
level
=
h
->
cache_level
;
if
(
h
->
cache_level
)
__nft_flush_cache
(
h
);
h
->
cache_level
=
NFT_CL_NONE
;
__nft_build_cache
(
h
,
level
,
NULL
,
NULL
,
NULL
);
}
void
nft_release_cache
(
struct
nft_handle
*
h
)
{
if
(
h
->
cache_index
)
flush_cache
(
h
,
&
h
->
__cache
[
0
],
NULL
);
}
struct
nftnl_table_list
*
nftnl_table_list_get
(
struct
nft_handle
*
h
)
{
__nft_build_cache
(
h
,
NFT_CL_TABLES
,
NULL
,
NULL
,
NULL
);
return
h
->
cache
->
tables
;
}
struct
nftnl_set_list
*
nft_set_list_get
(
struct
nft_handle
*
h
,
const
char
*
table
,
const
char
*
set
)
{
const
struct
builtin_table
*
t
;
t
=
nft_table_builtin_find
(
h
,
table
);
if
(
!
t
)
return
NULL
;
__nft_build_cache
(
h
,
NFT_CL_RULES
,
t
,
set
,
NULL
);
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
;
__nft_build_cache
(
h
,
NFT_CL_CHAINS
,
t
,
NULL
,
chain
);
return
h
->
cache
->
table
[
t
->
type
].
chains
;
}
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment