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
dab1e98e
Commit
dab1e98e
authored
Oct 24, 2018
by
Arturo Borrero Gonzalez
Browse files
New upstream version 1.8.1
parent
f1f129da
Changes
268
Show whitespace changes
Inline
Side-by-side
iptables/iptables.c
View file @
dab1e98e
...
...
@@ -276,7 +276,7 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
va_list
args
;
va_start
(
args
,
msg
);
fprintf
(
stderr
,
"%s v%s: "
,
prog_name
,
prog_vers
);
fprintf
(
stderr
,
"%s v%s
(legacy)
: "
,
prog_name
,
prog_vers
);
vfprintf
(
stderr
,
msg
,
args
);
va_end
(
args
);
fprintf
(
stderr
,
"
\n
"
);
...
...
@@ -405,27 +405,6 @@ parse_chain(const char *chainname)
"Invalid chain name `%s'"
,
chainname
);
}
static
const
char
*
parse_target
(
const
char
*
targetname
)
{
const
char
*
ptr
;
if
(
strlen
(
targetname
)
<
1
)
xtables_error
(
PARAMETER_PROBLEM
,
"Invalid target name (too short)"
);
if
(
strlen
(
targetname
)
>=
XT_EXTENSION_MAXNAMELEN
)
xtables_error
(
PARAMETER_PROBLEM
,
"Invalid target name `%s' (%u chars max)"
,
targetname
,
XT_EXTENSION_MAXNAMELEN
-
1
);
for
(
ptr
=
targetname
;
*
ptr
;
ptr
++
)
if
(
isspace
(
*
ptr
))
xtables_error
(
PARAMETER_PROBLEM
,
"Invalid target name `%s'"
,
targetname
);
return
targetname
;
}
static
void
set_option
(
unsigned
int
*
options
,
unsigned
int
option
,
uint8_t
*
invflg
,
int
invert
)
...
...
@@ -502,19 +481,23 @@ print_match(const struct xt_entry_match *m,
const
struct
ipt_ip
*
ip
,
int
numeric
)
{
const
struct
xtables_match
*
match
=
xtables_find_match
(
m
->
u
.
user
.
name
,
XTF_TRY_LOAD
,
NULL
);
const
char
*
name
=
m
->
u
.
user
.
name
;
const
int
revision
=
m
->
u
.
user
.
revision
;
struct
xtables_match
*
match
,
*
mt
;
match
=
xtables_find_match
(
name
,
XTF_TRY_LOAD
,
NULL
);
if
(
match
)
{
if
(
match
->
print
&&
m
->
u
.
user
.
revision
==
match
->
revision
)
match
->
print
(
ip
,
m
,
numeric
);
mt
=
xtables_find_match_revision
(
name
,
XTF_TRY_LOAD
,
match
,
revision
);
if
(
mt
&&
mt
->
print
)
mt
->
print
(
ip
,
m
,
numeric
);
else
if
(
match
->
print
)
printf
(
"%s%s "
,
match
->
name
,
unsupported_rev
);
else
printf
(
"%s "
,
match
->
name
);
}
else
{
if
(
m
->
u
.
user
.
name
[
0
])
printf
(
"UNKNOWN match `%s' "
,
m
->
u
.
user
.
name
);
if
(
name
[
0
])
printf
(
"UNKNOWN match `%s' "
,
name
);
}
/* Don't stop iterating. */
return
0
;
...
...
@@ -528,10 +511,9 @@ print_firewall(const struct ipt_entry *fw,
unsigned
int
format
,
struct
xtc_handle
*
const
handle
)
{
const
struct
xtables_target
*
target
=
NULL
;
struct
xtables_target
*
target
,
*
tg
;
const
struct
xt_entry_target
*
t
;
uint8_t
flags
;
char
buf
[
BUFSIZ
];
if
(
!
iptc_is_chain
(
targname
,
handle
))
target
=
xtables_find_target
(
targname
,
XTF_TRY_LOAD
);
...
...
@@ -570,59 +552,9 @@ print_firewall(const struct ipt_entry *fw,
fputc
(
' '
,
stdout
);
}
if
(
format
&
FMT_VIA
)
{
char
iface
[
IFNAMSIZ
+
2
];
if
(
fw
->
ip
.
invflags
&
IPT_INV_VIA_IN
)
{
iface
[
0
]
=
'!'
;
iface
[
1
]
=
'\0'
;
}
else
iface
[
0
]
=
'\0'
;
if
(
fw
->
ip
.
iniface
[
0
]
!=
'\0'
)
{
strcat
(
iface
,
fw
->
ip
.
iniface
);
}
else
if
(
format
&
FMT_NUMERIC
)
strcat
(
iface
,
"*"
);
else
strcat
(
iface
,
"any"
);
printf
(
FMT
(
" %-6s "
,
"in %s "
),
iface
);
print_ifaces
(
fw
->
ip
.
iniface
,
fw
->
ip
.
outiface
,
fw
->
ip
.
invflags
,
format
);
if
(
fw
->
ip
.
invflags
&
IPT_INV_VIA_OUT
)
{
iface
[
0
]
=
'!'
;
iface
[
1
]
=
'\0'
;
}
else
iface
[
0
]
=
'\0'
;
if
(
fw
->
ip
.
outiface
[
0
]
!=
'\0'
)
{
strcat
(
iface
,
fw
->
ip
.
outiface
);
}
else
if
(
format
&
FMT_NUMERIC
)
strcat
(
iface
,
"*"
);
else
strcat
(
iface
,
"any"
);
printf
(
FMT
(
"%-6s "
,
"out %s "
),
iface
);
}
fputc
(
fw
->
ip
.
invflags
&
IPT_INV_SRCIP
?
'!'
:
' '
,
stdout
);
if
(
fw
->
ip
.
smsk
.
s_addr
==
0L
&&
!
(
format
&
FMT_NUMERIC
))
printf
(
FMT
(
"%-19s "
,
"%s "
),
"anywhere"
);
else
{
if
(
format
&
FMT_NUMERIC
)
strcpy
(
buf
,
xtables_ipaddr_to_numeric
(
&
fw
->
ip
.
src
));
else
strcpy
(
buf
,
xtables_ipaddr_to_anyname
(
&
fw
->
ip
.
src
));
strcat
(
buf
,
xtables_ipmask_to_numeric
(
&
fw
->
ip
.
smsk
));
printf
(
FMT
(
"%-19s "
,
"%s "
),
buf
);
}
fputc
(
fw
->
ip
.
invflags
&
IPT_INV_DSTIP
?
'!'
:
' '
,
stdout
);
if
(
fw
->
ip
.
dmsk
.
s_addr
==
0L
&&
!
(
format
&
FMT_NUMERIC
))
printf
(
FMT
(
"%-19s "
,
"-> %s"
),
"anywhere"
);
else
{
if
(
format
&
FMT_NUMERIC
)
strcpy
(
buf
,
xtables_ipaddr_to_numeric
(
&
fw
->
ip
.
dst
));
else
strcpy
(
buf
,
xtables_ipaddr_to_anyname
(
&
fw
->
ip
.
dst
));
strcat
(
buf
,
xtables_ipmask_to_numeric
(
&
fw
->
ip
.
dmsk
));
printf
(
FMT
(
"%-19s "
,
"-> %s"
),
buf
);
}
print_ipv4_addresses
(
fw
,
format
);
if
(
format
&
FMT_NOTABLE
)
fputs
(
" "
,
stdout
);
...
...
@@ -635,9 +567,13 @@ print_firewall(const struct ipt_entry *fw,
IPT_MATCH_ITERATE
(
fw
,
print_match
,
&
fw
->
ip
,
format
&
FMT_NUMERIC
);
if
(
target
)
{
if
(
target
->
print
&&
t
->
u
.
user
.
revision
==
target
->
revision
)
const
int
revision
=
t
->
u
.
user
.
revision
;
tg
=
xtables_find_target_revision
(
targname
,
XTF_TRY_LOAD
,
target
,
revision
);
if
(
tg
&&
tg
->
print
)
/* Print the target information. */
t
arget
->
print
(
&
fw
->
ip
,
t
,
format
&
FMT_NUMERIC
);
t
g
->
print
(
&
fw
->
ip
,
t
,
format
&
FMT_NUMERIC
);
else
if
(
target
->
print
)
printf
(
" %s%s"
,
target
->
name
,
unsupported_rev
);
}
else
if
(
t
->
u
.
target_size
!=
sizeof
(
*
t
))
...
...
@@ -1025,23 +961,28 @@ print_iface(char letter, const char *iface, const unsigned char *mask,
static
int
print_match_save
(
const
struct
xt_entry_match
*
e
,
const
struct
ipt_ip
*
ip
)
{
const
struct
xtables_match
*
match
=
xtables_find_match
(
e
->
u
.
user
.
name
,
XTF_TRY_LOAD
,
NULL
);
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
)
{
printf
(
" -m %s"
,
match
->
alias
?
match
->
alias
(
e
)
:
e
->
u
.
user
.
name
);
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
(
m
atch
->
save
&&
e
->
u
.
user
.
revision
==
match
->
revision
)
m
atch
->
save
(
ip
,
e
);
if
(
m
t
&&
mt
->
save
)
m
t
->
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
"
,
e
->
u
.
user
.
name
);
name
);
exit
(
1
);
}
}
...
...
@@ -1114,9 +1055,8 @@ void print_rule4(const struct ipt_entry *e,
e
->
ip
.
invflags
&
IPT_INV_FRAG
?
" !"
:
""
);
/* Print matchinfo part */
if
(
e
->
target_offset
)
{
if
(
e
->
target_offset
)
IPT_MATCH_ITERATE
(
e
,
print_match_save
,
&
e
->
ip
);
}
/* print counters for iptables -R */
if
(
counters
<
0
)
...
...
@@ -1126,18 +1066,25 @@ void print_rule4(const struct ipt_entry *e,
target_name
=
iptc_get_target
(
e
,
h
);
t
=
ipt_get_target
((
struct
ipt_entry
*
)
e
);
if
(
t
->
u
.
user
.
name
[
0
])
{
const
struct
xtables_target
*
target
=
xtables_find_target
(
t
->
u
.
user
.
name
,
XTF_TRY_LOAD
);
const
char
*
name
=
t
->
u
.
user
.
name
;
const
int
revision
=
t
->
u
.
user
.
revision
;
struct
xtables_target
*
target
,
*
tg
,
*
tg2
;
target
=
xtables_find_target
(
name
,
XTF_TRY_LOAD
);
if
(
!
target
)
{
fprintf
(
stderr
,
"Can't find library for target `%s'
\n
"
,
t
->
u
.
user
.
name
);
name
);
exit
(
1
);
}
printf
(
" -j %s"
,
target
->
alias
?
target
->
alias
(
t
)
:
target_name
);
if
(
target
->
save
&&
t
->
u
.
user
.
revision
==
target
->
revision
)
target
->
save
(
&
e
->
ip
,
t
);
tg
=
tg2
=
xtables_find_target_revision
(
name
,
XTF_TRY_LOAD
,
target
,
revision
);
if
(
!
tg2
)
tg2
=
target
;
printf
(
" -j %s"
,
tg2
->
alias
?
tg2
->
alias
(
t
)
:
target_name
);
if
(
tg
&&
tg
->
save
)
tg
->
save
(
&
e
->
ip
,
t
);
else
if
(
target
->
save
)
printf
(
unsupported_rev
);
else
{
...
...
@@ -1148,7 +1095,7 @@ void print_rule4(const struct ipt_entry *e,
sizeof
(
struct
xt_entry_target
))
{
fprintf
(
stderr
,
"Target `%s' is missing "
"save function
\n
"
,
t
->
u
.
user
.
name
);
name
);
exit
(
1
);
}
}
...
...
@@ -1243,90 +1190,13 @@ generate_entry(const struct ipt_entry *fw,
return
e
;
}
static
void
command_jump
(
struct
iptables_command_state
*
cs
)
{
size_t
size
;
set_option
(
&
cs
->
options
,
OPT_JUMP
,
&
cs
->
fw
.
ip
.
invflags
,
cs
->
invert
);
cs
->
jumpto
=
parse_target
(
optarg
);
/* TRY_LOAD (may be chain name) */
cs
->
target
=
xtables_find_target
(
cs
->
jumpto
,
XTF_TRY_LOAD
);
if
(
cs
->
target
==
NULL
)
return
;
size
=
XT_ALIGN
(
sizeof
(
struct
xt_entry_target
))
+
cs
->
target
->
size
;
cs
->
target
->
t
=
xtables_calloc
(
1
,
size
);
cs
->
target
->
t
->
u
.
target_size
=
size
;
if
(
cs
->
target
->
real_name
==
NULL
)
{
strcpy
(
cs
->
target
->
t
->
u
.
user
.
name
,
cs
->
jumpto
);
}
else
{
/* Alias support for userspace side */
strcpy
(
cs
->
target
->
t
->
u
.
user
.
name
,
cs
->
target
->
real_name
);
if
(
!
(
cs
->
target
->
ext_flags
&
XTABLES_EXT_ALIAS
))
fprintf
(
stderr
,
"Notice: The %s target is converted into %s target "
"in rule listing and saving.
\n
"
,
cs
->
jumpto
,
cs
->
target
->
real_name
);
}
cs
->
target
->
t
->
u
.
user
.
revision
=
cs
->
target
->
revision
;
xs_init_target
(
cs
->
target
);
if
(
cs
->
target
->
x6_options
!=
NULL
)
opts
=
xtables_options_xfrm
(
iptables_globals
.
orig_opts
,
opts
,
cs
->
target
->
x6_options
,
&
cs
->
target
->
option_offset
);
else
opts
=
xtables_merge_options
(
iptables_globals
.
orig_opts
,
opts
,
cs
->
target
->
extra_opts
,
&
cs
->
target
->
option_offset
);
if
(
opts
==
NULL
)
xtables_error
(
OTHER_PROBLEM
,
"can't alloc memory!"
);
}
static
void
command_match
(
struct
iptables_command_state
*
cs
)
{
struct
xtables_match
*
m
;
size_t
size
;
if
(
cs
->
invert
)
xtables_error
(
PARAMETER_PROBLEM
,
"unexpected ! flag before --match"
);
m
=
xtables_find_match
(
optarg
,
XTF_LOAD_MUST_SUCCEED
,
&
cs
->
matches
);
size
=
XT_ALIGN
(
sizeof
(
struct
xt_entry_match
))
+
m
->
size
;
m
->
m
=
xtables_calloc
(
1
,
size
);
m
->
m
->
u
.
match_size
=
size
;
if
(
m
->
real_name
==
NULL
)
{
strcpy
(
m
->
m
->
u
.
user
.
name
,
m
->
name
);
}
else
{
strcpy
(
m
->
m
->
u
.
user
.
name
,
m
->
real_name
);
if
(
!
(
m
->
ext_flags
&
XTABLES_EXT_ALIAS
))
fprintf
(
stderr
,
"Notice: the %s match is converted into %s match "
"in rule listing and saving.
\n
"
,
m
->
name
,
m
->
real_name
);
}
m
->
m
->
u
.
user
.
revision
=
m
->
revision
;
xs_init_match
(
m
);
if
(
m
==
m
->
next
)
return
;
/* Merge options for non-cloned matches */
if
(
m
->
x6_options
!=
NULL
)
opts
=
xtables_options_xfrm
(
iptables_globals
.
orig_opts
,
opts
,
m
->
x6_options
,
&
m
->
option_offset
);
else
if
(
m
->
extra_opts
!=
NULL
)
opts
=
xtables_merge_options
(
iptables_globals
.
orig_opts
,
opts
,
m
->
extra_opts
,
&
m
->
option_offset
);
if
(
opts
==
NULL
)
xtables_error
(
OTHER_PROBLEM
,
"can't alloc memory!"
);
}
int
do_command4
(
int
argc
,
char
*
argv
[],
char
**
table
,
struct
xtc_handle
**
handle
,
bool
restore
)
{
struct
iptables_command_state
cs
;
struct
iptables_command_state
cs
=
{
.
jumpto
=
""
,
.
argv
=
argv
,
};
struct
ipt_entry
*
e
=
NULL
;
unsigned
int
nsaddrs
=
0
,
ndaddrs
=
0
;
struct
in_addr
*
saddrs
=
NULL
,
*
smasks
=
NULL
;
...
...
@@ -1348,10 +1218,6 @@ int do_command4(int argc, char *argv[], char **table,
struct
xtables_target
*
t
;
unsigned
long
long
cnt
;
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
;
...
...
@@ -1393,8 +1259,7 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_DELETE
,
CMD_NONE
,
cs
.
invert
);
chain
=
optarg
;
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
{
if
(
xs_has_arg
(
argc
,
argv
))
{
rulenum
=
parse_rulenumber
(
argv
[
optind
++
]);
command
=
CMD_DELETE_NUM
;
}
...
...
@@ -1404,8 +1269,7 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_REPLACE
,
CMD_NONE
,
cs
.
invert
);
chain
=
optarg
;
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
xs_has_arg
(
argc
,
argv
))
rulenum
=
parse_rulenumber
(
argv
[
optind
++
]);
else
xtables_error
(
PARAMETER_PROBLEM
,
...
...
@@ -1417,8 +1281,7 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_INSERT
,
CMD_NONE
,
cs
.
invert
);
chain
=
optarg
;
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
xs_has_arg
(
argc
,
argv
))
rulenum
=
parse_rulenumber
(
argv
[
optind
++
]);
else
rulenum
=
1
;
break
;
...
...
@@ -1427,11 +1290,9 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_LIST
,
CMD_ZERO
|
CMD_ZERO_NUM
,
cs
.
invert
);
if
(
optarg
)
chain
=
optarg
;
else
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
else
if
(
xs_has_arg
(
argc
,
argv
))
chain
=
argv
[
optind
++
];
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
xs_has_arg
(
argc
,
argv
))
rulenum
=
parse_rulenumber
(
argv
[
optind
++
]);
break
;
...
...
@@ -1439,11 +1300,9 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_LIST_RULES
,
CMD_ZERO
|
CMD_ZERO_NUM
,
cs
.
invert
);
if
(
optarg
)
chain
=
optarg
;
else
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
else
if
(
xs_has_arg
(
argc
,
argv
))
chain
=
argv
[
optind
++
];
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
xs_has_arg
(
argc
,
argv
))
rulenum
=
parse_rulenumber
(
argv
[
optind
++
]);
break
;
...
...
@@ -1451,8 +1310,7 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_FLUSH
,
CMD_NONE
,
cs
.
invert
);
if
(
optarg
)
chain
=
optarg
;
else
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
else
if
(
xs_has_arg
(
argc
,
argv
))
chain
=
argv
[
optind
++
];
break
;
...
...
@@ -1460,11 +1318,9 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_ZERO
,
CMD_LIST
|
CMD_LIST_RULES
,
cs
.
invert
);
if
(
optarg
)
chain
=
optarg
;
else
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
else
if
(
xs_has_arg
(
argc
,
argv
))
chain
=
argv
[
optind
++
];
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
{
if
(
xs_has_arg
(
argc
,
argv
))
{
rulenum
=
parse_rulenumber
(
argv
[
optind
++
]);
command
=
CMD_ZERO_NUM
;
}
...
...
@@ -1481,8 +1337,7 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_DELETE_CHAIN
,
CMD_NONE
,
cs
.
invert
);
if
(
optarg
)
chain
=
optarg
;
else
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
else
if
(
xs_has_arg
(
argc
,
argv
))
chain
=
argv
[
optind
++
];
break
;
...
...
@@ -1490,8 +1345,7 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_RENAME_CHAIN
,
CMD_NONE
,
cs
.
invert
);
chain
=
optarg
;
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
xs_has_arg
(
argc
,
argv
))
newname
=
argv
[
optind
++
];
else
xtables_error
(
PARAMETER_PROBLEM
,
...
...
@@ -1504,8 +1358,7 @@ int do_command4(int argc, char *argv[], char **table,
add_command
(
&
command
,
CMD_SET_POLICY
,
CMD_NONE
,
cs
.
invert
);
chain
=
optarg
;
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
xs_has_arg
(
argc
,
argv
))
policy
=
argv
[
optind
++
];
else
xtables_error
(
PARAMETER_PROBLEM
,
...
...
@@ -1561,11 +1414,13 @@ int do_command4(int argc, char *argv[], char **table,
set_option
(
&
cs
.
options
,
OPT_JUMP
,
&
cs
.
fw
.
ip
.
invflags
,
cs
.
invert
);
cs
.
fw
.
ip
.
flags
|=
IPT_F_GOTO
;
cs
.
jumpto
=
parse_target
(
optarg
);
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
);
break
;
...
...
@@ -1613,16 +1468,7 @@ int do_command4(int argc, char *argv[], char **table,
"You cannot use `-w' from "
"iptables-restore"
);
}
wait
=
-
1
;
if
(
optarg
)
{
if
(
sscanf
(
optarg
,
"%i"
,
&
wait
)
!=
1
)
xtables_error
(
PARAMETER_PROBLEM
,
"wait seconds not numeric"
);
}
else
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
sscanf
(
argv
[
optind
++
],
"%i"
,
&
wait
)
!=
1
)
xtables_error
(
PARAMETER_PROBLEM
,
"wait seconds not numeric"
);
wait
=
parse_wait_time
(
argc
,
argv
);
break
;
case
'W'
:
...
...
@@ -1631,14 +1477,7 @@ int do_command4(int argc, char *argv[], char **table,
"You cannot use `-W' from "
"iptables-restore"
);
}
if
(
optarg
)
parse_wait_interval
(
optarg
,
&
wait_interval
);
else
if
(
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
parse_wait_interval
(
argv
[
optind
++
],
&
wait_interval
);
parse_wait_interval
(
argc
,
argv
,
&
wait_interval
);
wait_interval_set
=
true
;
break
;
...
...
@@ -1667,7 +1506,7 @@ int do_command4(int argc, char *argv[], char **table,
if
(
cs
.
invert
)
printf
(
"Not %s ;-)
\n
"
,
prog_vers
);
else
printf
(
"%s v%s
\n
"
,
printf
(
"%s v%s
(legacy)
\n
"
,
prog_name
,
prog_vers
);
exit
(
0
);
...
...
@@ -1688,8 +1527,7 @@ int do_command4(int argc, char *argv[], char **table,
bcnt
=
strchr
(
pcnt
+
1
,
','
);
if
(
bcnt
)
bcnt
++
;
if
(
!
bcnt
&&
optind
<
argc
&&
argv
[
optind
][
0
]
!=
'-'
&&
argv
[
optind
][
0
]
!=
'!'
)
if
(
!
bcnt
&&
xs_has_arg
(
argc
,
argv
))
bcnt
=
argv
[
optind
++
];
if
(
!
bcnt
)
xtables_error
(
PARAMETER_PROBLEM
,
...
...
@@ -1796,15 +1634,8 @@ int do_command4(int argc, char *argv[], char **table,
generic_opt_check
(
command
,
cs
.
options
);
/* Attempt to acquire the xtables lock */
if
(
!
restore
&&
!
xtables_lock
(
wait
,
&
wait_interval
))
{
fprintf
(
stderr
,
"Another app is currently holding the xtables lock. "
);
if
(
wait
==
0
)
fprintf
(
stderr
,
"Perhaps you want to use the -w option?
\n
"
);
else
fprintf
(
stderr
,
"Stopped waiting after %ds.
\n
"
,
wait
);
xtables_free_opts
(
1
);
exit
(
RESOURCE_PROBLEM
);
}
if
(
!
restore
)
xtables_lock_or_exit
(
wait
,
&
wait_interval
);
/* only allocate handle if we weren't called with a handle */
if
(
!*
handle
)
...
...
iptables/nft-arp.c
View file @
dab1e98e
...
...
@@ -92,7 +92,7 @@ static char *
mask_to_dotted
(
const
struct
in_addr
*
mask
)
{
int
i
;
static
char
buf
[
2
0
];
static
char
buf
[
2
2
];
u_int32_t
maskaddr
,
bits
;
maskaddr
=
ntohl
(
mask
->
s_addr
);
...
...
@@ -109,7 +109,7 @@ mask_to_dotted(const struct in_addr *mask)
sprintf
(
buf
,
"/%d"
,
i
);
else
/* mask was not a decent combination of 1's and 0's */
sprintf
(
buf
,
"/%s"
,
addr_to_dotted
(
mask
));
s
n
printf
(
buf
,
sizeof
(
buf
),
"/%s"
,
addr_to_dotted
(
mask
));
return
buf
;
}
...
...
@@ -139,8 +139,8 @@ static void print_mac_and_mask(const unsigned char *mac, const unsigned char *ma
static
int
nft_arp_add
(
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
ar
ptables_command_state
*
cs
=
data
;
struct
arpt_entry
*
fw
=
&
cs
->
fw
;
struct
i
ptables_command_state
*
cs
=
data
;
struct
arpt_entry
*
fw
=
&
cs
->
arp
;
uint32_t
op
;
int
ret
=
0
;
...
...
@@ -260,8 +260,8 @@ static uint16_t ipt_to_arpt_flags(uint8_t invflags)
static
void
nft_arp_parse_meta
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
,
void
*
data
)
{
struct
ar
ptables_command_state
*
cs
=
data
;
struct
arpt_entry
*
fw
=
&
cs
->
fw
;
struct
i
ptables_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
,
...
...
@@ -271,17 +271,10 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
fw
->
arp
.
invflags
|=
ipt_to_arpt_flags
(
flags
);
}
static
void
nft_arp_parse_target
(
struct
xtables_target
*
target
,
void
*
data
)
{
struct
arptables_command_state
*
cs
=
data
;
cs
->
target
=
target
;
}
static
void
nft_arp_parse_immediate
(
const
char
*
jumpto
,
bool
nft_goto
,
void
*
data
)
{
struct
ar
ptables_command_state
*
cs
=
data
;
struct
i
ptables_command_state
*
cs
=
data
;
cs
->
jumpto
=
jumpto
;
}
...
...
@@ -294,8 +287,8 @@ static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
static
void
nft_arp_parse_payload
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
,
void
*
data
)
{
struct
ar
ptables_command_state
*
cs
=
data
;
struct
arpt_entry
*
fw
=
&
cs
->
fw
;
struct
i
ptables_command_state
*
cs
=
data
;
struct
arpt_entry
*
fw
=
&
cs
->
arp
;
struct
in_addr
addr
;
unsigned
short
int
ar_hrd
,
ar_pro
,
ar_op
,
ar_hln
;
bool
inv
;
...
...
@@ -330,9 +323,6 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
fw
->
arp
.
invflags
|=
ARPT_INV_ARPOP
;
break
;
default:
if
(
fw
->
arp
.
arhln
<
0
)
break
;
if
(
ctx
->
payload
.
offset
==
sizeof
(
struct
arphdr
)
+
fw
->
arp
.
arhln
)
{
get_cmp_data
(
e
,
&
addr
,
sizeof
(
addr
),
&
inv
);
...
...
@@ -365,14 +355,14 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
}
}
void
nft_rule_to_
arptables_command_state
(
struct
nftnl_rule
*
r
,
struct
ar
ptables_command_state
*
cs
)
static
void
nft_
arp_
rule_to_
cs
(
const
struct
nftnl_rule
*
r
,
struct
i
ptables_command_state
*
cs
)
{
struct
nftnl_expr_iter
*
iter
;
struct
nftnl_expr
*
expr
;
int
family
=
nftnl_rule_get_u32
(
r
,
NFTNL_RULE_FAMILY
);
struct
nft_xt_ctx
ctx
=
{
.
s
tate
.
cs_arp
=
cs
,
.
c
s
=
cs
,
.
family
=
family
,
};
...
...
@@ -387,7 +377,7 @@ void nft_rule_to_arptables_command_state(struct nftnl_rule *r,
nftnl_expr_get_str
(
expr
,
NFTNL_EXPR_NAME
);
if
(
strcmp
(
name
,
"counter"
)
==
0
)
nft_parse_counter
(
expr
,
&
ctx
.
state
.
cs_arp
->
fw
.
counters
);
nft_parse_counter
(
expr
,
&
ctx
.
cs
->
arp
.
counters
);
else
if
(
strcmp
(
name
,
"payload"
)
==
0
)
nft_parse_payload
(
&
ctx
,
expr
);
else
if
(
strcmp
(
name
,
"meta"
)
==
0
)
...
...
@@ -418,10 +408,11 @@ void nft_rule_to_arptables_command_state(struct nftnl_rule *r,
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
)
bool
basechain
,
uint32_t
refs
,
uint32_t
entries
)
{
printf
(
"Chain %s"
,
chain
);
if
(
pol
)
{
if
(
basechain
&&
pol
)
{
printf
(
" (policy %s"
,
pol
);
if
(
!
(
format
&
FMT_NOCOUNTS
))
{
fputc
(
' '
,
stdout
);
...
...
@@ -436,7 +427,8 @@ static void nft_arp_print_header(unsigned int format, const char *chain,
}
}
static
void
print_fw_details
(
struct
arpt_entry
*
fw
,
unsigned
int
format
)
static
void
nft_arp_print_rule_details
(
const
struct
arpt_entry
*
fw
,
unsigned
int
format
)
{
char
buf
[
BUFSIZ
];
char
iface
[
IFNAMSIZ
+
2
];
...
...
@@ -542,6 +534,7 @@ after_devdst:
if
(
tmp
<=
NUMOPCODES
&&
!
(
format
&
FMT_NUMERIC
))
printf
(
"--opcode %s"
,
opcodes
[
tmp
-
1
]);
else
printf
(
"--opcode %d"
,
tmp
);
if
(
fw
->
arp
.
arpop_mask
!=
65535
)
printf
(
"/%d"
,
ntohs
(
fw
->
arp
.
arpop_mask
));
...
...
@@ -578,36 +571,48 @@ after_devdst:
}
static
void
nft_arp_print_firewall
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
)
__nft_arp_save_rule
(
const
void
*
data
,
unsigned
int
format
)
{
struct
arptables_command_state
cs
=
{};
nft_rule_to_arptables_command_state
(
r
,
&
cs
);
const
struct
iptables_command_state
*
cs
=
data
;
if
(
format
&
FMT_LINENUMBERS
)
printf
(
"%u "
,
num
);
nft_arp_print_rule_details
(
&
cs
->
arp
,
format
);
print_fw_details
(
&
cs
.
fw
,
format
);
if
(
cs
.
jumpto
!=
NULL
&&
strcmp
(
cs
.
jumpto
,
""
)
!=
0
)
{
printf
(
"-j %s"
,
cs
.
jumpto
);
}
else
if
(
cs
.
target
)
{
printf
(
"-j %s"
,
cs
.
target
->
name
);
cs
.
target
->
print
(
&
cs
.
fw
,
cs
.
target
->
t
,
format
&
FMT_NUMERIC
);
if
(
cs
->
jumpto
!=
NULL
&&
strcmp
(
cs
->
jumpto
,
""
)
!=
0
)
{
printf
(
"-j %s"
,
cs
->
jumpto
);
}
else
if
(
cs
->
target
)
{
printf
(
"-j %s"
,
cs
->
target
->
name
);
cs
->
target
->
print
(
&
cs
->
arp
,
cs
->
target
->
t
,
format
&
FMT_NUMERIC
);
}
if
(
!
(
format
&
FMT_NOCOUNTS
))
{
printf
(
", pcnt="
);
xtables_print_num
(
cs
.
fw
.
counters
.
pcnt
,
format
);
xtables_print_num
(
cs
->
arp
.
counters
.
pcnt
,
format
);
printf
(
"-- bcnt="
);
xtables_print_num
(
cs
.
fw
.
counters
.
bcnt
,
format
);
xtables_print_num
(
cs
->
arp
.
counters
.
bcnt
,
format
);
}
if
(
!
(
format
&
FMT_NONEWLINE
))
fputc
(
'\n'
,
stdout
);
}
static
void
nft_arp_save_rule
(
const
void
*
data
,
unsigned
int
format
)
{
__nft_arp_save_rule
(
data
,
format
|
FMT_NUMERIC
);
}
static
void
nft_arp_print_rule
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
)
{
struct
iptables_command_state
cs
=
{};
if
(
format
&
FMT_LINENUMBERS
)
printf
(
"%u "
,
num
);
nft_arp_rule_to_cs
(
r
,
&
cs
);
__nft_arp_save_rule
(
&
cs
,
format
);
}
static
bool
nft_arp_is_same
(
const
void
*
data_a
,
const
void
*
data_b
)
{
...
...
@@ -637,24 +642,31 @@ static bool nft_arp_is_same(const void *data_a,
static
bool
nft_arp_rule_find
(
struct
nft_family_ops
*
ops
,
struct
nftnl_rule
*
r
,
void
*
data
)
{
const
struct
ar
ptables_command_state
*
cs
=
data
;
struct
ar
ptables_command_state
this
=
{};
const
struct
i
ptables_command_state
*
cs
=
data
;
struct
i
ptables_command_state
this
=
{};
/* Delete by matching rule case */
nft_rule_to_
arptables_command_state
(
r
,
&
this
);
nft_
arp_
rule_to_
cs
(
r
,
&
this
);
if
(
!
nft_arp_is_same
(
cs
,
&
this
))
if
(
!
nft_arp_is_same
(
&
cs
->
arp
,
&
this
.
arp
))
return
false
;
if
(
!
compare_targets
(
cs
->
target
,
this
.
target
))
return
false
;
if
(
strcmp
(
cs
->
jumpto
,
this
.
jumpto
)
!=
0
)
if
(
this
.
jumpto
&&
strcmp
(
cs
->
jumpto
,
this
.
jumpto
)
!=
0
)
return
false
;
return
true
;
}
static
void
nft_arp_save_chain
(
const
struct
nftnl_chain
*
c
,
const
char
*
policy
)
{
const
char
*
chain
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_NAME
);
printf
(
":%s %s
\n
"
,
chain
,
policy
?:
"-"
);
}
struct
nft_family_ops
nft_family_ops_arp
=
{
.
add
=
nft_arp_add
,
.
is_same
=
nft_arp_is_same
,
...
...
@@ -663,10 +675,13 @@ struct nft_family_ops nft_family_ops_arp = {
.
parse_payload
=
nft_arp_parse_payload
,
.
parse_immediate
=
nft_arp_parse_immediate
,
.
print_header
=
nft_arp_print_header
,
.
print_
firewall
=
nft_arp_print_
firewall
,
.
save_
firewall
=
NULL
,
.
print_
rule
=
nft_arp_print_
rule
,
.
save_
rule
=
nft_arp_save_rule
,
.
save_counters
=
NULL
,
.
save_chain
=
nft_arp_save_chain
,
.
post_parse
=
NULL
,
.
rule_to_cs
=
nft_arp_rule_to_cs
,
.
clear_cs
=
nft_clear_iptables_command_state
,
.
rule_find
=
nft_arp_rule_find
,
.
parse_target
=
nft_
arp
_parse_target
,
.
parse_target
=
nft_
ipv46
_parse_target
,
};
iptables/nft-arp.h
View file @
dab1e98e
...
...
@@ -4,13 +4,4 @@
extern
char
*
opcodes
[];
#define NUMOPCODES 9
struct
arptables_command_state
{
struct
arpt_entry
fw
;
struct
xtables_target
*
target
;
const
char
*
jumpto
;
};
void
nft_rule_to_arptables_command_state
(
struct
nftnl_rule
*
r
,
struct
arptables_command_state
*
cs
);
#endif
iptables/nft-bridge.c
View file @
dab1e98e
...
...
@@ -16,22 +16,30 @@
#include <xtables.h>
#include <libiptc/libxtc.h>
#include <linux/netfilter/nf_tables.h>
#include <ebtables/ethernetdb.h>
#include "nft-shared.h"
#include "nft-bridge.h"
#include "nft.h"
void
ebt_cs_clean
(
struct
eb
tables_command_state
*
cs
)
void
ebt_cs_clean
(
struct
ip
tables_command_state
*
cs
)
{
struct
ebt_match
*
m
,
*
nm
;
xtables_rule_matches_free
(
&
cs
->
matches
);
for
(
m
=
cs
->
match_list
;
m
;)
{
if
(
!
m
->
ismatch
)
{
struct
xtables_target
*
target
=
m
->
u
.
watcher
;
if
(
target
->
t
)
{
free
(
target
->
t
);
target
->
t
=
NULL
;
}
if
(
target
==
target
->
next
)
free
(
target
);
}
nm
=
m
->
next
;
if
(
!
m
->
ismatch
)
free
(
m
->
u
.
watcher
->
t
);
free
(
m
);
m
=
nm
;
}
...
...
@@ -54,10 +62,16 @@ static void ebt_print_mac(const unsigned char *mac)
printf
(
"%s"
,
ether_ntoa
((
struct
ether_addr
*
)
mac
));
}
static
bool
mac_all_ones
(
const
unsigned
char
*
mac
)
{
static
const
char
hlpmsk
[
6
]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
return
memcmp
(
mac
,
hlpmsk
,
sizeof
(
hlpmsk
))
==
0
;
}
/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
static
void
ebt_print_mac_and_mask
(
const
unsigned
char
*
mac
,
const
unsigned
char
*
mask
)
{
char
hlpmsk
[
6
]
=
{};
if
(
!
memcmp
(
mac
,
eb_mac_type_unicast
,
6
)
&&
!
memcmp
(
mask
,
eb_msk_type_unicast
,
6
))
...
...
@@ -73,29 +87,13 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char
printf
(
"BGA"
);
else
{
ebt_print_mac
(
mac
);
if
(
memcmp
(
mask
,
hlpmsk
,
6
))
{
if
(
!
mac_all_ones
(
mask
))
{
printf
(
"/"
);
ebt_print_mac
(
mask
);
}
}
}
static
uint16_t
ipt_to_ebt_flags
(
uint8_t
invflags
)
{
uint16_t
result
=
0
;
if
(
invflags
&
IPT_INV_VIA_IN
)
result
|=
EBT_IIN
;
if
(
invflags
&
IPT_INV_VIA_OUT
)
result
|=
EBT_IOUT
;
if
(
invflags
&
IPT_INV_PROTO
)
result
|=
EBT_IPROTO
;
return
result
;
}
static
void
add_logical_iniface
(
struct
nftnl_rule
*
r
,
char
*
iface
,
uint32_t
op
)
{
int
iface_len
;
...
...
@@ -125,7 +123,7 @@ static void add_logical_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
/* TODO: Use generic add_action() once we convert this to use
* iptables_command_state.
*/
static
int
_add_action
(
struct
nftnl_rule
*
r
,
struct
eb
tables_command_state
*
cs
)
static
int
_add_action
(
struct
nftnl_rule
*
r
,
struct
ip
tables_command_state
*
cs
)
{
int
ret
=
0
;
...
...
@@ -153,11 +151,10 @@ static int _add_action(struct nftnl_rule *r, struct ebtables_command_state *cs)
static
int
nft_bridge_add
(
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
eb
tables_command_state
*
cs
=
data
;
struct
ip
tables_command_state
*
cs
=
data
;
struct
ebt_match
*
iter
;
struct
ebt_entry
*
fw
=
&
cs
->
fw
;
struct
ebt_entry
*
fw
=
&
cs
->
eb
;
uint32_t
op
;
char
*
addr
;
if
(
fw
->
in
[
0
]
!=
'\0'
)
{
op
=
nft_invflags2cmp
(
fw
->
invflags
,
EBT_IIN
);
...
...
@@ -179,30 +176,32 @@ static int nft_bridge_add(struct nftnl_rule *r, void *data)
add_logical_outiface
(
r
,
fw
->
logical_out
,
op
);
}
addr
=
ether_ntoa
((
struct
ether_addr
*
)
fw
->
sourcemac
);
if
(
strcmp
(
addr
,
"0:0:0:0:0:0"
)
!=
0
)
{
if
(
fw
->
bitmask
&
EBT_ISOURCE
)
{
op
=
nft_invflags2cmp
(
fw
->
invflags
,
EBT_ISOURCE
);
add_payload
(
r
,
offsetof
(
struct
ethhdr
,
h_source
),
6
,
NFT_PAYLOAD_LL_HEADER
);
if
(
!
mac_all_ones
(
fw
->
sourcemsk
))
add_bitwise
(
r
,
fw
->
sourcemsk
,
6
);
add_cmp_ptr
(
r
,
op
,
fw
->
sourcemac
,
6
);
}
addr
=
ether_ntoa
((
struct
ether_addr
*
)
fw
->
destmac
);
if
(
strcmp
(
addr
,
"0:0:0:0:0:0"
)
!=
0
)
{
if
(
fw
->
bitmask
&
EBT_IDEST
)
{
op
=
nft_invflags2cmp
(
fw
->
invflags
,
EBT_IDEST
);
add_payload
(
r
,
offsetof
(
struct
ethhdr
,
h_dest
),
6
,
NFT_PAYLOAD_LL_HEADER
);
if
(
!
mac_all_ones
(
fw
->
destmsk
))
add_bitwise
(
r
,
fw
->
destmsk
,
6
);
add_cmp_ptr
(
r
,
op
,
fw
->
destmac
,
6
);
}
if
(
fw
->
ethproto
!
=
0
)
{
if
(
(
fw
->
bitmask
&
EBT_NOPROTO
)
=
=
0
)
{
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_compat
(
r
,
fw
->
ethproto
,
fw
->
invflags
);
add_compat
(
r
,
fw
->
ethproto
,
fw
->
invflags
&
EBT_IPROTO
);
for
(
iter
=
cs
->
match_list
;
iter
;
iter
=
iter
->
next
)
{
if
(
iter
->
ismatch
)
{
...
...
@@ -223,62 +222,44 @@ static int nft_bridge_add(struct nftnl_rule *r, void *data)
static
void
nft_bridge_parse_meta
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
,
void
*
data
)
{
struct
ebtables_command_state
*
cs
=
data
;
struct
ebt_entry
*
fw
=
&
cs
->
fw
;
uint8_t
flags
=
0
;
int
iface
=
0
;
const
void
*
ifname
;
uint32_t
len
;
iface
=
parse_meta
(
e
,
ctx
->
meta
.
key
,
fw
->
in
,
fw
->
in_mask
,
fw
->
out
,
fw
->
out_mask
,
&
flags
);
if
(
!
iface
)
goto
out
;
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
:
ifname
=
nftnl_expr_get
(
e
,
NFTNL_EXPR_CMP_DATA
,
&
len
);
if
(
nftnl_expr_get_u32
(
e
,
NFTNL_EXPR_CMP_OP
)
==
NFT_CMP_NEQ
)
flags
|=
IPT_INV_VIA_IN
;
memcpy
(
fw
->
logical_in
,
ifname
,
len
);
if
(
fw
->
logical_in
[
len
]
==
'\0'
)
memset
(
fw
->
in_mask
,
0xff
,
len
);
else
{
fw
->
logical_in
[
len
]
=
'+'
;
fw
->
logical_in
[
len
+
1
]
=
'\0'
;
memset
(
fw
->
in_mask
,
0xff
,
len
+
1
);
}
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
:
ifname
=
nftnl_expr_get
(
e
,
NFTNL_EXPR_CMP_DATA
,
&
len
);
if
(
nftnl_expr_get_u32
(
e
,
NFTNL_EXPR_CMP_OP
)
==
NFT_CMP_NEQ
)
flags
|=
IPT_INV_VIA_OUT
;
memcpy
(
fw
->
logical_out
,
ifname
,
len
);
if
(
fw
->
logical_out
[
len
]
==
'\0'
)
memset
(
fw
->
out_mask
,
0xff
,
len
);
else
{
fw
->
logical_out
[
len
]
=
'+'
;
fw
->
logical_out
[
len
+
1
]
=
'\0'
;
memset
(
fw
->
out_mask
,
0xff
,
len
+
1
);
}
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
;
}
out:
fw
->
invflags
|=
ipt_to_ebt_flags
(
flags
);
}
static
void
nft_bridge_parse_payload
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
,
void
*
data
)
{
struct
eb
tables_command_state
*
cs
=
data
;
struct
ebt_entry
*
fw
=
&
cs
->
fw
;
struct
ip
tables_command_state
*
cs
=
data
;
struct
ebt_entry
*
fw
=
&
cs
->
eb
;
unsigned
char
addr
[
ETH_ALEN
];
unsigned
short
int
ethproto
;
bool
inv
;
...
...
@@ -291,6 +272,14 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
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
,
ETH_ALEN
);
}
fw
->
bitmask
|=
EBT_IDEST
;
break
;
case
offsetof
(
struct
ethhdr
,
h_source
):
get_cmp_data
(
e
,
addr
,
sizeof
(
addr
),
&
inv
);
...
...
@@ -298,12 +287,20 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
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
,
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
;
}
}
...
...
@@ -311,7 +308,7 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
static
void
nft_bridge_parse_immediate
(
const
char
*
jumpto
,
bool
nft_goto
,
void
*
data
)
{
struct
eb
tables_command_state
*
cs
=
data
;
struct
ip
tables_command_state
*
cs
=
data
;
cs
->
jumpto
=
jumpto
;
}
...
...
@@ -339,14 +336,14 @@ static void parse_watcher(void *object, struct ebt_match **match_list,
static
void
nft_bridge_parse_match
(
struct
xtables_match
*
m
,
void
*
data
)
{
struct
eb
tables_command_state
*
cs
=
data
;
struct
ip
tables_command_state
*
cs
=
data
;
parse_watcher
(
m
,
&
cs
->
match_list
,
true
);
}
static
void
nft_bridge_parse_target
(
struct
xtables_target
*
t
,
void
*
data
)
{
struct
eb
tables_command_state
*
cs
=
data
;
struct
ip
tables_command_state
*
cs
=
data
;
/* harcoded names :-( */
if
(
strcmp
(
t
->
name
,
"log"
)
==
0
||
...
...
@@ -358,66 +355,17 @@ static void nft_bridge_parse_target(struct xtables_target *t, void *data)
cs
->
target
=
t
;
}
void
nft_rule_to_ebtables_command_state
(
struct
nftnl_rule
*
r
,
struct
eb
tables_command_state
*
cs
)
static
void
nft_rule_to_ebtables_command_state
(
const
struct
nftnl_rule
*
r
,
struct
ip
tables_command_state
*
cs
)
{
struct
nftnl_expr_iter
*
iter
;
struct
nftnl_expr
*
expr
;
int
family
=
nftnl_rule_get_u32
(
r
,
NFTNL_RULE_FAMILY
);
struct
nft_xt_ctx
ctx
=
{
.
state
.
cs_eb
=
cs
,
.
family
=
family
,
};
iter
=
nftnl_expr_iter_create
(
r
);
if
(
iter
==
NULL
)
return
;
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
,
&
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
);
expr
=
nftnl_expr_iter_next
(
iter
);
}
nftnl_expr_iter_destroy
(
iter
);
if
(
cs
->
jumpto
!=
NULL
)
return
;
if
(
cs
->
target
!=
NULL
&&
cs
->
target
->
name
!=
NULL
)
cs
->
target
=
xtables_find_target
(
cs
->
target
->
name
,
XTF_TRY_LOAD
);
else
cs
->
jumpto
=
"CONTINUE"
;
cs
->
eb
.
bitmask
=
EBT_NOPROTO
;
nft_rule_to_iptables_command_state
(
r
,
cs
);
}
static
void
print_iface
(
const
char
*
iface
)
static
void
print_iface
(
const
char
*
option
,
const
char
*
name
,
bool
invert
)
{
char
*
c
;
if
((
c
=
strchr
(
iface
,
IF_WILDCARD
)))
*
c
=
'+'
;
printf
(
"%s "
,
iface
);
if
(
c
)
*
c
=
IF_WILDCARD
;
if
(
*
name
)
printf
(
"%s%s %s "
,
invert
?
"! "
:
""
,
option
,
name
);
}
static
void
nft_bridge_print_table_header
(
const
char
*
tablename
)
...
...
@@ -428,124 +376,147 @@ 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
)
bool
basechain
,
uint32_t
refs
,
uint32_t
entries
)
{
printf
(
"Bridge chain: %s, entries: %u, policy: %s
\n
"
,
chain
,
ref
s
,
basechain
?
pol
:
"RETURN"
);
chain
,
entrie
s
,
basechain
?
pol
:
"RETURN"
);
}
static
void
nft_bridge_print_firewall
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
static
void
print_matches_and_watchers
(
const
struct
iptables_command_state
*
cs
,
unsigned
int
format
)
{
struct
xtables_match
*
matchp
;
struct
xtables_target
*
watcherp
;
struct
xtables_match
*
matchp
;
struct
ebt_match
*
m
;
struct
ebtables_command_state
cs
=
{};
char
*
addr
;
nft_rule_to_ebtables_command_state
(
r
,
&
cs
);
for
(
m
=
cs
->
match_list
;
m
;
m
=
m
->
next
)
{
if
(
m
->
ismatch
)
{
matchp
=
m
->
u
.
match
;
if
(
matchp
->
print
!=
NULL
)
{
matchp
->
print
(
&
cs
->
eb
,
matchp
->
m
,
format
&
FMT_NUMERIC
);
}
}
else
{
watcherp
=
m
->
u
.
watcher
;
if
(
watcherp
->
print
!=
NULL
)
{
watcherp
->
print
(
&
cs
->
eb
,
watcherp
->
t
,
format
&
FMT_NUMERIC
);
}
}
}
}
static
void
print_mac
(
char
option
,
const
unsigned
char
*
mac
,
const
unsigned
char
*
mask
,
bool
invert
)
{
printf
(
"-%c "
,
option
);
if
(
invert
)
printf
(
"! "
);
ebt_print_mac_and_mask
(
mac
,
mask
);
printf
(
" "
);
}
if
(
format
&
FMT_LINENUMBERS
)
printf
(
"%d "
,
num
);
static
void
print_protocol
(
uint16_t
ethproto
,
bool
invert
,
unsigned
int
bitmask
)
{
struct
xt_ethertypeent
*
ent
;
/* Dont print anything about the protocol if no protocol was
* specified, obviously this means any protocol will do. */
if
(
cs
.
fw
.
ethproto
!=
0
)
{
if
(
bitmask
&
EBT_NOPROTO
)
return
;
printf
(
"-p "
);
if
(
cs
.
fw
.
invflags
&
EBT_IPROTO
)
if
(
invert
)
printf
(
"! "
);
if
(
cs
.
fw
.
bitmask
&
EBT_802_3
)
printf
(
"Length "
);
else
{
struct
ethertypeent
*
ent
;
ent
=
getethertypebynumber
(
ntohs
(
cs
.
fw
.
ethproto
));
if
(
bitmask
&
EBT_802_3
)
{
printf
(
"length "
);
return
;
}
ent
=
xtables_getethertypebynumber
(
ntohs
(
ethproto
));
if
(
!
ent
)
printf
(
"0x%x "
,
ntohs
(
cs
.
fw
.
ethproto
));
printf
(
"0x%x "
,
ntohs
(
ethproto
));
else
printf
(
"%s "
,
ent
->
e_name
);
}
}
}
addr
=
ether_ntoa
((
struct
ether_addr
*
)
cs
.
fw
.
sourcemac
);
if
(
strcmp
(
addr
,
"0:0:0:0:0:0"
)
!=
0
)
{
printf
(
"-s "
);
if
(
cs
.
fw
.
invflags
&
EBT_ISOURCE
)
printf
(
"! "
);
ebt_print_mac_and_mask
(
cs
.
fw
.
sourcemac
,
cs
.
fw
.
sourcemsk
);
printf
(
" "
);
}
static
void
nft_bridge_save_rule
(
const
void
*
data
,
unsigned
int
format
)
{
const
struct
iptables_command_state
*
cs
=
data
;
if
(
cs
->
eb
.
ethproto
)
print_protocol
(
cs
->
eb
.
ethproto
,
cs
->
eb
.
invflags
&
EBT_IPROTO
,
cs
->
eb
.
bitmask
);
if
(
cs
->
eb
.
bitmask
&
EBT_ISOURCE
)
print_mac
(
's'
,
cs
->
eb
.
sourcemac
,
cs
->
eb
.
sourcemsk
,
cs
->
eb
.
invflags
&
EBT_ISOURCE
);
if
(
cs
->
eb
.
bitmask
&
EBT_IDEST
)
print_mac
(
'd'
,
cs
->
eb
.
destmac
,
cs
->
eb
.
destmsk
,
cs
->
eb
.
invflags
&
EBT_IDEST
);
print_iface
(
"-i"
,
cs
->
eb
.
in
,
cs
->
eb
.
invflags
&
EBT_IIN
);
print_iface
(
"--logical-in"
,
cs
->
eb
.
logical_in
,
cs
->
eb
.
invflags
&
EBT_ILOGICALIN
);
print_iface
(
"-o"
,
cs
->
eb
.
out
,
cs
->
eb
.
invflags
&
EBT_IOUT
);
print_iface
(
"--logical-out"
,
cs
->
eb
.
logical_out
,
cs
->
eb
.
invflags
&
EBT_ILOGICALOUT
);
print_matches_and_watchers
(
cs
,
format
);
addr
=
ether_ntoa
((
struct
ether_addr
*
)
cs
.
fw
.
destmac
);
if
(
strcmp
(
addr
,
"0:0:0:0:0:0"
)
!=
0
)
{
printf
(
"-d "
);
if
(
cs
.
fw
.
invflags
&
EBT_IDEST
)
printf
(
"! "
);
ebt_print_mac_and_mask
(
cs
.
fw
.
destmac
,
cs
.
fw
.
destmsk
);
printf
(
" "
);
}
printf
(
"-j "
);
if
(
cs
.
fw
.
in
[
0
]
!=
'\0'
)
{
printf
(
"-i "
);
if
(
cs
.
fw
.
invflags
&
EBT_IIN
)
printf
(
"! "
);
print
_iface
(
cs
.
fw
.
in
);
if
(
cs
->
jumpto
!=
NULL
)
{
if
(
strcmp
(
cs
->
jumpto
,
""
)
!=
0
)
printf
(
"%s"
,
cs
->
jumpto
);
else
print
f
(
"CONTINUE"
);
}
if
(
cs
.
fw
.
logical_in
[
0
]
!=
'\0'
)
{
printf
(
"--logical-in "
);
if
(
cs
.
fw
.
invflags
&
EBT_ILOGICALIN
)
printf
(
"! "
);
print_iface
(
cs
.
fw
.
logical_in
);
if
(
cs
->
target
!=
NULL
&&
cs
->
target
->
print
!=
NULL
)
{
printf
(
" "
);
cs
->
target
->
print
(
&
cs
->
fw
,
cs
->
target
->
t
,
format
&
FMT_NUMERIC
);
}
if
(
cs
.
fw
.
logical_out
[
0
]
!=
'\0'
)
{
printf
(
"--logical-out "
);
if
(
cs
.
fw
.
invflags
&
EBT_ILOGICALOUT
)
printf
(
"! "
);
print_iface
(
cs
.
fw
.
logical_out
);
}
if
(
!
(
format
&
FMT_NOCOUNTS
))
{
const
char
*
counter_fmt
;
if
(
cs
.
fw
.
out
[
0
]
!=
'\0'
)
{
printf
(
"-o "
);
if
(
cs
.
fw
.
invflags
&
EBT_IOUT
)
printf
(
"! "
);
print_iface
(
cs
.
fw
.
out
);
}
if
(
format
&
FMT_EBT_SAVE
)
counter_fmt
=
" -c %"
PRIu64
" %"
PRIu64
""
;
else
counter_fmt
=
" , pcnt = %"
PRIu64
" -- bcnt = %"
PRIu64
""
;
for
(
m
=
cs
.
match_list
;
m
;
m
=
m
->
next
)
{
if
(
m
->
ismatch
)
{
matchp
=
m
->
u
.
match
;
if
(
matchp
->
print
!=
NULL
)
{
matchp
->
print
(
&
cs
.
fw
,
matchp
->
m
,
format
&
FMT_NUMERIC
);
printf
(
counter_fmt
,
(
uint64_t
)
cs
->
counters
.
pcnt
,
(
uint64_t
)
cs
->
counters
.
bcnt
);
}
}
else
{
watcherp
=
m
->
u
.
watcher
;
if
(
watcherp
->
print
!=
NULL
)
{
watcherp
->
print
(
&
cs
.
fw
,
watcherp
->
t
,
format
&
FMT_NUMERIC
);
}
}
}
printf
(
"-j "
);
if
(
cs
.
jumpto
!=
NULL
)
printf
(
"%s"
,
cs
.
jumpto
);
else
if
(
cs
.
target
!=
NULL
&&
cs
.
target
->
print
!=
NULL
)
cs
.
target
->
print
(
&
cs
.
fw
,
cs
.
target
->
t
,
format
&
FMT_NUMERIC
);
if
(
!
(
format
&
FMT_NOCOUNTS
))
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
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_bridge_save_rule
(
&
cs
,
format
);
ebt_cs_clean
(
&
cs
);
}
static
void
nft_bridge_save_chain
(
const
struct
nftnl_chain
*
c
,
const
char
*
policy
)
{
const
char
*
chain
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_NAME
);
printf
(
":%s %s
\n
"
,
chain
,
policy
?:
"ACCEPT"
);
}
static
bool
nft_bridge_is_same
(
const
void
*
data_a
,
const
void
*
data_b
)
{
const
struct
ebt_entry
*
a
=
data_a
;
...
...
@@ -587,21 +558,14 @@ static bool nft_bridge_is_same(const void *data_a, const void *data_b)
}
}
return
is_same_interfaces
((
char
*
)
a
->
in
,
(
char
*
)
a
->
out
,
a
->
in_mask
,
a
->
out_mask
,
(
char
*
)
b
->
in
,
(
char
*
)
b
->
out
,
b
->
in_mask
,
b
->
out_mask
);
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
,
void
*
data
)
{
struct
eb
tables_command_state
*
cs
=
data
;
struct
eb
tables_command_state
this
=
{};
struct
ip
tables_command_state
*
cs
=
data
;
struct
ip
tables_command_state
this
=
{};
nft_rule_to_ebtables_command_state
(
r
,
&
this
);
...
...
@@ -628,6 +592,168 @@ static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nftnl_rule *
return
true
;
}
static
int
xlate_ebmatches
(
const
struct
iptables_command_state
*
cs
,
struct
xt_xlate
*
xl
)
{
int
ret
=
1
,
numeric
=
cs
->
options
&
OPT_NUMERIC
;
struct
ebt_match
*
m
;
for
(
m
=
cs
->
match_list
;
m
;
m
=
m
->
next
)
{
if
(
m
->
ismatch
)
{
struct
xtables_match
*
matchp
=
m
->
u
.
match
;
struct
xt_xlate_mt_params
mt_params
=
{
.
ip
=
(
const
void
*
)
&
cs
->
eb
,
.
numeric
=
numeric
,
.
escape_quotes
=
false
,
.
match
=
matchp
->
m
,
};
if
(
!
matchp
->
xlate
)
return
0
;
ret
=
matchp
->
xlate
(
xl
,
&
mt_params
);
}
else
{
struct
xtables_target
*
watcherp
=
m
->
u
.
watcher
;
struct
xt_xlate_tg_params
wt_params
=
{
.
ip
=
(
const
void
*
)
&
cs
->
eb
,
.
numeric
=
numeric
,
.
escape_quotes
=
false
,
.
target
=
watcherp
->
t
,
};
if
(
!
watcherp
->
xlate
)
return
0
;
ret
=
watcherp
->
xlate
(
xl
,
&
wt_params
);
}
if
(
!
ret
)
break
;
}
return
ret
;
}
static
int
xlate_ebaction
(
const
struct
iptables_command_state
*
cs
,
struct
xt_xlate
*
xl
)
{
int
ret
=
1
,
numeric
=
cs
->
options
&
OPT_NUMERIC
;
/* If no target at all, add nothing (default to continue) */
if
(
cs
->
target
!=
NULL
)
{
/* Standard target? */
if
(
strcmp
(
cs
->
jumpto
,
XTC_LABEL_ACCEPT
)
==
0
)
xt_xlate_add
(
xl
,
" accept"
);
else
if
(
strcmp
(
cs
->
jumpto
,
XTC_LABEL_DROP
)
==
0
)
xt_xlate_add
(
xl
,
" drop"
);
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
,
.
numeric
=
numeric
,
};
ret
=
cs
->
target
->
xlate
(
xl
,
&
params
);
}
else
return
0
;
}
else
if
(
cs
->
jumpto
==
NULL
)
{
}
else
if
(
strlen
(
cs
->
jumpto
)
>
0
)
xt_xlate_add
(
xl
,
" jump %s"
,
cs
->
jumpto
);
return
ret
;
}
static
void
xlate_mac
(
struct
xt_xlate
*
xl
,
const
unsigned
char
*
mac
)
{
int
i
;
xt_xlate_add
(
xl
,
"%02x"
,
mac
[
0
]);
for
(
i
=
1
;
i
<
ETH_ALEN
;
i
++
)
xt_xlate_add
(
xl
,
":%02x"
,
mac
[
i
]);
}
static
void
nft_bridge_xlate_mac
(
struct
xt_xlate
*
xl
,
const
char
*
type
,
bool
invert
,
const
unsigned
char
*
mac
,
const
unsigned
char
*
mask
)
{
char
one_msk
[
ETH_ALEN
]
=
{
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
};
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 "
);
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
]);
}
xt_xlate_add
(
xl
,
" "
);
}
static
int
nft_bridge_xlate
(
const
void
*
data
,
struct
xt_xlate
*
xl
)
{
const
struct
iptables_command_state
*
cs
=
data
;
int
ret
;
xlate_ifname
(
xl
,
"iifname"
,
cs
->
eb
.
in
,
cs
->
eb
.
invflags
&
EBT_IIN
);
xlate_ifname
(
xl
,
"meta ibrname"
,
cs
->
eb
.
logical_in
,
cs
->
eb
.
invflags
&
EBT_ILOGICALIN
);
xlate_ifname
(
xl
,
"oifname"
,
cs
->
eb
.
out
,
cs
->
eb
.
invflags
&
EBT_IOUT
);
xlate_ifname
(
xl
,
"meta obrname"
,
cs
->
eb
.
logical_out
,
cs
->
eb
.
invflags
&
EBT_ILOGICALOUT
);
if
((
cs
->
eb
.
bitmask
&
EBT_NOPROTO
)
==
0
)
{
const
char
*
implicit
=
NULL
;
switch
(
ntohs
(
cs
->
eb
.
ethproto
))
{
case
ETH_P_IP
:
implicit
=
"ip"
;
break
;
case
ETH_P_IPV6
:
implicit
=
"ip6"
;
break
;
case
ETH_P_8021Q
:
implicit
=
"vlan"
;
break
;
default:
break
;
}
if
(
!
implicit
||
!
xlate_find_match
(
cs
,
implicit
))
xt_xlate_add
(
xl
,
"ether type %s0x%x "
,
cs
->
eb
.
invflags
&
EBT_IPROTO
?
"!= "
:
""
,
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
);
if
(
cs
->
eb
.
bitmask
&
EBT_IDEST
)
nft_bridge_xlate_mac
(
xl
,
"daddr"
,
cs
->
eb
.
invflags
&
EBT_IDEST
,
cs
->
eb
.
destmac
,
cs
->
eb
.
destmsk
);
ret
=
xlate_ebmatches
(
cs
,
xl
);
if
(
ret
==
0
)
return
ret
;
/* Always add counters per rule, as in ebtables */
xt_xlate_add
(
xl
,
"counter"
);
ret
=
xlate_ebaction
(
cs
,
xl
);
return
ret
;
}
struct
nft_family_ops
nft_family_ops_bridge
=
{
.
add
=
nft_bridge_add
,
.
is_same
=
nft_bridge_is_same
,
...
...
@@ -639,9 +765,13 @@ struct nft_family_ops nft_family_ops_bridge = {
.
parse_target
=
nft_bridge_parse_target
,
.
print_table_header
=
nft_bridge_print_table_header
,
.
print_header
=
nft_bridge_print_header
,
.
print_
firewall
=
nft_bridge_print_
firewall
,
.
save_
firewall
=
NULL
,
.
print_
rule
=
nft_bridge_print_
rule
,
.
save_
rule
=
nft_bridge_save_rule
,
.
save_counters
=
NULL
,
.
save_chain
=
nft_bridge_save_chain
,
.
post_parse
=
NULL
,
.
rule_to_cs
=
nft_rule_to_ebtables_command_state
,
.
clear_cs
=
ebt_cs_clean
,
.
rule_find
=
nft_bridge_rule_find
,
.
xlate
=
nft_bridge_xlate
,
};
iptables/nft-bridge.h
View file @
dab1e98e
...
...
@@ -15,9 +15,6 @@
#define LIST_X 0x10
#define LIST_MAC2 0x20
/* Be backwards compatible, so don't use '+' in kernel */
#define IF_WILDCARD 1
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
];
...
...
@@ -70,56 +67,7 @@ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mas
*/
#define EBT_VERDICT_BITS 0x0000000F
/* Fake ebt_entry */
struct
ebt_entry
{
/* this needs to be the first field */
unsigned
int
bitmask
;
unsigned
int
invflags
;
uint16_t
ethproto
;
/* the physical in-dev */
char
in
[
IFNAMSIZ
];
/* the logical in-dev */
char
logical_in
[
IFNAMSIZ
];
/* the physical out-dev */
char
out
[
IFNAMSIZ
];
/* the logical out-dev */
char
logical_out
[
IFNAMSIZ
];
unsigned
char
sourcemac
[
ETH_ALEN
];
unsigned
char
sourcemsk
[
ETH_ALEN
];
unsigned
char
destmac
[
ETH_ALEN
];
unsigned
char
destmsk
[
ETH_ALEN
];
unsigned
char
in_mask
[
IFNAMSIZ
];
unsigned
char
out_mask
[
IFNAMSIZ
];
};
/* trick for ebtables-compat, since watchers are targets */
struct
ebt_match
{
struct
ebt_match
*
next
;
union
{
struct
xtables_match
*
match
;
struct
xtables_target
*
watcher
;
}
u
;
bool
ismatch
;
};
struct
ebtables_command_state
{
struct
ebt_entry
fw
;
struct
xtables_target
*
target
;
struct
xtables_rule_match
*
matches
;
struct
ebt_match
*
match_list
;
const
char
*
jumpto
;
struct
xt_counters
counters
;
int
invert
;
int
c
;
char
**
argv
;
int
proto_used
;
char
*
protocol
;
unsigned
int
options
;
};
void
nft_rule_to_ebtables_command_state
(
struct
nftnl_rule
*
r
,
struct
ebtables_command_state
*
cs
);
struct
nftnl_rule
;
static
const
char
*
ebt_standard_targets
[
NUM_STANDARD_TARGETS
]
=
{
"ACCEPT"
,
...
...
@@ -130,7 +78,7 @@ static const char *ebt_standard_targets[NUM_STANDARD_TARGETS] = {
static
inline
const
char
*
nft_ebt_standard_target
(
unsigned
int
num
)
{
if
(
num
>
NUM_STANDARD_TARGETS
)
if
(
num
>
=
NUM_STANDARD_TARGETS
)
return
NULL
;
return
ebt_standard_targets
[
num
];
...
...
@@ -166,6 +114,13 @@ static inline const char *ebt_target_name(unsigned int verdict)
*flags |= mask; \
}) \
void
ebt_cs_clean
(
struct
ebtables_command_state
*
cs
);
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
);
struct
xtables_target
*
ebt_command_jump
(
const
char
*
jumpto
);
#endif
iptables/nft-ipv4.c
View file @
dab1e98e
...
...
@@ -45,8 +45,7 @@ static int nft_ipv4_add(struct nftnl_rule *r, void *data)
if
(
cs
->
fw
.
ip
.
proto
!=
0
)
{
op
=
nft_invflags2cmp
(
cs
->
fw
.
ip
.
invflags
,
XT_INV_PROTO
);
add_proto
(
r
,
offsetof
(
struct
iphdr
,
protocol
),
1
,
cs
->
fw
.
ip
.
proto
,
op
);
add_l4proto
(
r
,
cs
->
fw
.
ip
.
proto
,
op
);
}
if
(
cs
->
fw
.
ip
.
src
.
s_addr
!=
0
)
{
...
...
@@ -65,22 +64,26 @@ static int nft_ipv4_add(struct nftnl_rule *r, void *data)
add_payload
(
r
,
offsetof
(
struct
iphdr
,
frag_off
),
2
,
NFT_PAYLOAD_NETWORK_HEADER
);
/* get the 13 bits that contain the fragment offset */
add_bitwise_u16
(
r
,
0x1fff
,
!
0x1fff
);
add_bitwise_u16
(
r
,
0x1fff
,
0
);
/* if offset is non-zero, this is a fragment */
op
=
nft_invflags2cmp
(
cs
->
fw
.
ip
.
invflags
,
IPT_INV_FRAG
);
op
=
NFT_CMP_NEQ
;
if
(
cs
->
fw
.
ip
.
invflags
&
IPT_INV_FRAG
)
op
=
NFT_CMP_EQ
;
add_cmp_u16
(
r
,
0
,
op
);
}
add_compat
(
r
,
cs
->
fw
.
ip
.
proto
,
cs
->
fw
.
ip
.
invflags
);
add_compat
(
r
,
cs
->
fw
.
ip
.
proto
,
cs
->
fw
.
ip
.
invflags
&
XT_INV_PROTO
);
for
(
matchp
=
cs
->
matches
;
matchp
;
matchp
=
matchp
->
next
)
{
/* Use nft built-in comments support instead of comment match */
if
(
strcmp
(
matchp
->
match
->
name
,
"comment"
)
==
0
)
{
ret
=
add_comment
(
r
,
(
char
*
)
matchp
->
match
->
m
->
data
);
if
(
ret
<
0
)
return
ret
;
goto
try_match
;
}
else
{
try_match:
ret
=
add_match
(
r
,
matchp
->
match
->
m
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -168,6 +171,16 @@ static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
{
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
);
...
...
@@ -221,6 +234,7 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
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
;
...
...
@@ -242,44 +256,6 @@ static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto,
cs
->
fw
.
ip
.
flags
|=
IPT_F_GOTO
;
}
static
void
nft_ipv4_print_header
(
unsigned
int
format
,
const
char
*
chain
,
const
char
*
pol
,
const
struct
xt_counters
*
counters
,
bool
basechain
,
uint32_t
refs
)
{
print_header
(
format
,
chain
,
pol
,
counters
,
basechain
,
refs
);
}
static
void
print_ipv4_addr
(
const
struct
iptables_command_state
*
cs
,
unsigned
int
format
)
{
char
buf
[
BUFSIZ
];
fputc
(
cs
->
fw
.
ip
.
invflags
&
IPT_INV_SRCIP
?
'!'
:
' '
,
stdout
);
if
(
cs
->
fw
.
ip
.
smsk
.
s_addr
==
0L
&&
!
(
format
&
FMT_NUMERIC
))
printf
(
FMT
(
"%-19s "
,
"%s "
),
"anywhere"
);
else
{
if
(
format
&
FMT_NUMERIC
)
strcpy
(
buf
,
xtables_ipaddr_to_numeric
(
&
cs
->
fw
.
ip
.
src
));
else
strcpy
(
buf
,
xtables_ipaddr_to_anyname
(
&
cs
->
fw
.
ip
.
src
));
strcat
(
buf
,
xtables_ipmask_to_numeric
(
&
cs
->
fw
.
ip
.
smsk
));
printf
(
FMT
(
"%-19s "
,
"%s "
),
buf
);
}
fputc
(
cs
->
fw
.
ip
.
invflags
&
IPT_INV_DSTIP
?
'!'
:
' '
,
stdout
);
if
(
cs
->
fw
.
ip
.
dmsk
.
s_addr
==
0L
&&
!
(
format
&
FMT_NUMERIC
))
printf
(
FMT
(
"%-19s "
,
"-> %s"
),
"anywhere"
);
else
{
if
(
format
&
FMT_NUMERIC
)
strcpy
(
buf
,
xtables_ipaddr_to_numeric
(
&
cs
->
fw
.
ip
.
dst
));
else
strcpy
(
buf
,
xtables_ipaddr_to_anyname
(
&
cs
->
fw
.
ip
.
dst
));
strcat
(
buf
,
xtables_ipmask_to_numeric
(
&
cs
->
fw
.
ip
.
dmsk
));
printf
(
FMT
(
"%-19s "
,
"-> %s"
),
buf
);
}
}
static
void
print_fragment
(
unsigned
int
flags
,
unsigned
int
invflags
,
unsigned
int
format
)
{
...
...
@@ -293,20 +269,19 @@ static void print_fragment(unsigned int flags, unsigned int invflags,
fputc
(
' '
,
stdout
);
}
static
void
nft_ipv4_print_
firewall
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
static
void
nft_ipv4_print_
rule
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
)
{
struct
iptables_command_state
cs
=
{};
nft_rule_to_iptables_command_state
(
r
,
&
cs
);
print_firewall_details
(
&
cs
,
cs
.
jumpto
,
cs
.
fw
.
ip
.
flags
,
cs
.
fw
.
ip
.
invflags
,
cs
.
fw
.
ip
.
proto
,
num
,
format
);
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_ifaces
(
cs
.
fw
.
ip
.
iniface
,
cs
.
fw
.
ip
.
outiface
,
cs
.
fw
.
ip
.
invflags
,
format
);
print_ipv4_addr
(
&
cs
,
format
);
print_ipv4_addr
esses
(
&
cs
.
fw
,
format
);
if
(
format
&
FMT_NOTABLE
)
fputs
(
" "
,
stdout
);
...
...
@@ -320,6 +295,8 @@ static void nft_ipv4_print_firewall(struct nftnl_rule *r, unsigned int num,
if
(
!
(
format
&
FMT_NONEWLINE
))
fputc
(
'\n'
,
stdout
);
xtables_rule_matches_free
(
&
cs
.
matches
);
}
static
void
save_ipv4_addr
(
char
letter
,
const
struct
in_addr
*
addr
,
...
...
@@ -332,11 +309,16 @@ static void save_ipv4_addr(char letter, const struct in_addr *addr,
mask_to_str
(
mask
));
}
static
void
nft_ipv4_save_
firewall
(
const
void
*
data
,
unsigned
int
format
)
static
void
nft_ipv4_save_
rule
(
const
void
*
data
,
unsigned
int
format
)
{
const
struct
iptables_command_state
*
cs
=
data
;
save_firewall_details
(
cs
,
cs
->
fw
.
ip
.
invflags
,
cs
->
fw
.
ip
.
proto
,
save_ipv4_addr
(
's'
,
&
cs
->
fw
.
ip
.
src
,
cs
->
fw
.
ip
.
smsk
.
s_addr
,
cs
->
fw
.
ip
.
invflags
&
IPT_INV_SRCIP
);
save_ipv4_addr
(
'd'
,
&
cs
->
fw
.
ip
.
dst
,
cs
->
fw
.
ip
.
dmsk
.
s_addr
,
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
);
...
...
@@ -346,19 +328,8 @@ static void nft_ipv4_save_firewall(const void *data, unsigned int format)
printf
(
"-f "
);
}
save_ipv4_addr
(
's'
,
&
cs
->
fw
.
ip
.
src
,
cs
->
fw
.
ip
.
smsk
.
s_addr
,
cs
->
fw
.
ip
.
invflags
&
IPT_INV_SRCIP
);
save_ipv4_addr
(
'd'
,
&
cs
->
fw
.
ip
.
dst
,
cs
->
fw
.
ip
.
dmsk
.
s_addr
,
cs
->
fw
.
ip
.
invflags
&
IPT_INV_DSTIP
);
save_matches_and_target
(
cs
->
matches
,
cs
->
target
,
cs
->
jumpto
,
cs
->
fw
.
ip
.
flags
,
&
cs
->
fw
);
if
(
cs
->
target
==
NULL
&&
strlen
(
cs
->
jumpto
)
>
0
)
{
printf
(
"-%c %s"
,
cs
->
fw
.
ip
.
flags
&
IPT_F_GOTO
?
'g'
:
'j'
,
cs
->
jumpto
);
}
printf
(
"
\n
"
);
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
,
...
...
@@ -416,28 +387,6 @@ static void nft_ipv4_post_parse(int command,
" source or destination IP addresses"
);
}
static
void
nft_ipv4_parse_target
(
struct
xtables_target
*
t
,
void
*
data
)
{
struct
iptables_command_state
*
cs
=
data
;
cs
->
target
=
t
;
}
static
bool
nft_ipv4_rule_find
(
struct
nft_family_ops
*
ops
,
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
iptables_command_state
*
cs
=
data
;
return
nft_ipv46_rule_find
(
ops
,
r
,
cs
);
}
static
void
nft_ipv4_save_counters
(
const
void
*
data
)
{
const
struct
iptables_command_state
*
cs
=
data
;
save_counters
(
cs
->
counters
.
pcnt
,
cs
->
counters
.
bcnt
);
}
static
int
nft_ipv4_xlate
(
const
void
*
data
,
struct
xt_xlate
*
xl
)
{
const
struct
iptables_command_state
*
cs
=
data
;
...
...
@@ -450,23 +399,25 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
cs
->
fw
.
ip
.
invflags
&
IPT_INV_VIA_OUT
);
if
(
cs
->
fw
.
ip
.
flags
&
IPT_F_FRAG
)
{
xt_xlate_add
(
xl
,
"ip frag-off %s%x "
,
xt_xlate_add
(
xl
,
"ip frag-off
& 0x1fff
%s%x "
,
cs
->
fw
.
ip
.
invflags
&
IPT_INV_FRAG
?
""
:
"!= "
,
0
);
}
if
(
cs
->
fw
.
ip
.
proto
!=
0
)
{
const
struct
protoent
*
pent
=
getprotobynumber
(
cs
->
fw
.
ip
.
proto
);
char
protonum
[
strlen
(
"255"
)
+
1
];
char
protonum
[
sizeof
(
"65535"
)];
const
char
*
name
=
protonum
;
if
(
!
xlate_find_match
(
cs
,
pent
->
p_name
))
{
snprintf
(
protonum
,
sizeof
(
protonum
),
"%u"
,
cs
->
fw
.
ip
.
proto
);
protonum
[
sizeof
(
protonum
)
-
1
]
=
'\0'
;
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
?
"!= "
:
""
,
pent
?
pent
->
p_name
:
protonum
);
"!= "
:
""
,
name
);
}
}
...
...
@@ -488,7 +439,7 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
return
ret
;
/* Always add counters per rule, as in iptables */
xt_xlate_add
(
xl
,
"counter
"
);
xt_xlate_add
(
xl
,
"counter"
);
ret
=
xlate_action
(
cs
,
!!
(
cs
->
fw
.
ip
.
flags
&
IPT_F_GOTO
),
xl
);
comment
=
xt_xlate_get_comment
(
xl
);
...
...
@@ -504,13 +455,16 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.
parse_meta
=
nft_ipv4_parse_meta
,
.
parse_payload
=
nft_ipv4_parse_payload
,
.
parse_immediate
=
nft_ipv4_parse_immediate
,
.
print_header
=
nft_ipv4_print_header
,
.
print_firewall
=
nft_ipv4_print_firewall
,
.
save_firewall
=
nft_ipv4_save_firewall
,
.
save_counters
=
nft_ipv4_save_counters
,
.
print_header
=
print_header
,
.
print_rule
=
nft_ipv4_print_rule
,
.
save_rule
=
nft_ipv4_save_rule
,
.
save_counters
=
save_counters
,
.
save_chain
=
nft_ipv46_save_chain
,
.
proto_parse
=
nft_ipv4_proto_parse
,
.
post_parse
=
nft_ipv4_post_parse
,
.
parse_target
=
nft_ipv4_parse_target
,
.
rule_find
=
nft_ipv4_rule_find
,
.
parse_target
=
nft_ipv46_parse_target
,
.
rule_to_cs
=
nft_rule_to_iptables_command_state
,
.
clear_cs
=
nft_clear_iptables_command_state
,
.
rule_find
=
nft_ipv46_rule_find
,
.
xlate
=
nft_ipv4_xlate
,
};
iptables/nft-ipv6.c
View file @
dab1e98e
...
...
@@ -44,8 +44,7 @@ static int nft_ipv6_add(struct nftnl_rule *r, void *data)
if
(
cs
->
fw6
.
ipv6
.
proto
!=
0
)
{
op
=
nft_invflags2cmp
(
cs
->
fw6
.
ipv6
.
invflags
,
XT_INV_PROTO
);
add_proto
(
r
,
offsetof
(
struct
ip6_hdr
,
ip6_nxt
),
1
,
cs
->
fw6
.
ipv6
.
proto
,
op
);
add_l4proto
(
r
,
cs
->
fw6
.
ipv6
.
proto
,
op
);
}
if
(
!
IN6_IS_ADDR_UNSPECIFIED
(
&
cs
->
fw6
.
ipv6
.
src
))
{
...
...
@@ -60,15 +59,16 @@ static int nft_ipv6_add(struct nftnl_rule *r, void *data)
&
cs
->
fw6
.
ipv6
.
dst
,
&
cs
->
fw6
.
ipv6
.
dmsk
,
sizeof
(
struct
in6_addr
),
op
);
}
add_compat
(
r
,
cs
->
fw6
.
ipv6
.
proto
,
cs
->
fw6
.
ipv6
.
invflags
);
add_compat
(
r
,
cs
->
fw6
.
ipv6
.
proto
,
cs
->
fw6
.
ipv6
.
invflags
&
XT_INV_PROTO
);
for
(
matchp
=
cs
->
matches
;
matchp
;
matchp
=
matchp
->
next
)
{
/* Use nft built-in comments support instead of comment match */
if
(
strcmp
(
matchp
->
match
->
name
,
"comment"
)
==
0
)
{
ret
=
add_comment
(
r
,
(
char
*
)
matchp
->
match
->
m
->
data
);
if
(
ret
<
0
)
return
ret
;
goto
try_match
;
}
else
{
try_match:
ret
=
add_match
(
r
,
matchp
->
match
->
m
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -114,6 +114,16 @@ static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
{
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
);
...
...
@@ -140,7 +150,7 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6
(
ctx
,
&
cs
->
fw6
.
ipv6
.
smsk
);
ctx
->
flags
&=
~
NFT_XT_CTX_BITWISE
;
}
else
{
memset
(
&
cs
->
fw
.
ip
.
smsk
,
0xff
,
sizeof
(
struct
in6_addr
));
memset
(
&
cs
->
fw
6
.
ip
v6
.
smsk
,
0xff
,
sizeof
(
struct
in6_addr
));
}
if
(
inv
)
...
...
@@ -153,7 +163,7 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6
(
ctx
,
&
cs
->
fw6
.
ipv6
.
dmsk
);
ctx
->
flags
&=
~
NFT_XT_CTX_BITWISE
;
}
else
{
memset
(
&
cs
->
fw
.
ip
.
dmsk
,
0xff
,
sizeof
(
struct
in6_addr
));
memset
(
&
cs
->
fw
6
.
ip
v6
.
dmsk
,
0xff
,
sizeof
(
struct
in6_addr
));
}
if
(
inv
)
...
...
@@ -161,7 +171,6 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
break
;
case
offsetof
(
struct
ip6_hdr
,
ip6_nxt
):
get_cmp_data
(
e
,
&
proto
,
sizeof
(
proto
),
&
inv
);
cs
->
fw6
.
ipv6
.
flags
|=
IP6T_F_PROTO
;
cs
->
fw6
.
ipv6
.
proto
=
proto
;
if
(
inv
)
cs
->
fw6
.
ipv6
.
invflags
|=
IP6T_INV_PROTO
;
...
...
@@ -182,64 +191,24 @@ static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
cs
->
fw6
.
ipv6
.
flags
|=
IP6T_F_GOTO
;
}
static
void
nft_ipv6_print_header
(
unsigned
int
format
,
const
char
*
chain
,
const
char
*
pol
,
const
struct
xt_counters
*
counters
,
bool
basechain
,
uint32_t
refs
)
{
print_header
(
format
,
chain
,
pol
,
counters
,
basechain
,
refs
);
}
static
void
print_ipv6_addr
(
const
struct
iptables_command_state
*
cs
,
unsigned
int
format
)
{
char
buf
[
BUFSIZ
];
fputc
(
cs
->
fw6
.
ipv6
.
invflags
&
IP6T_INV_SRCIP
?
'!'
:
' '
,
stdout
);
if
(
IN6_IS_ADDR_UNSPECIFIED
(
&
cs
->
fw6
.
ipv6
.
src
)
&&
!
(
format
&
FMT_NUMERIC
))
printf
(
FMT
(
"%-19s "
,
"%s "
),
"anywhere"
);
else
{
if
(
format
&
FMT_NUMERIC
)
strcpy
(
buf
,
xtables_ip6addr_to_numeric
(
&
cs
->
fw6
.
ipv6
.
src
));
else
strcpy
(
buf
,
xtables_ip6addr_to_anyname
(
&
cs
->
fw6
.
ipv6
.
src
));
strcat
(
buf
,
xtables_ip6mask_to_numeric
(
&
cs
->
fw6
.
ipv6
.
smsk
));
printf
(
FMT
(
"%-19s "
,
"%s "
),
buf
);
}
fputc
(
cs
->
fw6
.
ipv6
.
invflags
&
IP6T_INV_DSTIP
?
'!'
:
' '
,
stdout
);
if
(
IN6_IS_ADDR_UNSPECIFIED
(
&
cs
->
fw6
.
ipv6
.
dst
)
&&
!
(
format
&
FMT_NUMERIC
))
printf
(
FMT
(
"%-19s "
,
"-> %s"
),
"anywhere"
);
else
{
if
(
format
&
FMT_NUMERIC
)
strcpy
(
buf
,
xtables_ip6addr_to_numeric
(
&
cs
->
fw6
.
ipv6
.
dst
));
else
strcpy
(
buf
,
xtables_ip6addr_to_anyname
(
&
cs
->
fw6
.
ipv6
.
dst
));
strcat
(
buf
,
xtables_ip6mask_to_numeric
(
&
cs
->
fw6
.
ipv6
.
dmsk
));
printf
(
FMT
(
"%-19s "
,
"-> %s"
),
buf
);
}
}
static
void
nft_ipv6_print_firewall
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
static
void
nft_ipv6_print_rule
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
)
{
struct
iptables_command_state
cs
=
{};
nft_rule_to_iptables_command_state
(
r
,
&
cs
);
print_
firewall
_details
(
&
cs
,
cs
.
jumpto
,
cs
.
fw6
.
ipv6
.
flags
,
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_ifaces
(
cs
.
fw6
.
ipv6
.
iniface
,
cs
.
fw6
.
ipv6
.
outiface
,
cs
.
fw6
.
ipv6
.
invflags
,
format
);
print_ipv6_addr
(
&
cs
,
format
);
print_ipv6_addr
esses
(
&
cs
.
fw6
,
format
);
if
(
format
&
FMT_NOTABLE
)
fputs
(
" "
,
stdout
);
...
...
@@ -251,42 +220,45 @@ static void nft_ipv6_print_firewall(struct nftnl_rule *r, unsigned int num,
if
(
!
(
format
&
FMT_NONEWLINE
))
fputc
(
'\n'
,
stdout
);
xtables_rule_matches_free
(
&
cs
.
matches
);
}
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
&&
IN6_IS_ADDR_UNSPECIFIED
(
addr
)
)
if
(
!
invert
&&
l
==
0
)
return
;
inet_ntop
(
AF_INET6
,
addr
,
addr_str
,
INET6_ADDRSTRLEN
);
printf
(
"%s-%c %s "
,
invert
?
"! "
:
""
,
letter
,
addr_str
);
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
);
}
static
void
nft_ipv6_save_
firewall
(
const
void
*
data
,
unsigned
int
format
)
static
void
nft_ipv6_save_
rule
(
const
void
*
data
,
unsigned
int
format
)
{
const
struct
iptables_command_state
*
cs
=
data
;
save_firewall_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_ipv6_addr
(
's'
,
&
cs
->
fw6
.
ipv6
.
src
,
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
,
save_ipv6_addr
(
'd'
,
&
cs
->
fw6
.
ipv6
.
dst
,
&
cs
->
fw6
.
ipv6
.
dmsk
,
cs
->
fw6
.
ipv6
.
invflags
&
IP6T_INV_DSTIP
);
save_matches_and_target
(
cs
->
matches
,
cs
->
target
,
cs
->
jumpto
,
cs
->
fw6
.
ipv6
.
flags
,
&
cs
->
fw6
);
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
);
if
(
cs
->
target
==
NULL
&&
strlen
(
cs
->
jumpto
)
>
0
)
{
printf
(
"-%c %s"
,
cs
->
fw6
.
ipv6
.
flags
&
IP6T_F_GOTO
?
'g'
:
'j'
,
cs
->
jumpto
);
}
printf
(
"
\n
"
);
save_matches_and_target
(
cs
,
cs
->
fw6
.
ipv6
.
flags
&
IP6T_F_GOTO
,
&
cs
->
fw6
,
format
);
}
/* These are invalid numbers as upper layer protocol */
...
...
@@ -315,9 +287,6 @@ static void nft_ipv6_proto_parse(struct iptables_command_state *cs,
static
void
nft_ipv6_post_parse
(
int
command
,
struct
iptables_command_state
*
cs
,
struct
xtables_args
*
args
)
{
if
(
args
->
proto
!=
0
)
args
->
flags
|=
IP6T_F_PROTO
;
cs
->
fw6
.
ipv6
.
flags
=
args
->
flags
;
/* We already set invflags in proto_parse, but we need to refresh it
* to include new parsed options.
...
...
@@ -364,28 +333,6 @@ static void nft_ipv6_post_parse(int command, struct iptables_command_state *cs,
" source or destination IP addresses"
);
}
static
void
nft_ipv6_parse_target
(
struct
xtables_target
*
t
,
void
*
data
)
{
struct
iptables_command_state
*
cs
=
data
;
cs
->
target
=
t
;
}
static
bool
nft_ipv6_rule_find
(
struct
nft_family_ops
*
ops
,
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
iptables_command_state
*
cs
=
data
;
return
nft_ipv46_rule_find
(
ops
,
r
,
cs
);
}
static
void
nft_ipv6_save_counters
(
const
void
*
data
)
{
const
struct
iptables_command_state
*
cs
=
data
;
save_counters
(
cs
->
counters
.
pcnt
,
cs
->
counters
.
bcnt
);
}
static
void
xlate_ipv6_addr
(
const
char
*
selector
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
int
invert
,
struct
xt_xlate
*
xl
)
...
...
@@ -414,17 +361,20 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
if
(
cs
->
fw6
.
ipv6
.
proto
!=
0
)
{
const
struct
protoent
*
pent
=
getprotobynumber
(
cs
->
fw6
.
ipv6
.
proto
);
char
protonum
[
strlen
(
"255"
)
+
1
];
char
protonum
[
sizeof
(
"65535"
)];
const
char
*
name
=
protonum
;
if
(
!
xlate_find_match
(
cs
,
pent
->
p_name
))
{
snprintf
(
protonum
,
sizeof
(
protonum
),
"%u"
,
cs
->
fw6
.
ipv6
.
proto
);
protonum
[
sizeof
(
protonum
)
-
1
]
=
'\0'
;
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
?
"!= "
:
""
,
pent
?
pent
->
p_name
:
protonum
);
"!= "
:
""
,
name
);
}
}
xlate_ipv6_addr
(
"ip6 saddr"
,
&
cs
->
fw6
.
ipv6
.
src
,
&
cs
->
fw6
.
ipv6
.
smsk
,
...
...
@@ -437,7 +387,7 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
return
ret
;
/* Always add counters per rule, as in iptables */
xt_xlate_add
(
xl
,
"counter
"
);
xt_xlate_add
(
xl
,
"counter"
);
ret
=
xlate_action
(
cs
,
!!
(
cs
->
fw6
.
ipv6
.
flags
&
IP6T_F_GOTO
),
xl
);
comment
=
xt_xlate_get_comment
(
xl
);
...
...
@@ -453,13 +403,16 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.
parse_meta
=
nft_ipv6_parse_meta
,
.
parse_payload
=
nft_ipv6_parse_payload
,
.
parse_immediate
=
nft_ipv6_parse_immediate
,
.
print_header
=
nft_ipv6_print_header
,
.
print_firewall
=
nft_ipv6_print_firewall
,
.
save_firewall
=
nft_ipv6_save_firewall
,
.
save_counters
=
nft_ipv6_save_counters
,
.
print_header
=
print_header
,
.
print_rule
=
nft_ipv6_print_rule
,
.
save_rule
=
nft_ipv6_save_rule
,
.
save_counters
=
save_counters
,
.
save_chain
=
nft_ipv46_save_chain
,
.
proto_parse
=
nft_ipv6_proto_parse
,
.
post_parse
=
nft_ipv6_post_parse
,
.
parse_target
=
nft_ipv6_parse_target
,
.
rule_find
=
nft_ipv6_rule_find
,
.
parse_target
=
nft_ipv46_parse_target
,
.
rule_to_cs
=
nft_rule_to_iptables_command_state
,
.
clear_cs
=
nft_clear_iptables_command_state
,
.
rule_find
=
nft_ipv46_rule_find
,
.
xlate
=
nft_ipv6_xlate
,
};
iptables/nft-shared.c
View file @
dab1e98e
...
...
@@ -16,10 +16,13 @@
#include <stdbool.h>
#include <netdb.h>
#include <errno.h>
#include <inttypes.h>
#include <xtables.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/xt_comment.h>
#include <linux/netfilter/xt_limit.h>
#include <libmnl/libmnl.h>
#include <libnftnl/rule.h>
...
...
@@ -83,7 +86,7 @@ void add_bitwise_u16(struct nftnl_rule *r, int mask, int xor)
nftnl_rule_add_expr
(
r
,
expr
);
}
static
void
add_bitwise
(
struct
nftnl_rule
*
r
,
uint8_t
*
mask
,
size_t
len
)
void
add_bitwise
(
struct
nftnl_rule
*
r
,
uint8_t
*
mask
,
size_t
len
)
{
struct
nftnl_expr
*
expr
;
uint32_t
xor
[
4
]
=
{
0
};
...
...
@@ -138,9 +141,10 @@ void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
iface_len
=
strlen
(
iface
);
add_meta
(
r
,
NFT_META_IIFNAME
);
if
(
iface
[
iface_len
-
1
]
==
'+'
)
if
(
iface
[
iface_len
-
1
]
==
'+'
)
{
if
(
iface_len
>
1
)
add_cmp_ptr
(
r
,
op
,
iface
,
iface_len
-
1
);
else
}
else
add_cmp_ptr
(
r
,
op
,
iface
,
iface_len
+
1
);
}
...
...
@@ -151,16 +155,27 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
iface_len
=
strlen
(
iface
);
add_meta
(
r
,
NFT_META_OIFNAME
);
if
(
iface
[
iface_len
-
1
]
==
'+'
)
if
(
iface
[
iface_len
-
1
]
==
'+'
)
{
if
(
iface_len
>
1
)
add_cmp_ptr
(
r
,
op
,
iface
,
iface_len
-
1
);
else
}
else
add_cmp_ptr
(
r
,
op
,
iface
,
iface_len
+
1
);
}
void
add_addr
(
struct
nftnl_rule
*
r
,
int
offset
,
void
*
data
,
void
*
mask
,
size_t
len
,
uint32_t
op
)
{
const
char
*
m
=
mask
;
int
i
;
add_payload
(
r
,
offset
,
len
,
NFT_PAYLOAD_NETWORK_HEADER
);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
m
[
i
]
!=
0xff
)
break
;
}
if
(
i
!=
len
)
add_bitwise
(
r
,
mask
,
len
);
add_cmp_ptr
(
r
,
op
,
data
,
len
);
...
...
@@ -173,6 +188,12 @@ void add_proto(struct nftnl_rule *r, int offset, size_t len,
add_cmp_u8
(
r
,
proto
,
op
);
}
void
add_l4proto
(
struct
nftnl_rule
*
r
,
uint8_t
proto
,
uint32_t
op
)
{
add_meta
(
r
,
NFT_META_L4PROTO
);
add_cmp_u8
(
r
,
proto
,
op
);
}
bool
is_same_interfaces
(
const
char
*
a_iniface
,
const
char
*
a_outiface
,
unsigned
const
char
*
a_iniface_mask
,
unsigned
const
char
*
a_outiface_mask
,
...
...
@@ -207,6 +228,30 @@ 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
)
{
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
+
1
);
}
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
)
...
...
@@ -234,35 +279,21 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
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
;
memcpy
(
iniface
,
ifname
,
len
);
if
(
iniface
[
len
]
==
'\0'
)
memset
(
iniface_mask
,
0xff
,
len
);
else
{
iniface
[
len
]
=
'+'
;
iniface
[
len
+
1
]
=
'\0'
;
memset
(
iniface_mask
,
0xff
,
len
+
1
);
}
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
;
memcpy
(
outiface
,
ifname
,
len
);
if
(
outiface
[
len
]
==
'\0'
)
memset
(
outiface_mask
,
0xff
,
len
);
else
{
outiface
[
len
]
=
'+'
;
outiface
[
len
+
1
]
=
'\0'
;
memset
(
outiface_mask
,
0xff
,
len
+
1
);
}
parse_ifname
(
ifname
,
len
,
outiface
,
outiface_mask
);
break
;
default:
return
-
1
;
...
...
@@ -271,22 +302,6 @@ int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
return
0
;
}
static
void
*
nft_get_data
(
struct
nft_xt_ctx
*
ctx
)
{
switch
(
ctx
->
family
)
{
case
NFPROTO_IPV4
:
case
NFPROTO_IPV6
:
return
ctx
->
state
.
cs
;
case
NFPROTO_ARP
:
return
ctx
->
state
.
cs_arp
;
case
NFPROTO_BRIDGE
:
return
ctx
->
state
.
cs_eb
;
default:
/* Should not happen */
return
NULL
;
}
}
void
nft_parse_target
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
)
{
uint32_t
tg_len
;
...
...
@@ -296,7 +311,7 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
struct
xt_entry_target
*
t
;
size_t
size
;
struct
nft_family_ops
*
ops
;
void
*
data
=
nft_get_data
(
ctx
)
;
void
*
data
=
ctx
->
cs
;
target
=
xtables_find_target
(
targname
,
XTF_TRY_LOAD
);
if
(
target
==
NULL
)
...
...
@@ -304,11 +319,7 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
size
=
XT_ALIGN
(
sizeof
(
struct
xt_entry_target
))
+
tg_len
;
t
=
calloc
(
1
,
size
);
if
(
t
==
NULL
)
{
fprintf
(
stderr
,
"OOM"
);
exit
(
EXIT_FAILURE
);
}
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
);
...
...
@@ -333,10 +344,8 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
switch
(
ctx
->
family
)
{
case
NFPROTO_IPV4
:
case
NFPROTO_IPV6
:
matches
=
&
ctx
->
state
.
cs
->
matches
;
break
;
case
NFPROTO_BRIDGE
:
matches
=
&
ctx
->
s
tate
.
cs_eb
->
matches
;
matches
=
&
ctx
->
c
s
->
matches
;
break
;
default:
fprintf
(
stderr
,
"BUG: nft_parse_match() unknown family %d
\n
"
,
...
...
@@ -348,12 +357,7 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
if
(
match
==
NULL
)
return
;
m
=
calloc
(
1
,
sizeof
(
struct
xt_entry_match
)
+
mt_len
);
if
(
m
==
NULL
)
{
fprintf
(
stderr
,
"OOM"
);
exit
(
EXIT_FAILURE
);
}
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
);
...
...
@@ -363,7 +367,7 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ops
=
nft_family_ops_lookup
(
ctx
->
family
);
if
(
ops
->
parse_match
!=
NULL
)
ops
->
parse_match
(
match
,
nft_get_data
(
ctx
)
);
ops
->
parse_match
(
match
,
ctx
->
cs
);
}
void
print_proto
(
uint16_t
proto
,
int
invert
)
...
...
@@ -394,10 +398,54 @@ void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
*
inv
=
false
;
}
static
void
nft_meta_set_to_target
(
struct
nft_xt_ctx
*
ctx
)
{
const
struct
nft_family_ops
*
ops
;
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
;
ops
=
nft_family_ops_lookup
(
ctx
->
family
);
ops
->
parse_target
(
target
,
ctx
->
cs
);
}
void
nft_parse_meta
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
)
{
ctx
->
reg
=
nftnl_expr_get_u32
(
e
,
NFTNL_EXPR_META_DREG
);
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
;
}
...
...
@@ -427,7 +475,7 @@ void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
void
nft_parse_cmp
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
)
{
struct
nft_family_ops
*
ops
=
nft_family_ops_lookup
(
ctx
->
family
);
void
*
data
=
nft_get_data
(
ctx
)
;
void
*
data
=
ctx
->
cs
;
uint32_t
reg
;
reg
=
nftnl_expr_get_u32
(
e
,
NFTNL_EXPR_CMP_SREG
);
...
...
@@ -453,13 +501,30 @@ void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters)
void
nft_parse_immediate
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
)
{
int
verdict
=
nftnl_expr_get_u32
(
e
,
NFTNL_EXPR_IMM_VERDICT
);
const
char
*
chain
=
nftnl_expr_get_str
(
e
,
NFTNL_EXPR_IMM_CHAIN
);
struct
nft_family_ops
*
ops
;
const
char
*
jumpto
=
NULL
;
bool
nft_goto
=
false
;
void
*
data
=
nft_get_data
(
ctx
);
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
:
...
...
@@ -473,6 +538,7 @@ void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
break
;;
case
NFT_GOTO
:
nft_goto
=
true
;
/* fall through */
case
NFT_JUMP
:
jumpto
=
chain
;
break
;
...
...
@@ -482,14 +548,57 @@ void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ops
->
parse_immediate
(
jumpto
,
nft_goto
,
data
);
}
void
nft_rule_to_iptables_command_state
(
struct
nftnl_rule
*
r
,
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
nft_family_ops
*
ops
;
struct
xt_rateinfo
*
rinfo
;
size_t
size
;
switch
(
ctx
->
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
->
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
;
ops
=
nft_family_ops_lookup
(
ctx
->
family
);
if
(
ops
->
parse_match
!=
NULL
)
ops
->
parse_match
(
match
,
ctx
->
cs
);
}
void
nft_rule_to_iptables_command_state
(
const
struct
nftnl_rule
*
r
,
struct
iptables_command_state
*
cs
)
{
struct
nftnl_expr_iter
*
iter
;
struct
nftnl_expr
*
expr
;
int
family
=
nftnl_rule_get_u32
(
r
,
NFTNL_RULE_FAMILY
);
struct
nft_xt_ctx
ctx
=
{
.
state
.
cs
=
cs
,
.
cs
=
cs
,
.
family
=
family
,
};
...
...
@@ -504,7 +613,7 @@ void nft_rule_to_iptables_command_state(struct nftnl_rule *r,
nftnl_expr_get_str
(
expr
,
NFTNL_EXPR_NAME
);
if
(
strcmp
(
name
,
"counter"
)
==
0
)
nft_parse_counter
(
expr
,
&
ctx
.
state
.
cs
->
counters
);
nft_parse_counter
(
expr
,
&
ctx
.
cs
->
counters
);
else
if
(
strcmp
(
name
,
"payload"
)
==
0
)
nft_parse_payload
(
&
ctx
,
expr
);
else
if
(
strcmp
(
name
,
"meta"
)
==
0
)
...
...
@@ -519,6 +628,8 @@ void nft_rule_to_iptables_command_state(struct nftnl_rule *r,
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
);
expr
=
nftnl_expr_iter_next
(
iter
);
}
...
...
@@ -527,7 +638,7 @@ void nft_rule_to_iptables_command_state(struct nftnl_rule *r,
if
(
nftnl_rule_is_set
(
r
,
NFTNL_RULE_USERDATA
))
{
const
void
*
data
;
uint32_t
len
;
uint32_t
len
,
size
;
struct
xtables_match
*
match
;
struct
xt_entry_match
*
m
;
...
...
@@ -537,14 +648,12 @@ void nft_rule_to_iptables_command_state(struct nftnl_rule *r,
if
(
match
==
NULL
)
return
;
m
=
calloc
(
1
,
sizeof
(
struct
xt_entry_match
)
+
len
);
if
(
m
==
NULL
)
{
fprintf
(
stderr
,
"OOM"
);
exit
(
EXIT_FAILURE
);
}
size
=
XT_ALIGN
(
sizeof
(
struct
xt_entry_match
))
+
match
->
size
;
m
=
xtables_calloc
(
1
,
size
);
memcpy
(
&
m
->
data
,
get_comment
(
data
,
len
),
len
);
m
->
u
.
match_size
=
len
+
XT_ALIGN
(
sizeof
(
struct
xt_entry_match
));
strncpy
((
char
*
)
m
->
data
,
get_comment
(
data
,
len
),
match
->
size
-
1
);
m
->
u
.
match_size
=
size
;
m
->
u
.
user
.
revision
=
0
;
strcpy
(
m
->
u
.
user
.
name
,
match
->
name
);
...
...
@@ -559,9 +668,16 @@ void nft_rule_to_iptables_command_state(struct nftnl_rule *r,
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
);
}
void
print_header
(
unsigned
int
format
,
const
char
*
chain
,
const
char
*
pol
,
const
struct
xt_counters
*
counters
,
bool
basechain
,
uint32_t
refs
)
uint32_t
refs
,
uint32_t
entries
)
{
printf
(
"Chain %s"
,
chain
);
if
(
basechain
)
{
...
...
@@ -603,7 +719,7 @@ void print_header(unsigned int format, const char *chain, const char *pol,
printf
(
"
\n
"
);
}
void
print_
firewall
_details
(
const
struct
iptables_command_state
*
cs
,
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
)
...
...
@@ -630,45 +746,6 @@ void print_firewall_details(const struct iptables_command_state *cs,
}
}
void
print_ifaces
(
const
char
*
iniface
,
const
char
*
outiface
,
uint8_t
invflags
,
unsigned
int
format
)
{
char
iface
[
IFNAMSIZ
+
2
];
if
(
!
(
format
&
FMT_VIA
))
return
;
if
(
invflags
&
IPT_INV_VIA_IN
)
{
iface
[
0
]
=
'!'
;
iface
[
1
]
=
'\0'
;
}
else
iface
[
0
]
=
'\0'
;
if
(
iniface
[
0
]
!=
'\0'
)
strcat
(
iface
,
iniface
);
else
if
(
format
&
FMT_NUMERIC
)
strcat
(
iface
,
"*"
);
else
strcat
(
iface
,
"any"
);
printf
(
FMT
(
" %-6s "
,
"in %s "
),
iface
);
if
(
invflags
&
IPT_INV_VIA_OUT
)
{
iface
[
0
]
=
'!'
;
iface
[
1
]
=
'\0'
;
}
else
iface
[
0
]
=
'\0'
;
if
(
outiface
[
0
]
!=
'\0'
)
strcat
(
iface
,
outiface
);
else
if
(
format
&
FMT_NUMERIC
)
strcat
(
iface
,
"*"
);
else
strcat
(
iface
,
"any"
);
printf
(
FMT
(
"%-6s "
,
"out %s "
),
iface
);
}
static
void
print_iface
(
char
letter
,
const
char
*
iface
,
const
unsigned
char
*
mask
,
int
inv
)
{
...
...
@@ -693,7 +770,7 @@ print_iface(char letter, const char *iface, const unsigned char *mask, int inv)
printf
(
" "
);
}
void
save_
firewall
_details
(
const
struct
iptables_command_state
*
cs
,
void
save_
rule
_details
(
const
struct
iptables_command_state
*
cs
,
uint8_t
invflags
,
uint16_t
proto
,
const
char
*
iniface
,
unsigned
const
char
*
iniface_mask
,
...
...
@@ -722,19 +799,31 @@ void save_firewall_details(const struct iptables_command_state *cs,
}
}
void
save_counters
(
uint64_t
pcnt
,
uint64_t
bcnt
)
void
save_counters
(
const
void
*
data
)
{
const
struct
iptables_command_state
*
cs
=
data
;
printf
(
"[%llu:%llu] "
,
(
unsigned
long
long
)
cs
->
counters
.
pcnt
,
(
unsigned
long
long
)
cs
->
counters
.
bcnt
);
}
void
nft_ipv46_save_chain
(
const
struct
nftnl_chain
*
c
,
const
char
*
policy
)
{
printf
(
"[%llu:%llu] "
,
(
unsigned
long
long
)
pcnt
,
(
unsigned
long
long
)
bcnt
);
const
char
*
chain
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_NAME
);
uint64_t
pkts
=
nftnl_chain_get_u64
(
c
,
NFTNL_CHAIN_PACKETS
);
uint64_t
bytes
=
nftnl_chain_get_u64
(
c
,
NFTNL_CHAIN_BYTES
);
printf
(
":%s %s [%"
PRIu64
":%"
PRIu64
"]
\n
"
,
chain
,
policy
?:
"-"
,
pkts
,
bytes
);
}
void
save_matches_and_target
(
struct
x
tables_
rule_match
*
m
,
struct
xtables_target
*
target
,
const
char
*
jumpto
,
uint8_t
flags
,
const
void
*
fw
)
void
save_matches_and_target
(
const
struct
ip
tables_
command_state
*
cs
,
bool
goto_flag
,
const
void
*
fw
,
unsigned
int
format
)
{
struct
xtables_rule_match
*
matchp
;
for
(
matchp
=
m
;
matchp
;
matchp
=
matchp
->
next
)
{
for
(
matchp
=
cs
->
matches
;
matchp
;
matchp
=
matchp
->
next
)
{
if
(
matchp
->
match
->
alias
)
{
printf
(
"-m %s"
,
matchp
->
match
->
alias
(
matchp
->
match
->
m
));
...
...
@@ -748,15 +837,24 @@ void save_matches_and_target(struct xtables_rule_match *m,
printf
(
" "
);
}
if
(
target
!=
NULL
)
{
if
(
target
->
alias
)
{
printf
(
"-j %s"
,
target
->
alias
(
target
->
t
));
if
((
format
&
(
FMT_NOCOUNTS
|
FMT_C_COUNTS
))
==
FMT_C_COUNTS
)
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
));
}
else
printf
(
"-j %s"
,
jumpto
);
printf
(
"-j %s"
,
cs
->
jumpto
);
if
(
target
->
save
!=
NULL
)
target
->
save
(
fw
,
target
->
t
);
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
(
"
\n
"
);
}
void
print_matches_and_target
(
struct
iptables_command_state
*
cs
,
...
...
@@ -838,7 +936,9 @@ bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2)
if
(
tg1
==
NULL
&&
tg2
==
NULL
)
return
true
;
if
((
tg1
==
NULL
&&
tg2
!=
NULL
)
||
(
tg1
!=
NULL
&&
tg2
==
NULL
))
if
(
tg1
==
NULL
||
tg2
==
NULL
)
return
false
;
if
(
tg1
->
userspacesize
!=
tg2
->
userspacesize
)
return
false
;
if
(
strcmp
(
tg1
->
t
->
u
.
user
.
name
,
tg2
->
t
->
u
.
user
.
name
)
!=
0
)
...
...
@@ -850,16 +950,23 @@ 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
;
}
bool
nft_ipv46_rule_find
(
struct
nft_family_ops
*
ops
,
struct
nftnl_rule
*
r
,
struct
iptables_command_state
*
cs
)
struct
nftnl_rule
*
r
,
void
*
data
)
{
struct
iptables_command_state
this
=
{};
struct
iptables_command_state
*
cs
=
data
,
this
=
{};
nft_rule_to_iptables_command_state
(
r
,
&
this
);
DEBUGP
(
"comparing with... "
);
#ifdef DEBUG_DEL
nft_rule_print_save
(
&
this
,
r
,
NFT_RULE_APPEND
,
0
);
nft_rule_print_save
(
r
,
NFT_RULE_APPEND
,
0
);
#endif
if
(
!
ops
->
is_same
(
cs
,
&
this
))
return
false
;
...
...
@@ -881,3 +988,32 @@ bool nft_ipv46_rule_find(struct nft_family_ops *ops,
return
true
;
}
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"
;
const
char
*
prefix
=
"ip"
;
FILE
*
fp
=
NULL
;
char
buf
[
1024
];
switch
(
family
)
{
case
NFPROTO_IPV4
:
fp
=
fopen
(
tables4
,
"r"
);
break
;
case
NFPROTO_IPV6
:
fp
=
fopen
(
tables6
,
"r"
);
prefix
=
"ip6"
;
break
;
default:
break
;
}
if
(
!
fp
)
return
;
if
(
fgets
(
buf
,
sizeof
(
buf
),
fp
))
fprintf
(
stderr
,
"# Warning: %stables-legacy tables present, use %stables-legacy%s to see them
\n
"
,
prefix
,
prefix
,
is_ipt_save
?
"-save"
:
""
);
fclose
(
fp
);
}
iptables/nft-shared.h
View file @
dab1e98e
...
...
@@ -5,17 +5,15 @@
#include <libnftnl/rule.h>
#include <libnftnl/expr.h>
#include <libnftnl/chain.h>
#include <linux/netfilter_arp/arp_tables.h>
#include "xshared.h"
#if 0
#define DEBUGP(x, args...) fprintf(stdout, x, ## args)
#ifdef DEBUG
#define NLDEBUG
#define DEBUG_DEL
#else
#define DEBUGP(x, args...)
#endif
/*
...
...
@@ -43,14 +41,11 @@ 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
),
};
struct
nft_xt_ctx
{
union
{
struct
iptables_command_state
*
cs
;
struct
arptables_command_state
*
cs_arp
;
struct
ebtables_command_state
*
cs_eb
;
}
state
;
struct
nftnl_expr_iter
*
iter
;
int
family
;
uint32_t
flags
;
...
...
@@ -63,6 +58,10 @@ struct nft_xt_ctx {
struct
{
uint32_t
key
;
}
meta
;
struct
{
uint32_t
data
[
4
];
uint32_t
len
,
reg
;
}
immediate
;
struct
{
uint32_t
mask
[
4
];
uint32_t
xor
[
4
];
...
...
@@ -89,17 +88,21 @@ struct nft_family_ops {
void
(
*
print_header
)(
unsigned
int
format
,
const
char
*
chain
,
const
char
*
pol
,
const
struct
xt_counters
*
counters
,
bool
basechain
,
uint32_t
refs
);
void
(
*
print_
firewall
)(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
uint32_t
refs
,
uint32_t
entries
);
void
(
*
print_
rule
)(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
);
void
(
*
save_
firewall
)(
const
void
*
data
,
unsigned
int
format
);
void
(
*
save_
rule
)(
const
void
*
data
,
unsigned
int
format
);
void
(
*
save_counters
)(
const
void
*
data
);
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
)(
const
struct
nftnl_rule
*
r
,
struct
iptables_command_state
*
cs
);
void
(
*
clear_cs
)(
struct
iptables_command_state
*
cs
);
bool
(
*
rule_find
)(
struct
nft_family_ops
*
ops
,
struct
nftnl_rule
*
r
,
void
*
data
);
int
(
*
xlate
)(
const
void
*
data
,
struct
xt_xlate
*
xl
);
...
...
@@ -107,6 +110,7 @@ struct nft_family_ops {
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
,
int
mask
,
int
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
);
...
...
@@ -118,6 +122,7 @@ void add_addr(struct nftnl_rule *r, int offset,
void
*
data
,
void
*
mask
,
size_t
len
,
uint32_t
op
);
void
add_proto
(
struct
nftnl_rule
*
r
,
int
offset
,
size_t
len
,
uint8_t
proto
,
uint32_t
op
);
void
add_l4proto
(
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
,
...
...
@@ -140,36 +145,36 @@ void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e);
void
nft_parse_payload
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
);
void
nft_parse_counter
(
struct
nftnl_expr
*
e
,
struct
xt_counters
*
counters
);
void
nft_parse_immediate
(
struct
nft_xt_ctx
*
ctx
,
struct
nftnl_expr
*
e
);
void
nft_rule_to_iptables_command_state
(
struct
nftnl_rule
*
r
,
void
nft_rule_to_iptables_command_state
(
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
);
void
print_
firewall
_details
(
const
struct
iptables_command_state
*
cs
,
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_ifaces
(
const
char
*
iniface
,
const
char
*
outiface
,
uint8_t
invflags
,
unsigned
int
format
);
void
print_matches_and_target
(
struct
iptables_command_state
*
cs
,
unsigned
int
format
);
void
save_
firewall
_details
(
const
struct
iptables_command_state
*
cs
,
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
save_counters
(
uint64_t
pcnt
,
uint64_t
bcnt
);
void
save_matches_and_target
(
struct
xtables_rule_match
*
m
,
struct
x
tables_
target
*
target
,
const
char
*
jumpto
,
u
int8_t
flags
,
const
void
*
fw
);
void
save_counters
(
const
void
*
data
);
void
nft_ipv46_save_chain
(
const
struct
nftnl_chain
*
c
,
const
char
*
policy
);
void
save_matches_and_target
(
const
struct
ip
tables_
command_state
*
cs
,
bool
goto_flag
,
const
void
*
fw
,
u
nsigned
int
format
);
struct
nft_family_ops
*
nft_family_ops_lookup
(
int
family
);
struct
nft_handle
;
void
nft_ipv46_parse_target
(
struct
xtables_target
*
t
,
void
*
data
);
bool
nft_ipv46_rule_find
(
struct
nft_family_ops
*
ops
,
struct
nftnl_rule
*
r
,
struct
iptables_command_state
*
cs
);
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
);
...
...
@@ -223,9 +228,9 @@ struct nft_xt_cmd_parse {
unsigned
int
command
;
unsigned
int
rulenum
;
char
*
table
;
char
*
chain
;
char
*
newname
;
char
*
policy
;
const
char
*
chain
;
const
char
*
newname
;
const
char
*
policy
;
bool
restore
;
int
verbose
;
};
...
...
@@ -238,6 +243,7 @@ struct nft_xt_restore_parse {
FILE
*
in
;
int
testing
;
const
char
*
tablename
;
bool
commit
;
};
struct
nftnl_chain_list
;
...
...
@@ -245,17 +251,18 @@ struct nftnl_chain_list;
struct
nft_xt_restore_cb
{
void
(
*
table_new
)(
struct
nft_handle
*
h
,
const
char
*
table
);
struct
nftnl_chain_list
*
(
*
chain_list
)(
struct
nft_handle
*
h
);
int
(
*
chains_purge
)(
struct
nft_handle
*
h
,
const
char
*
table
,
struct
nftnl_chain_list
*
clist
);
void
(
*
chain_del
)(
struct
nftnl_chain_list
*
clist
,
const
char
*
curtable
,
const
char
*
chain
);
int
(
*
chain_user_flush
)(
struct
nft_handle
*
h
,
struct
nftnl_chain_list
*
clist
,
const
char
*
table
,
const
char
*
chain
);
int
(
*
chain_set
)(
struct
nft_handle
*
h
,
const
char
*
table
,
const
char
*
chain
,
const
char
*
policy
,
const
struct
xt_counters
*
counters
);
int
(
*
chain_user_add
)(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
);
int
(
*
ru
le_flush
)(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
);
int
(
*
tab
le_flush
)(
struct
nft_handle
*
h
,
const
char
*
table
);
int
(
*
do_command
)(
struct
nft_handle
*
h
,
int
argc
,
char
*
argv
[],
char
**
table
,
bool
restore
);
...
...
@@ -269,4 +276,5 @@ void xtables_restore_parse(struct nft_handle *h,
struct
nft_xt_restore_cb
*
cb
,
int
argc
,
char
*
argv
[]);
void
nft_check_xt_legacy
(
int
family
,
bool
is_ipt_save
);
#endif
iptables/nft.c
View file @
dab1e98e
...
...
@@ -19,6 +19,7 @@
#include <time.h>
#include <stdarg.h>
#include <inttypes.h>
#include <assert.h>
#include <xtables.h>
#include <libiptc/libxtc.h>
...
...
@@ -37,6 +38,8 @@
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nf_tables_compat.h>
#include <linux/netfilter/xt_limit.h>
#include <libmnl/libmnl.h>
#include <libnftnl/table.h>
#include <libnftnl/chain.h>
...
...
@@ -44,6 +47,7 @@
#include <libnftnl/expr.h>
#include <libnftnl/set.h>
#include <libnftnl/udata.h>
#include <libnftnl/batch.h>
#include <netinet/in.h>
/* inet_ntoa */
#include <arpa/inet.h>
...
...
@@ -60,7 +64,7 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
void
*
data
)
{
int
ret
;
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
char
buf
[
16536
];
if
(
mnl_socket_sendto
(
h
->
nl
,
nlh
,
nlh
->
nlmsg_len
)
<
0
)
return
-
1
;
...
...
@@ -80,13 +84,7 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
return
0
;
}
static
LIST_HEAD
(
batch_page_list
);
static
int
batch_num_pages
;
struct
batch_page
{
struct
list_head
head
;
struct
mnl_nlmsg_batch
*
batch
;
};
#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
...
...
@@ -94,44 +92,74 @@ struct batch_page {
*/
#define BATCH_PAGE_SIZE getpagesize() * 32
static
struct
mnl_nlmsg
_batch
*
mnl_
nftnl_
batch_
alloc
(
void
)
static
struct
nftnl
_batch
*
mnl_batch_
init
(
void
)
{
st
atic
char
*
buf
;
st
ruct
nftnl_batch
*
batch
;
/* libmnl needs higher buffer to handle batch overflows */
buf
=
malloc
(
BATCH_PAGE_SIZE
+
getpagesize
());
if
(
buf
==
NULL
)
batch
=
nftnl_batch_alloc
(
BATCH_PAGE_SIZE
,
NFT_NLMSG_MAXSIZE
);
if
(
batch
==
NULL
)
return
NULL
;
return
mnl_nlmsg_batch_start
(
buf
,
BATCH_PAGE_SIZE
)
;
return
batch
;
}
static
struct
mnl_nlmsg_batch
*
mnl_nftnl_batch_page_add
(
struct
mnl_nlmsg_batch
*
batch
)
static
void
mnl_nft_batch_continue
(
struct
nftnl_batch
*
batch
)
{
struct
batch_page
*
batch_page
;
assert
(
nftnl_batch_update
(
batch
)
>=
0
);
}
batch_page
=
malloc
(
sizeof
(
struct
batch_page
));
if
(
batch_page
==
NULL
)
return
NULL
;
static
uint32_t
mnl_batch_begin
(
struct
nftnl_batch
*
batch
,
uint32_t
seqnum
)
{
nftnl_batch_begin
(
nftnl_batch_buffer
(
batch
),
seqnum
);
mnl_nft_batch_continue
(
batch
);
return
seqnum
;
}
static
void
mnl_batch_end
(
struct
nftnl_batch
*
batch
,
uint32_t
seqnum
)
{
nftnl_batch_end
(
nftnl_batch_buffer
(
batch
),
seqnum
);
mnl_nft_batch_continue
(
batch
);
}
static
void
mnl_batch_reset
(
struct
nftnl_batch
*
batch
)
{
nftnl_batch_free
(
batch
);
}
struct
mnl_err
{
struct
list_head
head
;
int
err
;
uint32_t
seqnum
;
};
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
));
batch_page
->
batch
=
batch
;
list_add_tail
(
&
batch_page
->
head
,
&
batch_page_list
);
batch_num_pages
++
;
err
->
seqnum
=
seqnum
;
err
->
err
=
error
;
list_add_tail
(
&
err
->
head
,
err_list
);
}
return
mnl_nftnl_batch_alloc
();
static
void
mnl_err_list_free
(
struct
mnl_err
*
err
)
{
list_del
(
&
err
->
head
);
free
(
err
);
}
static
int
nlbuffsiz
;
static
void
mnl_nft_set_sndbuffer
(
const
struct
mnl_socket
*
nl
)
static
void
mnl_set_sndbuffer
(
const
struct
mnl_socket
*
nl
,
struct
nftnl_batch
*
batch
)
{
int
newbuffsiz
;
if
(
batch_num_pages
*
BATCH_PAGE_SIZE
<=
nlbuffsiz
)
if
(
nftnl_batch_iovec_len
(
batch
)
*
BATCH_PAGE_SIZE
<=
nlbuffsiz
)
return
;
newbuffsiz
=
batch_num_pages
*
BATCH_PAGE_SIZE
;
newbuffsiz
=
nftnl_batch_iovec_len
(
batch
)
*
BATCH_PAGE_SIZE
;
/* Rise sender buffer length to avoid hitting -EMSGSIZE */
if
(
setsockopt
(
mnl_socket_get_fd
(
nl
),
SOL_SOCKET
,
SO_SNDBUFFORCE
,
...
...
@@ -141,56 +169,32 @@ static void mnl_nft_set_sndbuffer(const struct mnl_socket *nl)
nlbuffsiz
=
newbuffsiz
;
}
static
void
mnl_nftnl_batch_reset
(
void
)
{
struct
batch_page
*
batch_page
,
*
next
;
list_for_each_entry_safe
(
batch_page
,
next
,
&
batch_page_list
,
head
)
{
list_del
(
&
batch_page
->
head
);
free
(
batch_page
->
batch
);
free
(
batch_page
);
batch_num_pages
--
;
}
}
static
ssize_t
mnl_nft_socket_sendmsg
(
const
struct
mnl_socket
*
nl
)
static
ssize_t
mnl_nft_socket_sendmsg
(
const
struct
mnl_socket
*
nf_sock
,
struct
nftnl_batch
*
batch
)
{
static
const
struct
sockaddr_nl
snl
=
{
.
nl_family
=
AF_NETLINK
};
struct
iovec
iov
[
batch_num_pages
];
uint32_t
iov_len
=
nftnl_batch_iovec_len
(
batch
);
struct
iovec
iov
[
iov_len
];
struct
msghdr
msg
=
{
.
msg_name
=
(
struct
sockaddr
*
)
&
snl
,
.
msg_namelen
=
sizeof
(
snl
),
.
msg_iov
=
iov
,
.
msg_iovlen
=
batch_num_pages
,
.
msg_iovlen
=
iov_len
,
};
struct
batch_page
*
batch_page
;
int
i
=
0
,
ret
;
mnl_nft_set_sndbuffer
(
nl
);
list_for_each_entry
(
batch_page
,
&
batch_page_list
,
head
)
{
iov
[
i
].
iov_base
=
mnl_nlmsg_batch_head
(
batch_page
->
batch
);
iov
[
i
].
iov_len
=
mnl_nlmsg_batch_size
(
batch_page
->
batch
);
i
++
;
#ifdef NL_DEBUG
mnl_nlmsg_fprintf
(
stdout
,
mnl_nlmsg_batch_head
(
batch_page
->
batch
),
mnl_nlmsg_batch_size
(
batch_page
->
batch
),
sizeof
(
struct
nfgenmsg
));
#endif
}
ret
=
sendmsg
(
mnl_socket_get_fd
(
nl
),
&
msg
,
0
);
mnl_
nftnl_batch_
reset
(
);
mnl_set_sndbuffer
(
nf_sock
,
batch
);
nftnl_batch_
iovec
(
batch
,
iov
,
iov_len
);
return
ret
;
return
sendmsg
(
mnl_socket_get_fd
(
nf_sock
),
&
msg
,
0
)
;
}
static
int
mnl_nftnl_batch_talk
(
struct
nft_handle
*
h
)
static
int
mnl_batch_talk
(
const
struct
mnl_socket
*
nf_sock
,
struct
nftnl_batch
*
batch
,
struct
list_head
*
err_list
)
{
int
ret
,
fd
=
mnl_socket_get_fd
(
h
->
nl
);
const
struct
mnl_socket
*
nl
=
nf_sock
;
int
ret
,
fd
=
mnl_socket_get_fd
(
nl
),
portid
=
mnl_socket_get_portid
(
nl
);
char
rcv_buf
[
MNL_SOCKET_BUFFER_SIZE
];
fd_set
readfds
;
struct
timeval
tv
=
{
...
...
@@ -199,7 +203,7 @@ static int mnl_nftnl_batch_talk(struct nft_handle *h)
};
int
err
=
0
;
ret
=
mnl_nft_socket_sendmsg
(
h
->
nl
);
ret
=
mnl_nft_socket_sendmsg
(
nf_sock
,
batch
);
if
(
ret
==
-
1
)
return
-
1
;
...
...
@@ -212,16 +216,18 @@ static int mnl_nftnl_batch_talk(struct nft_handle *h)
return
-
1
;
while
(
ret
>
0
&&
FD_ISSET
(
fd
,
&
readfds
))
{
ret
=
mnl_socket_recvfrom
(
h
->
nl
,
rcv_buf
,
sizeof
(
rcv_buf
));
struct
nlmsghdr
*
nlh
=
(
struct
nlmsghdr
*
)
rcv_buf
;
ret
=
mnl_socket_recvfrom
(
nl
,
rcv_buf
,
sizeof
(
rcv_buf
));
if
(
ret
==
-
1
)
return
-
1
;
ret
=
mnl_cb_run
(
rcv_buf
,
ret
,
0
,
h
->
portid
,
NULL
,
NULL
);
/*
Annotate first error and continue
, make sure we get all
* acknoledgments.
*/
if
(
!
err
&&
ret
=
=
-
1
)
err
=
errno
;
ret
=
mnl_cb_run
(
rcv_buf
,
ret
,
0
,
portid
,
NULL
,
NULL
);
/*
Continue on error
, make sure we get all
acknowledgments */
if
(
ret
==
-
1
)
{
mnl_err_list_node_add
(
err_list
,
errno
,
nlh
->
nlmsg_seq
);
err
=
-
1
;
}
ret
=
select
(
fd
+
1
,
&
readfds
,
NULL
,
NULL
,
&
tv
);
if
(
ret
==
-
1
)
...
...
@@ -230,31 +236,19 @@ static int mnl_nftnl_batch_talk(struct nft_handle *h)
FD_ZERO
(
&
readfds
);
FD_SET
(
fd
,
&
readfds
);
}
errno
=
err
;
return
err
?
-
1
:
0
;
}
static
void
mnl_nftnl_batch_begin
(
struct
mnl_nlmsg_batch
*
batch
,
uint32_t
seq
)
{
nftnl_batch_begin
(
mnl_nlmsg_batch_current
(
batch
),
seq
);
if
(
!
mnl_nlmsg_batch_next
(
batch
))
mnl_nftnl_batch_page_add
(
batch
);
}
static
void
mnl_nftnl_batch_end
(
struct
mnl_nlmsg_batch
*
batch
,
uint32_t
seq
)
{
nftnl_batch_end
(
mnl_nlmsg_batch_current
(
batch
),
seq
);
if
(
!
mnl_nlmsg_batch_next
(
batch
))
mnl_nftnl_batch_page_add
(
batch
);
return
err
;
}
enum
obj_update_type
{
NFT_COMPAT_TABLE_ADD
,
NFT_COMPAT_TABLE_FLUSH
,
NFT_COMPAT_CHAIN_ADD
,
NFT_COMPAT_CHAIN_USER_ADD
,
NFT_COMPAT_CHAIN_USER_DEL
,
NFT_COMPAT_CHAIN_USER_FLUSH
,
NFT_COMPAT_CHAIN_UPDATE
,
NFT_COMPAT_CHAIN_RENAME
,
NFT_COMPAT_CHAIN_ZERO
,
NFT_COMPAT_RULE_APPEND
,
NFT_COMPAT_RULE_INSERT
,
NFT_COMPAT_RULE_REPLACE
,
...
...
@@ -270,14 +264,82 @@ enum obj_action {
struct
obj_update
{
struct
list_head
head
;
enum
obj_update_type
type
;
unsigned
int
seq
;
union
{
struct
nftnl_table
*
table
;
struct
nftnl_chain
*
chain
;
struct
nftnl_rule
*
rule
;
void
*
ptr
;
};
struct
{
unsigned
int
lineno
;
}
error
;
};
static
int
mnl_append_error
(
const
struct
nft_handle
*
h
,
const
struct
obj_update
*
o
,
const
struct
mnl_err
*
err
,
char
*
buf
,
unsigned
int
len
)
{
static
const
char
*
type_name
[]
=
{
[
NFT_COMPAT_TABLE_ADD
]
=
"TABLE_ADD"
,
[
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_USER_FLUSH
]
=
"CHAIN_USER_FLUSH"
,
[
NFT_COMPAT_CHAIN_UPDATE
]
=
"CHAIN_UPDATE"
,
[
NFT_COMPAT_CHAIN_RENAME
]
=
"CHAIN_RENAME"
,
[
NFT_COMPAT_RULE_APPEND
]
=
"RULE_APPEND"
,
[
NFT_COMPAT_RULE_INSERT
]
=
"RULE_INSERT"
,
[
NFT_COMPAT_RULE_REPLACE
]
=
"RULE_REPLACE"
,
[
NFT_COMPAT_RULE_DELETE
]
=
"RULE_DELETE"
,
[
NFT_COMPAT_RULE_FLUSH
]
=
"RULE_FLUSH"
,
};
char
errmsg
[
256
];
char
tcr
[
128
];
if
(
o
->
error
.
lineno
)
snprintf
(
errmsg
,
sizeof
(
errmsg
),
"
\n
line %u: %s failed (%s)"
,
o
->
error
.
lineno
,
type_name
[
o
->
type
],
strerror
(
err
->
err
));
else
snprintf
(
errmsg
,
sizeof
(
errmsg
),
" %s failed (%s)"
,
type_name
[
o
->
type
],
strerror
(
err
->
err
));
switch
(
o
->
type
)
{
case
NFT_COMPAT_TABLE_ADD
:
case
NFT_COMPAT_TABLE_FLUSH
:
snprintf
(
tcr
,
sizeof
(
tcr
),
"table %s"
,
nftnl_table_get_str
(
o
->
table
,
NFTNL_TABLE_NAME
));
break
;
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_USER_FLUSH
:
case
NFT_COMPAT_CHAIN_UPDATE
:
case
NFT_COMPAT_CHAIN_RENAME
:
snprintf
(
tcr
,
sizeof
(
tcr
),
"chain %s"
,
nftnl_chain_get_str
(
o
->
chain
,
NFTNL_CHAIN_NAME
));
break
;
case
NFT_COMPAT_RULE_APPEND
:
case
NFT_COMPAT_RULE_INSERT
:
case
NFT_COMPAT_RULE_REPLACE
:
case
NFT_COMPAT_RULE_DELETE
:
case
NFT_COMPAT_RULE_FLUSH
:
snprintf
(
tcr
,
sizeof
(
tcr
),
"rule in chain %s"
,
nftnl_rule_get_str
(
o
->
rule
,
NFTNL_RULE_CHAIN
));
#if 0
{
nft_rule_print_save(o->rule, NFT_RULE_APPEND, FMT_NOCOUNTS);
}
#endif
break
;
}
return
snprintf
(
buf
,
len
,
"%s: %s"
,
errmsg
,
tcr
);
}
static
int
batch_add
(
struct
nft_handle
*
h
,
enum
obj_update_type
type
,
void
*
ptr
)
{
struct
obj_update
*
obj
;
...
...
@@ -287,6 +349,7 @@ static int batch_add(struct nft_handle *h, enum obj_update_type type, void *ptr)
return
-
1
;
obj
->
ptr
=
ptr
;
obj
->
error
.
lineno
=
h
->
error
.
lineno
;
obj
->
type
=
type
;
list_add_tail
(
&
obj
->
head
,
&
h
->
obj_list
);
h
->
obj_list_num
++
;
...
...
@@ -454,12 +517,6 @@ struct builtin_table xtables_arp[TABLES_MAX] = {
.
prio
=
NF_IP_PRI_FILTER
,
.
hook
=
NF_ARP_IN
,
},
{
.
name
=
"FORWARD"
,
.
type
=
"filter"
,
.
prio
=
NF_IP_PRI_FILTER
,
.
hook
=
NF_ARP_FORWARD
,
},
{
.
name
=
"OUTPUT"
,
.
type
=
"filter"
,
...
...
@@ -521,30 +578,6 @@ struct builtin_table xtables_bridge[TABLES_MAX] = {
},
};
int
nft_table_add
(
struct
nft_handle
*
h
,
struct
nftnl_table
*
t
,
uint16_t
flags
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
struct
nlmsghdr
*
nlh
;
int
ret
;
nlh
=
nftnl_table_nlmsg_build_hdr
(
buf
,
NFT_MSG_NEWTABLE
,
h
->
family
,
NLM_F_ACK
|
flags
,
h
->
seq
);
nftnl_table_nlmsg_build_payload
(
nlh
,
t
);
nftnl_table_free
(
t
);
#ifdef NLDEBUG
char
tmp
[
1024
];
nft_table_snprintf
(
tmp
,
sizeof
(
tmp
),
t
,
0
,
0
);
printf
(
"DEBUG: table: %s
\n
"
,
tmp
);
mnl_nlmsg_fprintf
(
stdout
,
nlh
,
nlh
->
nlmsg_len
,
sizeof
(
struct
nfgenmsg
));
#endif
ret
=
mnl_talk
(
h
,
nlh
,
NULL
,
NULL
);
return
(
ret
==
0
||
(
ret
==
-
1
&&
errno
==
EEXIST
))
?
0
:
-
1
;
}
static
int
nft_table_builtin_add
(
struct
nft_handle
*
h
,
struct
builtin_table
*
_t
)
{
...
...
@@ -560,13 +593,7 @@ static int nft_table_builtin_add(struct nft_handle *h,
nftnl_table_set
(
t
,
NFTNL_TABLE_NAME
,
(
char
*
)
_t
->
name
);
if
(
h
->
batch_support
)
ret
=
batch_table_add
(
h
,
NFT_COMPAT_TABLE_ADD
,
t
);
else
ret
=
nft_table_add
(
h
,
t
,
NLM_F_EXCL
);
if
(
ret
==
0
)
_t
->
initialized
=
true
;
return
ret
;
}
...
...
@@ -591,29 +618,6 @@ nft_chain_builtin_alloc(struct builtin_table *table,
return
c
;
}
int
nft_chain_add
(
struct
nft_handle
*
h
,
struct
nftnl_chain
*
c
,
uint16_t
flags
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
struct
nlmsghdr
*
nlh
;
/* NLM_F_CREATE requests module autoloading */
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_NEWCHAIN
,
h
->
family
,
NLM_F_ACK
|
flags
|
NLM_F_CREATE
,
h
->
seq
);
nftnl_chain_nlmsg_build_payload
(
nlh
,
c
);
nftnl_chain_free
(
c
);
#ifdef NLDEBUG
char
tmp
[
1024
];
nft_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
return
mnl_talk
(
h
,
nlh
,
NULL
,
NULL
);
}
static
void
nft_chain_builtin_add
(
struct
nft_handle
*
h
,
struct
builtin_table
*
table
,
struct
builtin_chain
*
chain
)
...
...
@@ -624,14 +628,11 @@ static void nft_chain_builtin_add(struct nft_handle *h,
if
(
c
==
NULL
)
return
;
if
(
h
->
batch_support
)
batch_chain_add
(
h
,
NFT_COMPAT_CHAIN_ADD
,
c
);
else
nft_chain_add
(
h
,
c
,
NLM_F_EXCL
);
}
/* find if built-in table already exists */
static
struct
builtin_table
*
struct
builtin_table
*
nft_table_builtin_find
(
struct
nft_handle
*
h
,
const
char
*
table
)
{
int
i
;
...
...
@@ -652,7 +653,7 @@ nft_table_builtin_find(struct nft_handle *h, const char *table)
}
/* find if built-in chain already exists */
static
struct
builtin_chain
*
struct
builtin_chain
*
nft_chain_builtin_find
(
struct
builtin_table
*
t
,
const
char
*
chain
)
{
int
i
;
...
...
@@ -676,7 +677,7 @@ static void nft_chain_builtin_init(struct nft_handle *h,
struct
nftnl_chain
*
c
;
/* Initialize built-in chains if they don't exist yet */
for
(
i
=
0
;
i
<
NF_I
P
_NUMHOOKS
&&
table
->
chains
[
i
].
name
!=
NULL
;
i
++
)
{
for
(
i
=
0
;
i
<
NF_I
NET
_NUMHOOKS
&&
table
->
chains
[
i
].
name
!=
NULL
;
i
++
)
{
c
=
nft_chain_list_find
(
list
,
table
->
name
,
table
->
chains
[
i
].
name
);
...
...
@@ -685,28 +686,27 @@ static void nft_chain_builtin_init(struct nft_handle *h,
nft_chain_builtin_add
(
h
,
table
,
&
table
->
chains
[
i
]);
}
nftnl_chain_list_free
(
list
);
}
static
int
nft_xt_builtin_init
(
struct
nft_handle
*
h
,
const
char
*
table
)
{
int
ret
=
0
;
struct
builtin_table
*
t
;
t
=
nft_table_builtin_find
(
h
,
table
);
if
(
t
==
NULL
)
{
ret
=
-
1
;
goto
out
;
}
if
(
nft_table_builtin_add
(
h
,
t
)
<
0
)
{
/* Built-in table already initialized, skip. */
if
(
errno
==
EEXIST
)
goto
out
;
}
if
(
t
==
NULL
)
ret
urn
-
1
;
if
(
t
->
initialized
)
return
0
;
if
(
nft_table_builtin_add
(
h
,
t
)
<
0
)
return
-
1
;
nft_chain_builtin_init
(
h
,
t
);
out:
return
ret
;
t
->
initialized
=
true
;
return
0
;
}
static
bool
nft_chain_builtin
(
struct
nftnl_chain
*
c
)
...
...
@@ -717,47 +717,20 @@ static bool nft_chain_builtin(struct nftnl_chain *c)
return
nftnl_chain_get
(
c
,
NFTNL_CHAIN_HOOKNUM
)
!=
NULL
;
}
static
bool
mnl_batch_supported
(
struct
nft_handle
*
h
)
static
int
nft_restart
(
struct
nft_handle
*
h
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
uint32_t
seq
=
1
;
int
ret
;
mnl_nftnl_batch_begin
(
h
->
batch
,
seq
++
);
nftnl_set_nlmsg_build_hdr
(
mnl_nlmsg_batch_current
(
h
->
batch
),
NFT_MSG_NEWSET
,
AF_INET
,
NLM_F_ACK
,
seq
++
);
mnl_nlmsg_batch_next
(
h
->
batch
);
mnl_nftnl_batch_end
(
h
->
batch
,
seq
++
);
ret
=
mnl_socket_sendto
(
h
->
nl
,
mnl_nlmsg_batch_head
(
h
->
batch
),
mnl_nlmsg_batch_size
(
h
->
batch
));
if
(
ret
<
0
)
goto
err
;
mnl_socket_close
(
h
->
nl
);
mnl_nlmsg_batch_reset
(
h
->
batch
);
h
->
nl
=
mnl_socket_open
(
NETLINK_NETFILTER
);
if
(
h
->
nl
==
NULL
)
return
-
1
;
ret
=
mnl_socket_recvfrom
(
h
->
nl
,
buf
,
sizeof
(
buf
));
while
(
ret
>
0
)
{
ret
=
mnl_cb_run
(
buf
,
ret
,
0
,
mnl_socket_get_portid
(
h
->
nl
),
NULL
,
NULL
);
if
(
ret
<=
0
)
break
;
if
(
mnl_socket_bind
(
h
->
nl
,
0
,
MNL_SOCKET_AUTOPID
)
<
0
)
return
-
1
;
ret
=
mnl_socket_recvfrom
(
h
->
nl
,
buf
,
sizeof
(
buf
));
}
h
->
portid
=
mnl_socket_get_portid
(
h
->
nl
);
/* We're sending an incomplete message to see if the kernel supports
* set messages in batches. EINVAL means that we sent an incomplete
* message with missing attributes. The kernel just ignores messages
* that we cannot include in the batch.
*/
return
(
ret
==
-
1
&&
errno
==
EINVAL
)
?
true
:
false
;
err:
mnl_nlmsg_batch_reset
(
h
->
batch
);
return
ret
;
return
0
;
}
int
nft_init
(
struct
nft_handle
*
h
,
struct
builtin_table
*
t
)
...
...
@@ -766,35 +739,77 @@ int nft_init(struct nft_handle *h, struct builtin_table *t)
if
(
h
->
nl
==
NULL
)
return
-
1
;
if
(
mnl_socket_bind
(
h
->
nl
,
0
,
MNL_SOCKET_AUTOPID
)
<
0
)
if
(
mnl_socket_bind
(
h
->
nl
,
0
,
MNL_SOCKET_AUTOPID
)
<
0
)
{
mnl_socket_close
(
h
->
nl
);
return
-
1
;
}
h
->
portid
=
mnl_socket_get_portid
(
h
->
nl
);
h
->
tables
=
t
;
INIT_LIST_HEAD
(
&
h
->
obj_list
);
INIT_LIST_HEAD
(
&
h
->
err_list
);
return
0
;
}
static
int
__flush_rule_cache
(
struct
nftnl_rule
*
r
,
void
*
data
)
{
const
char
*
tablename
=
data
;
h
->
batch
=
mnl_nftnl_batch_alloc
();
h
->
batch_support
=
mnl_batch_supported
(
h
);
if
(
!
strcmp
(
nftnl_rule_get_str
(
r
,
NFTNL_RULE_TABLE
),
tablename
))
{
nftnl_rule_list_del
(
r
);
nftnl_rule_free
(
r
);
}
return
0
;
}
static
void
flush_rule_cache
(
struct
nft_handle
*
h
)
static
void
flush_rule_cache
(
struct
nft_handle
*
h
,
const
char
*
tablename
)
{
if
(
!
h
->
rule_cache
)
return
;
if
(
tablename
)
{
nftnl_rule_list_foreach
(
h
->
rule_cache
,
__flush_rule_cache
,
(
void
*
)
tablename
);
}
else
{
nftnl_rule_list_free
(
h
->
rule_cache
);
h
->
rule_cache
=
NULL
;
}
}
static
int
__flush_chain_cache
(
struct
nftnl_chain
*
c
,
void
*
data
)
{
const
char
*
tablename
=
data
;
if
(
!
strcmp
(
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_TABLE
),
tablename
))
{
nftnl_chain_list_del
(
c
);
nftnl_chain_free
(
c
);
}
return
0
;
}
static
void
flush_chain_cache
(
struct
nft_handle
*
h
,
const
char
*
tablename
)
{
if
(
!
h
->
chain_cache
)
return
;
if
(
tablename
)
{
nftnl_chain_list_foreach
(
h
->
chain_cache
,
__flush_chain_cache
,
(
void
*
)
tablename
);
}
else
{
nftnl_chain_list_free
(
h
->
chain_cache
);
h
->
chain_cache
=
NULL
;
}
}
void
nft_fini
(
struct
nft_handle
*
h
)
{
flush_rule_cache
(
h
);
flush_chain_cache
(
h
,
NULL
);
flush_rule_cache
(
h
,
NULL
);
mnl_socket_close
(
h
->
nl
);
free
(
mnl_nlmsg_batch_head
(
h
->
batch
));
mnl_nlmsg_batch_stop
(
h
->
batch
);
}
static
void
nft_chain_print_debug
(
struct
nftnl_chain
*
c
,
struct
nlmsghdr
*
nlh
)
...
...
@@ -802,7 +817,7 @@ static void nft_chain_print_debug(struct nftnl_chain *c, struct nlmsghdr *nlh)
#ifdef NLDEBUG
char
tmp
[
1024
];
nft_chain_snprintf
(
tmp
,
sizeof
(
tmp
),
c
,
0
,
0
);
nft
nl
_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
...
...
@@ -818,8 +833,12 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h,
struct
builtin_chain
*
_c
;
_t
=
nft_table_builtin_find
(
h
,
table
);
if
(
!
_t
)
{
errno
=
ENXIO
;
return
NULL
;
}
/* if this built-in table does not exists, create it */
if
(
_t
!=
NULL
)
nft_table_builtin_add
(
h
,
_t
);
_c
=
nft_chain_builtin_find
(
_t
,
chain
);
...
...
@@ -856,14 +875,13 @@ int nft_chain_set(struct nft_handle *h, const char *table,
c
=
nft_chain_new
(
h
,
table
,
chain
,
NF_DROP
,
counters
);
else
if
(
strcmp
(
policy
,
"ACCEPT"
)
==
0
)
c
=
nft_chain_new
(
h
,
table
,
chain
,
NF_ACCEPT
,
counters
);
else
errno
=
EINVAL
;
if
(
c
==
NULL
)
return
0
;
if
(
h
->
batch_support
)
ret
=
batch_chain_add
(
h
,
NFT_COMPAT_CHAIN_UPDATE
,
c
);
else
ret
=
nft_chain_add
(
h
,
c
,
0
);
/* the core expects 1 for success and 0 for error */
return
ret
==
0
?
1
:
0
;
...
...
@@ -886,11 +904,50 @@ static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
return
0
;
}
static
int
add_nft_limit
(
struct
nftnl_rule
*
r
,
struct
xt_entry_match
*
m
)
{
struct
xt_rateinfo
*
rinfo
=
(
void
*
)
m
->
data
;
static
const
uint32_t
mult
[]
=
{
XT_LIMIT_SCALE
*
24
*
60
*
60
,
/* day */
XT_LIMIT_SCALE
*
60
*
60
,
/* hour */
XT_LIMIT_SCALE
*
60
,
/* min */
XT_LIMIT_SCALE
,
/* sec */
};
struct
nftnl_expr
*
expr
;
int
i
;
expr
=
nftnl_expr_alloc
(
"limit"
);
if
(
!
expr
)
return
-
ENOMEM
;
for
(
i
=
1
;
i
<
ARRAY_SIZE
(
mult
);
i
++
)
{
if
(
rinfo
->
avg
>
mult
[
i
]
||
mult
[
i
]
/
rinfo
->
avg
<
mult
[
i
]
%
rinfo
->
avg
)
break
;
}
nftnl_expr_set_u32
(
expr
,
NFTNL_EXPR_LIMIT_TYPE
,
NFT_LIMIT_PKTS
);
nftnl_expr_set_u32
(
expr
,
NFTNL_EXPR_LIMIT_FLAGS
,
0
);
nftnl_expr_set_u64
(
expr
,
NFTNL_EXPR_LIMIT_RATE
,
mult
[
i
-
1
]
/
rinfo
->
avg
);
nftnl_expr_set_u64
(
expr
,
NFTNL_EXPR_LIMIT_UNIT
,
mult
[
i
-
1
]
/
XT_LIMIT_SCALE
);
nftnl_expr_set_u32
(
expr
,
NFTNL_EXPR_LIMIT_BURST
,
rinfo
->
burst
);
nftnl_rule_add_expr
(
r
,
expr
);
return
0
;
}
int
add_match
(
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
);
expr
=
nftnl_expr_alloc
(
"match"
);
if
(
expr
==
NULL
)
return
-
ENOMEM
;
...
...
@@ -919,11 +976,36 @@ static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
return
0
;
}
static
int
add_meta_nftrace
(
struct
nftnl_rule
*
r
)
{
struct
nftnl_expr
*
expr
;
expr
=
nftnl_expr_alloc
(
"immediate"
);
if
(
expr
==
NULL
)
return
-
ENOMEM
;
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
);
expr
=
nftnl_expr_alloc
(
"meta"
);
if
(
expr
==
NULL
)
return
-
ENOMEM
;
nftnl_expr_set_u32
(
expr
,
NFTNL_EXPR_META_KEY
,
NFT_META_NFTRACE
);
nftnl_expr_set_u32
(
expr
,
NFTNL_EXPR_META_SREG
,
NFT_REG32_01
);
nftnl_rule_add_expr
(
r
,
expr
);
return
0
;
}
int
add_target
(
struct
nftnl_rule
*
r
,
struct
xt_entry_target
*
t
)
{
struct
nftnl_expr
*
expr
;
int
ret
;
if
(
strcmp
(
t
->
u
.
user
.
name
,
"TRACE"
)
==
0
)
return
add_meta_nftrace
(
r
);
expr
=
nftnl_expr_alloc
(
"target"
);
if
(
expr
==
NULL
)
return
-
ENOMEM
;
...
...
@@ -996,7 +1078,7 @@ static void nft_rule_print_debug(struct nftnl_rule *r, struct nlmsghdr *nlh)
#ifdef NLDEBUG
char
tmp
[
1024
];
nft_rule_snprintf
(
tmp
,
sizeof
(
tmp
),
r
,
0
,
0
);
nft
nl
_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
...
...
@@ -1027,13 +1109,21 @@ enum udata_type {
int
add_comment
(
struct
nftnl_rule
*
r
,
const
char
*
comment
)
{
struct
nftnl_udata_buf
*
udata
;
uint32_t
len
;
if
(
nftnl_rule_get_data
(
r
,
NFTNL_RULE_USERDATA
,
&
len
))
return
-
EALREADY
;
udata
=
nftnl_udata_buf_alloc
(
NFT_USERDATA_MAXLEN
);
if
(
!
udata
)
return
-
ENOMEM
;
if
(
strnlen
(
comment
,
255
)
==
255
)
return
-
ENOSPC
;
if
(
!
nftnl_udata_put_strz
(
udata
,
UDATA_TYPE_COMMENT
,
comment
))
return
-
ENOMEM
;
nftnl_rule_set_data
(
r
,
NFTNL_RULE_USERDATA
,
nftnl_udata_buf_data
(
udata
),
nftnl_udata_buf_len
(
udata
));
...
...
@@ -1105,6 +1195,8 @@ err:
return
NULL
;
}
static
struct
nftnl_rule_list
*
nft_rule_list_get
(
struct
nft_handle
*
h
);
int
nft_rule_append
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
void
*
data
,
uint64_t
handle
,
bool
verbose
)
...
...
@@ -1128,26 +1220,36 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
}
else
type
=
NFT_COMPAT_RULE_APPEND
;
if
(
batch_rule_add
(
h
,
type
,
r
)
<
0
)
if
(
batch_rule_add
(
h
,
type
,
r
)
<
0
)
{
nftnl_rule_free
(
r
);
return
0
;
}
if
(
verbose
)
h
->
ops
->
print_rule
(
r
,
0
,
FMT_PRINT_RULE
);
if
(
!
nft_rule_list_get
(
h
))
return
0
;
nftnl_rule_list_add_tail
(
r
,
h
->
rule_cache
);
flush_rule_cache
(
h
);
return
1
;
}
void
nft_rule_print_save
(
const
void
*
data
,
struct
nftnl_rule
*
r
,
enum
nft_rule_print
type
,
nft_rule_print_save
(
const
struct
nftnl_rule
*
r
,
enum
nft_rule_print
type
,
unsigned
int
format
)
{
const
char
*
chain
=
nftnl_rule_get_str
(
r
,
NFTNL_RULE_CHAIN
);
int
family
=
nftnl_rule_get_u32
(
r
,
NFTNL_RULE_FAMILY
);
struct
iptables_command_state
cs
=
{};
struct
nft_family_ops
*
ops
;
ops
=
nft_family_ops_lookup
(
family
);
ops
->
rule_to_cs
(
r
,
&
cs
);
if
(
!
(
format
&
FMT_NOCOUNTS
)
&&
ops
->
save_counters
)
ops
->
save_counters
(
data
);
if
(
!
(
format
&
(
FMT_NOCOUNTS
|
FMT_C_COUNTS
)
)
&&
ops
->
save_counters
)
ops
->
save_counters
(
&
cs
);
/* print chain name */
switch
(
type
)
{
...
...
@@ -1159,9 +1261,11 @@ nft_rule_print_save(const void *data,
break
;
}
if
(
ops
->
save_
firewall
)
ops
->
save_
firewall
(
data
,
format
);
if
(
ops
->
save_
rule
)
ops
->
save_
rule
(
&
cs
,
format
);
if
(
ops
->
clear_cs
)
ops
->
clear_cs
(
&
cs
);
}
static
int
nftnl_chain_list_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
...
...
@@ -1187,10 +1291,14 @@ err:
static
struct
nftnl_chain_list
*
nftnl_chain_list_get
(
struct
nft_handle
*
h
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
char
buf
[
16536
];
struct
nlmsghdr
*
nlh
;
struct
nftnl_chain_list
*
list
;
int
ret
;
if
(
h
->
chain_cache
)
return
h
->
chain_cache
;
retry:
list
=
nftnl_chain_list_alloc
();
if
(
list
==
NULL
)
{
errno
=
ENOMEM
;
...
...
@@ -1200,7 +1308,14 @@ static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h)
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETCHAIN
,
h
->
family
,
NLM_F_DUMP
,
h
->
seq
);
mnl_talk
(
h
,
nlh
,
nftnl_chain_list_cb
,
list
);
ret
=
mnl_talk
(
h
,
nlh
,
nftnl_chain_list_cb
,
list
);
if
(
ret
<
0
&&
errno
==
EINTR
)
{
assert
(
nft_restart
(
h
)
>=
0
);
nftnl_chain_list_free
(
list
);
goto
retry
;
}
h
->
chain_cache
=
list
;
return
list
;
}
...
...
@@ -1215,32 +1330,15 @@ static const char *policy_name[NF_ACCEPT+1] = {
[
NF_ACCEPT
]
=
"ACCEPT"
,
};
static
void
nft_chain_print_save
(
struct
nftnl_chain
*
c
,
bool
basechain
)
{
const
char
*
chain
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_NAME
);
uint64_t
pkts
=
nftnl_chain_get_u64
(
c
,
NFTNL_CHAIN_PACKETS
);
uint64_t
bytes
=
nftnl_chain_get_u64
(
c
,
NFTNL_CHAIN_BYTES
);
/* print chain name */
if
(
basechain
)
{
uint32_t
pol
=
NF_ACCEPT
;
/* no default chain policy? don't crash, display accept */
if
(
nftnl_chain_get
(
c
,
NFTNL_CHAIN_POLICY
))
pol
=
nftnl_chain_get_u32
(
c
,
NFTNL_CHAIN_POLICY
);
printf
(
":%s %s [%"
PRIu64
":%"
PRIu64
"]
\n
"
,
chain
,
policy_name
[
pol
],
pkts
,
bytes
);
}
else
printf
(
":%s - [%"
PRIu64
":%"
PRIu64
"]
\n
"
,
chain
,
pkts
,
bytes
);
}
int
nft_chain_save
(
struct
nft_handle
*
h
,
struct
nftnl_chain_list
*
list
,
const
char
*
table
)
{
struct
nftnl_chain_list_iter
*
iter
;
struct
nft_family_ops
*
ops
;
struct
nftnl_chain
*
c
;
ops
=
nft_family_ops_lookup
(
h
->
family
);
iter
=
nftnl_chain_list_iter_create
(
list
);
if
(
iter
==
NULL
)
return
0
;
...
...
@@ -1249,19 +1347,26 @@ int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list,
while
(
c
!=
NULL
)
{
const
char
*
chain_table
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_TABLE
);
bool
basechain
=
false
;
const
char
*
policy
=
NULL
;
if
(
strcmp
(
table
,
chain_table
)
!=
0
)
goto
next
;
basechain
=
nft_chain_builtin
(
c
);
nft_chain_print_save
(
c
,
basechain
);
if
(
nft_chain_builtin
(
c
))
{
uint32_t
pol
=
NF_ACCEPT
;
if
(
nftnl_chain_get
(
c
,
NFTNL_CHAIN_POLICY
))
pol
=
nftnl_chain_get_u32
(
c
,
NFTNL_CHAIN_POLICY
);
policy
=
policy_name
[
pol
];
}
if
(
ops
->
save_chain
)
ops
->
save_chain
(
c
,
policy
);
next:
c
=
nftnl_chain_list_iter_next
(
iter
);
}
nftnl_chain_list_iter_destroy
(
iter
);
nftnl_chain_list_free
(
list
);
return
1
;
}
...
...
@@ -1290,7 +1395,7 @@ err:
static
struct
nftnl_rule_list
*
nft_rule_list_get
(
struct
nft_handle
*
h
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
char
buf
[
16536
];
struct
nlmsghdr
*
nlh
;
struct
nftnl_rule_list
*
list
;
int
ret
;
...
...
@@ -1298,6 +1403,7 @@ static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
if
(
h
->
rule_cache
)
return
h
->
rule_cache
;
retry:
list
=
nftnl_rule_list_alloc
();
if
(
list
==
NULL
)
return
0
;
...
...
@@ -1307,15 +1413,21 @@ static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
ret
=
mnl_talk
(
h
,
nlh
,
nftnl_rule_list_cb
,
list
);
if
(
ret
<
0
)
{
if
(
errno
==
EINTR
)
{
assert
(
nft_restart
(
h
)
>=
0
);
nftnl_rule_list_free
(
list
);
return
NULL
;
goto
retry
;
}
h
->
rule_cache
=
list
;
nftnl_rule_list_free
(
list
);
return
NULL
;
}
h
->
rule_cache
=
list
;
return
list
;
}
int
nft_rule_save
(
struct
nft_handle
*
h
,
const
char
*
table
,
bool
counters
)
int
nft_rule_save
(
struct
nft_handle
*
h
,
const
char
*
table
,
unsigned
int
format
)
{
struct
nftnl_rule_list
*
list
;
struct
nftnl_rule_list_iter
*
iter
;
...
...
@@ -1333,15 +1445,11 @@ int nft_rule_save(struct nft_handle *h, const char *table, bool counters)
while
(
r
!=
NULL
)
{
const
char
*
rule_table
=
nftnl_rule_get_str
(
r
,
NFTNL_RULE_TABLE
);
struct
iptables_command_state
cs
=
{};
if
(
strcmp
(
table
,
rule_table
)
!=
0
)
goto
next
;
nft_rule_to_iptables_command_state
(
r
,
&
cs
);
nft_rule_print_save
(
&
cs
,
r
,
NFT_RULE_APPEND
,
counters
?
0
:
FMT_NOCOUNTS
);
nft_rule_print_save
(
r
,
NFT_RULE_APPEND
,
format
);
next:
r
=
nftnl_rule_list_iter_next
(
iter
);
...
...
@@ -1369,24 +1477,73 @@ __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
nftnl_rule_free
(
r
);
}
int
nft_rule_flush
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
)
struct
chain_user_flush_data
{
struct
nft_handle
*
handle
;
const
char
*
table
;
const
char
*
chain
;
};
static
int
__nft_chain_user_flush
(
struct
nftnl_chain
*
c
,
void
*
data
)
{
int
ret
;
const
char
*
table_name
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_TABLE
);
const
char
*
chain_name
=
nftnl_chain_get_str
(
c
,
NFTNL_CHAIN_NAME
);
struct
chain_user_flush_data
*
d
=
data
;
struct
nft_handle
*
h
=
d
->
handle
;
const
char
*
table
=
d
->
table
;
const
char
*
chain
=
d
->
chain
;
if
(
strcmp
(
table
,
table_name
)
!=
0
)
return
0
;
if
(
strcmp
(
chain
,
chain_name
)
!=
0
)
return
0
;
if
(
!
nftnl_chain_is_set
(
c
,
NFTNL_CHAIN_HOOKNUM
))
__nft_rule_flush
(
h
,
table
,
chain
);
return
0
;
}
int
nft_chain_user_flush
(
struct
nft_handle
*
h
,
struct
nftnl_chain_list
*
list
,
const
char
*
table
,
const
char
*
chain
)
{
struct
chain_user_flush_data
d
=
{
.
handle
=
h
,
.
table
=
table
,
.
chain
=
chain
,
};
nft_fn
=
nft_chain_user_flush
;
nftnl_chain_list_foreach
(
list
,
__nft_chain_user_flush
,
&
d
);
return
1
;
}
int
nft_rule_flush
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
bool
verbose
)
{
int
ret
=
0
;
struct
nftnl_chain_list
*
list
;
struct
nftnl_chain_list_iter
*
iter
;
struct
nftnl_chain
*
c
;
if
(
nft_xtables_config_load
(
h
,
XTABLES_CONFIG_DEFAULT
,
0
)
<
0
)
nft_xt_builtin_init
(
h
,
table
);
nft_fn
=
nft_rule_flush
;
list
=
nftnl_chain_list_get
(
h
);
if
(
list
==
NULL
)
{
ret
=
0
;
ret
=
1
;
goto
err
;
}
iter
=
nftnl_chain_list_iter_create
(
list
);
if
(
iter
==
NULL
)
if
(
iter
==
NULL
)
{
ret
=
1
;
goto
err
;
}
c
=
nftnl_chain_list_iter_next
(
iter
);
while
(
c
!=
NULL
)
{
...
...
@@ -1401,6 +1558,9 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table)
if
(
chain
!=
NULL
&&
strcmp
(
chain
,
chain_name
)
!=
0
)
goto
next
;
if
(
verbose
)
fprintf
(
stdout
,
"Flushing chain `%s'
\n
"
,
chain_name
);
__nft_rule_flush
(
h
,
table_name
,
chain_name
);
if
(
chain
!=
NULL
)
...
...
@@ -1408,12 +1568,9 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table)
next:
c
=
nftnl_chain_list_iter_next
(
iter
);
}
nftnl_chain_list_iter_destroy
(
iter
);
flush_rule_cache
(
h
);
flush_rule_cache
(
h
,
table
);
err:
nftnl_chain_list_free
(
list
);
/* the core expects 1 for success and 0 for error */
return
ret
==
0
?
1
:
0
;
}
...
...
@@ -1436,37 +1593,23 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
nftnl_chain_set
(
c
,
NFTNL_CHAIN_TABLE
,
(
char
*
)
table
);
nftnl_chain_set
(
c
,
NFTNL_CHAIN_NAME
,
(
char
*
)
chain
);
if
(
h
->
batch_support
)
{
ret
=
batch_chain_add
(
h
,
NFT_COMPAT_CHAIN_USER_ADD
,
c
);
}
else
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
struct
nlmsghdr
*
nlh
;
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_NEWCHAIN
,
h
->
family
,
NLM_F_ACK
|
NLM_F_EXCL
,
h
->
seq
);
nftnl_chain_nlmsg_build_payload
(
nlh
,
c
);
nftnl_chain_free
(
c
);
ret
=
mnl_talk
(
h
,
nlh
,
NULL
,
NULL
);
}
nft_chain_dump
(
h
);
nftnl_chain_list_add
(
c
,
h
->
chain_cache
);
/* the core expects 1 for success and 0 for error */
return
ret
==
0
?
1
:
0
;
}
static
int
__nft_chain_del
(
struct
nft_handle
*
h
,
struct
nftnl_chain
*
c
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
struct
nlmsghdr
*
nlh
;
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_DELCHAIN
,
h
->
family
,
NLM_F_ACK
,
h
->
seq
);
nftnl_chain_nlmsg_build_payload
(
nlh
,
c
);
return
mnl_talk
(
h
,
nlh
,
NULL
,
NULL
);
}
/* From linux/netlink.h */
#ifndef NLM_F_NONREC
#define NLM_F_NONREC 0x100
/* Do not delete recursively */
#endif
int
nft_chain_user_del
(
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
)
{
struct
nftnl_chain_list
*
list
;
struct
nftnl_chain_list_iter
*
iter
;
...
...
@@ -1474,6 +1617,8 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl
int
ret
=
0
;
int
deleted_ctr
=
0
;
nft_fn
=
nft_chain_user_del
;
list
=
nftnl_chain_list_get
(
h
);
if
(
list
==
NULL
)
goto
err
;
...
...
@@ -1499,15 +1644,16 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl
if
(
chain
!=
NULL
&&
strcmp
(
chain
,
chain_name
)
!=
0
)
goto
next
;
if
(
h
->
batch_support
)
if
(
verbose
)
fprintf
(
stdout
,
"Deleting chain `%s'
\n
"
,
chain
);
ret
=
batch_chain_add
(
h
,
NFT_COMPAT_CHAIN_USER_DEL
,
c
);
else
ret
=
__nft_chain_del
(
h
,
c
);
if
(
ret
<
0
)
break
;
deleted_ctr
++
;
nftnl_chain_list_del
(
c
);
if
(
chain
!=
NULL
)
break
;
...
...
@@ -1517,11 +1663,9 @@ next:
nftnl_chain_list_iter_destroy
(
iter
);
err:
if
(
!
h
->
batch_support
)
nftnl_chain_list_free
(
list
);
/* chain not found */
if
(
deleted_ctr
==
0
)
{
if
(
chain
!=
NULL
&&
deleted_ctr
==
0
)
{
ret
=
-
1
;
errno
=
ENOENT
;
}
...
...
@@ -1575,6 +1719,21 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain)
return
nft_chain_list_find
(
list
,
table
,
chain
);
}
bool
nft_chain_exists
(
struct
nft_handle
*
h
,
const
char
*
table
,
const
char
*
chain
)
{
struct
builtin_table
*
t
=
nft_table_builtin_find
(
h
,
table
);
/* xtables does not support custom tables */
if
(
!
t
)
return
false
;
if
(
nft_chain_builtin_find
(
t
,
chain
))
return
true
;
return
!!
nft_chain_find
(
h
,
table
,
chain
);
}
int
nft_chain_user_rename
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
const
char
*
newname
)
{
...
...
@@ -1608,19 +1767,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
nftnl_chain_set
(
c
,
NFTNL_CHAIN_NAME
,
(
char
*
)
newname
);
nftnl_chain_set_u64
(
c
,
NFTNL_CHAIN_HANDLE
,
handle
);
if
(
h
->
batch_support
)
{
ret
=
batch_chain_add
(
h
,
NFT_COMPAT_CHAIN_RENAME
,
c
);
}
else
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
struct
nlmsghdr
*
nlh
;
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_NEWCHAIN
,
h
->
family
,
NLM_F_ACK
,
h
->
seq
);
nftnl_chain_nlmsg_build_payload
(
nlh
,
c
);
nftnl_chain_free
(
c
);
ret
=
mnl_talk
(
h
,
nlh
,
NULL
,
NULL
);
}
/* the core expects 1 for success and 0 for error */
return
ret
==
0
?
1
:
0
;
...
...
@@ -1649,10 +1796,12 @@ err:
static
struct
nftnl_table_list
*
nftnl_table_list_get
(
struct
nft_handle
*
h
)
{
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
char
buf
[
16536
];
struct
nlmsghdr
*
nlh
;
struct
nftnl_table_list
*
list
;
int
ret
;
retry:
list
=
nftnl_table_list_alloc
();
if
(
list
==
NULL
)
return
0
;
...
...
@@ -1660,7 +1809,12 @@ static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
nlh
=
nftnl_rule_nlmsg_build_hdr
(
buf
,
NFT_MSG_GETTABLE
,
h
->
family
,
NLM_F_DUMP
,
h
->
seq
);
mnl_talk
(
h
,
nlh
,
nftnl_table_list_cb
,
list
);
ret
=
mnl_talk
(
h
,
nlh
,
nftnl_table_list_cb
,
list
);
if
(
ret
<
0
&&
errno
==
EINTR
)
{
assert
(
nft_restart
(
h
)
>=
0
);
nftnl_table_list_free
(
list
);
goto
retry
;
}
return
list
;
}
...
...
@@ -1685,12 +1839,15 @@ bool nft_table_find(struct nft_handle *h, const char *tablename)
const
char
*
this_tablename
=
nftnl_table_get
(
t
,
NFTNL_TABLE_NAME
);
if
(
strcmp
(
tablename
,
this_tablename
)
==
0
)
return
true
;
if
(
strcmp
(
tablename
,
this_tablename
)
==
0
)
{
ret
=
true
;
break
;
}
t
=
nftnl_table_list_iter_next
(
iter
);
}
nftnl_table_list_iter_destroy
(
iter
);
nftnl_table_list_free
(
list
);
err:
...
...
@@ -1701,20 +1858,17 @@ int nft_for_each_table(struct nft_handle *h,
int
(
*
func
)(
struct
nft_handle
*
h
,
const
char
*
tablename
,
bool
counters
),
bool
counters
)
{
int
ret
=
1
;
struct
nftnl_table_list
*
list
;
struct
nftnl_table_list_iter
*
iter
;
struct
nftnl_table
*
t
;
list
=
nftnl_table_list_get
(
h
);
if
(
list
==
NULL
)
{
ret
=
0
;
goto
err
;
}
if
(
list
==
NULL
)
return
-
1
;
iter
=
nftnl_table_list_iter_create
(
list
);
if
(
iter
==
NULL
)
return
0
;
return
-
1
;
t
=
nftnl_table_list_iter_next
(
iter
);
while
(
t
!=
NULL
)
{
...
...
@@ -1726,44 +1880,89 @@ int nft_for_each_table(struct nft_handle *h,
t
=
nftnl_table_list_iter_next
(
iter
);
}
nftnl_table_list_iter_destroy
(
iter
);
nftnl_table_list_free
(
list
);
err:
/* the core expects 1 for success and 0 for error */
return
ret
==
0
?
1
:
0
;
return
0
;
}
int
nft_table_purge_chains
(
struct
nft_handle
*
h
,
const
char
*
this_table
,
struct
nftnl_chain_list
*
chain_list
)
static
int
__nft_table_flush
(
struct
nft_handle
*
h
,
const
char
*
table
)
{
struct
nftnl_chain_list_iter
*
iter
;
struct
nftnl_chain
*
chain_obj
;
struct
builtin_table
*
_t
;
struct
nftnl_table
*
t
;
t
=
nftnl_table_alloc
();
if
(
t
==
NULL
)
return
-
1
;
nftnl_table_set_str
(
t
,
NFTNL_TABLE_NAME
,
table
);
batch_table_add
(
h
,
NFT_COMPAT_TABLE_FLUSH
,
t
);
_t
=
nft_table_builtin_find
(
h
,
table
);
assert
(
_t
);
_t
->
initialized
=
false
;
flush_chain_cache
(
h
,
table
);
flush_rule_cache
(
h
,
table
);
iter
=
nftnl_chain_list_iter_create
(
chain_list
);
if
(
iter
==
NULL
)
return
0
;
}
chain_obj
=
nftnl_chain_list_iter_next
(
iter
);
while
(
chain_obj
!=
NULL
)
{
const
char
*
table
=
nftnl_chain_get_str
(
chain_obj
,
NFTNL_CHAIN_TABLE
);
int
nft_table_flush
(
struct
nft_handle
*
h
,
const
char
*
table
)
{
struct
nftnl_table_list_iter
*
iter
;
struct
nftnl_table_list
*
list
;
struct
nftnl_table
*
t
;
int
ret
=
0
;
if
(
strcmp
(
this_table
,
table
)
!=
0
)
goto
next
;
nft_fn
=
nft_table_flush
;
if
(
nft_chain_builtin
(
chain_obj
))
goto
next
;
list
=
nftnl_table_list_get
(
h
);
if
(
list
==
NULL
)
{
ret
=
-
1
;
goto
err_out
;
}
if
(
__nft_chain_del
(
h
,
chain_obj
)
<
0
)
{
if
(
errno
!=
EBUSY
)
return
-
1
;
iter
=
nftnl_table_list_iter_create
(
list
);
if
(
iter
==
NULL
)
{
ret
=
-
1
;
goto
err_table_list
;
}
t
=
nftnl_table_list_iter_next
(
iter
);
while
(
t
!=
NULL
)
{
const
char
*
table_name
=
nftnl_table_get_str
(
t
,
NFTNL_TABLE_NAME
);
if
(
strcmp
(
table_name
,
table
)
!=
0
)
goto
next
;
ret
=
__nft_table_flush
(
h
,
table
);
if
(
ret
<
0
)
goto
err_table_iter
;
next:
chain_obj
=
nftnl_
chain
_list_iter_next
(
iter
);
t
=
nftnl_
table
_list_iter_next
(
iter
);
}
nftnl_chain_list_iter_destroy
(
iter
);
return
0
;
if
(
!
h
->
rule_cache
)
{
h
->
rule_cache
=
nftnl_rule_list_alloc
();
if
(
h
->
rule_cache
==
NULL
)
return
-
1
;
}
err_table_iter:
nftnl_table_list_iter_destroy
(
iter
);
err_table_list:
nftnl_table_list_free
(
list
);
err_out:
/* the core expects 1 for success and 0 for error */
return
ret
==
0
?
1
:
0
;
}
void
nft_table_new
(
struct
nft_handle
*
h
,
const
char
*
table
)
{
if
(
nft_xtables_config_load
(
h
,
XTABLES_CONFIG_DEFAULT
,
0
)
<
0
)
nft_xt_builtin_init
(
h
,
table
);
}
static
int
__nft_rule_del
(
struct
nft_handle
*
h
,
struct
nftnl_rule_list
*
list
,
...
...
@@ -1832,7 +2031,7 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
const
char
*
table
,
void
*
data
,
bool
verbose
)
{
struct
nftnl_rule_list
*
list
;
int
ret
;
struct
nftnl_rule
*
r
;
nft_fn
=
nft_rule_check
;
...
...
@@ -1840,11 +2039,15 @@ int nft_rule_check(struct nft_handle *h, const char *chain,
if
(
list
==
NULL
)
return
0
;
r
et
=
nft_rule_find
(
h
,
list
,
chain
,
table
,
data
,
-
1
)
?
1
:
0
;
if
(
r
et
==
0
)
r
=
nft_rule_find
(
h
,
list
,
chain
,
table
,
data
,
-
1
);
if
(
r
==
NULL
)
{
errno
=
ENOENT
;
return
0
;
}
if
(
verbose
)
h
->
ops
->
print_rule
(
r
,
0
,
FMT_PRINT_RULE
);
return
ret
;
return
1
;
}
int
nft_rule_delete
(
struct
nft_handle
*
h
,
const
char
*
chain
,
...
...
@@ -1865,15 +2068,15 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
ret
=
__nft_rule_del
(
h
,
list
,
r
);
if
(
ret
<
0
)
errno
=
ENOMEM
;
if
(
verbose
)
h
->
ops
->
print_rule
(
r
,
0
,
FMT_PRINT_RULE
);
}
else
errno
=
ENOENT
;
flush_rule_cache
(
h
);
return
ret
;
}
static
int
static
struct
nftnl_rule
*
nft_rule_add
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
struct
iptables_command_state
*
cs
,
uint64_t
handle
,
bool
verbose
)
...
...
@@ -1882,25 +2085,27 @@ nft_rule_add(struct nft_handle *h, const char *chain,
r
=
nft_rule_new
(
h
,
chain
,
table
,
cs
);
if
(
r
==
NULL
)
return
0
;
return
NULL
;
if
(
handle
>
0
)
nftnl_rule_set_u64
(
r
,
NFTNL_RULE_POSITION
,
handle
);
if
(
batch_rule_add
(
h
,
NFT_COMPAT_RULE_INSERT
,
r
)
<
0
)
{
nftnl_rule_free
(
r
);
return
0
;
return
NULL
;
}
flush_rule_cache
(
h
);
return
1
;
if
(
verbose
)
h
->
ops
->
print_rule
(
r
,
0
,
FMT_PRINT_RULE
);
return
r
;
}
int
nft_rule_insert
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
void
*
data
,
int
rulenum
,
bool
verbose
)
{
struct
nftnl_rule
*
r
,
*
new_rule
;
struct
nftnl_rule_list
*
list
;
struct
nftnl_rule
*
r
;
uint64_t
handle
=
0
;
/* If built-in chains don't exist for this table, create them */
...
...
@@ -1921,11 +2126,9 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
*/
r
=
nft_rule_find
(
h
,
list
,
chain
,
table
,
data
,
rulenum
-
1
);
if
(
r
!=
NULL
)
{
flush_rule_cache
(
h
);
if
(
r
!=
NULL
)
return
nft_rule_append
(
h
,
chain
,
table
,
data
,
0
,
verbose
);
}
errno
=
ENOENT
;
goto
err
;
...
...
@@ -1933,13 +2136,21 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
handle
=
nftnl_rule_get_u64
(
r
,
NFTNL_RULE_HANDLE
);
DEBUGP
(
"adding after rule handle %"
PRIu64
"
\n
"
,
handle
);
flush
_rule_
cache
(
h
);
}
else
{
nft
_rule_
list_get
(
h
);
}
return
nft_rule_add
(
h
,
chain
,
table
,
data
,
handle
,
verbose
);
new_rule
=
nft_rule_add
(
h
,
chain
,
table
,
data
,
handle
,
verbose
);
if
(
!
new_rule
)
goto
err
;
if
(
handle
)
nftnl_rule_list_insert_at
(
new_rule
,
r
);
else
nftnl_rule_list_add
(
new_rule
,
h
->
rule_cache
);
return
1
;
err:
flush_rule_cache
(
h
);
return
0
;
}
...
...
@@ -1958,8 +2169,6 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
r
=
nft_rule_find
(
h
,
list
,
chain
,
table
,
NULL
,
rulenum
);
if
(
r
!=
NULL
)
{
ret
=
1
;
DEBUGP
(
"deleting rule by number %d
\n
"
,
rulenum
);
ret
=
__nft_rule_del
(
h
,
list
,
r
);
if
(
ret
<
0
)
...
...
@@ -1967,8 +2176,6 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
}
else
errno
=
ENOENT
;
flush_rule_cache
(
h
);
return
ret
;
}
...
...
@@ -1991,14 +2198,14 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
(
unsigned
long
long
)
nftnl_rule_get_u64
(
r
,
NFTNL_RULE_HANDLE
));
nftnl_rule_list_del
(
r
);
ret
=
nft_rule_append
(
h
,
chain
,
table
,
data
,
nftnl_rule_get_u64
(
r
,
NFTNL_RULE_HANDLE
),
verbose
);
}
else
errno
=
ENOENT
;
flush_rule_cache
(
h
);
return
ret
;
}
...
...
@@ -2011,7 +2218,7 @@ __nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
struct
nftnl_rule_list
*
list
;
struct
nftnl_rule_list_iter
*
iter
;
struct
nftnl_rule
*
r
;
int
rule_ctr
=
0
,
ret
=
0
;
int
rule_ctr
=
0
;
list
=
nft_rule_list_get
(
h
);
if
(
list
==
NULL
)
...
...
@@ -2019,7 +2226,7 @@ __nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
iter
=
nftnl_rule_list_iter_create
(
list
);
if
(
iter
==
NULL
)
goto
err
;
return
0
;
r
=
nftnl_rule_list_iter_next
(
iter
);
while
(
r
!=
NULL
)
{
...
...
@@ -2040,21 +2247,51 @@ __nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
}
cb
(
r
,
rule_ctr
,
format
);
if
(
rulenum
>
0
&&
rule_ctr
==
rulenum
)
{
ret
=
1
;
if
(
rulenum
>
0
)
break
;
}
next:
r
=
nftnl_rule_list_iter_next
(
iter
);
}
nftnl_rule_list_iter_destroy
(
iter
);
err:
if
(
ret
==
0
)
errno
=
ENOENT
;
return
1
;
}
return
ret
;
static
int
nft_rule_count
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
)
{
struct
nftnl_rule_list_iter
*
iter
;
struct
nftnl_rule_list
*
list
;
struct
nftnl_rule
*
r
;
int
rule_ctr
=
0
;
list
=
nft_rule_list_get
(
h
);
if
(
list
==
NULL
)
return
0
;
iter
=
nftnl_rule_list_iter_create
(
list
);
if
(
iter
==
NULL
)
return
0
;
r
=
nftnl_rule_list_iter_next
(
iter
);
while
(
r
!=
NULL
)
{
const
char
*
rule_table
=
nftnl_rule_get_str
(
r
,
NFTNL_RULE_TABLE
);
const
char
*
rule_chain
=
nftnl_rule_get_str
(
r
,
NFTNL_RULE_CHAIN
);
if
(
strcmp
(
table
,
rule_table
)
!=
0
||
strcmp
(
chain
,
rule_chain
)
!=
0
)
goto
next
;
rule_ctr
++
;
next:
r
=
nftnl_rule_list_iter_next
(
iter
);
}
nftnl_rule_list_iter_destroy
(
iter
);
return
rule_ctr
;
}
int
nft_rule_list
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
...
...
@@ -2072,15 +2309,22 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
/* Force table and chain creation, otherwise first iptables -L
* lists no table/chains.
*/
if
(
!
list_empty
(
&
h
->
obj_list
))
if
(
!
list_empty
(
&
h
->
obj_list
))
{
nft_commit
(
h
);
flush_chain_cache
(
h
,
NULL
);
}
}
ops
=
nft_family_ops_lookup
(
h
->
family
);
if
(
!
nft_is_table_compatible
(
h
,
table
))
{
xtables_error
(
OTHER_PROBLEM
,
"table `%s' is incompatible, use 'nft' tool.
\n
"
,
table
);
return
0
;
}
if
(
chain
&&
rulenum
)
{
__nft_rule_list
(
h
,
chain
,
table
,
rulenum
,
format
,
ops
->
print_
firewall
);
rulenum
,
format
,
ops
->
print_
rule
);
return
1
;
}
...
...
@@ -2090,7 +2334,7 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if
(
iter
==
NULL
)
goto
err
;
if
(
ops
->
print_table_header
)
if
(
!
chain
&&
ops
->
print_table_header
)
ops
->
print_table_header
(
table
);
c
=
nftnl_chain_list_iter_next
(
iter
);
...
...
@@ -2108,37 +2352,44 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
.
bcnt
=
nftnl_chain_get_u64
(
c
,
NFTNL_CHAIN_BYTES
),
};
bool
basechain
=
false
;
uint32_t
entries
;
if
(
nftnl_chain_get
(
c
,
NFTNL_CHAIN_HOOKNUM
))
basechain
=
true
;
if
(
strcmp
(
table
,
chain_table
)
!=
0
)
goto
next
;
if
(
chain
&&
strcmp
(
chain
,
chain_name
)
!=
0
)
if
(
chain
)
{
if
(
strcmp
(
chain
,
chain_name
)
!=
0
)
goto
next
;
else
if
(
ops
->
print_table_header
)
ops
->
print_table_header
(
table
);
}
if
(
found
)
printf
(
"
\n
"
);
entries
=
nft_rule_count
(
h
,
chain_name
,
table
);
ops
->
print_header
(
format
,
chain_name
,
policy_name
[
policy
],
&
ctrs
,
basechain
,
refs
);
&
ctrs
,
basechain
,
refs
-
entries
,
entries
);
__nft_rule_list
(
h
,
chain_name
,
table
,
rulenum
,
format
,
ops
->
print_firewall
);
rulenum
,
format
,
ops
->
print_rule
);
found
=
true
;
/* we printed the chain we wanted, stop processing. */
if
(
chain
)
break
;
found
=
true
;
next:
c
=
nftnl_chain_list_iter_next
(
iter
);
}
nftnl_chain_list_iter_destroy
(
iter
);
err:
nftnl_chain_list_free
(
list
);
if
(
chain
&&
!
found
)
return
0
;
return
1
;
}
...
...
@@ -2146,11 +2397,7 @@ err:
static
void
list_save
(
struct
nftnl_rule
*
r
,
unsigned
int
num
,
unsigned
int
format
)
{
struct
iptables_command_state
cs
=
{};
nft_rule_to_iptables_command_state
(
r
,
&
cs
);
nft_rule_print_save
(
&
cs
,
r
,
NFT_RULE_APPEND
,
!
(
format
&
FMT_NOCOUNTS
));
nft_rule_print_save
(
r
,
NFT_RULE_APPEND
,
format
);
}
static
int
...
...
@@ -2205,8 +2452,26 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
{
struct
nftnl_chain_list
*
list
;
struct
nftnl_chain_list_iter
*
iter
;
unsigned
int
format
=
0
;
struct
nftnl_chain
*
c
;
int
ret
=
1
;
int
ret
=
0
;
/* If built-in chains don't exist for this table, create them */
if
(
nft_xtables_config_load
(
h
,
XTABLES_CONFIG_DEFAULT
,
0
)
<
0
)
{
nft_xt_builtin_init
(
h
,
table
);
/* Force table and chain creation, otherwise first iptables -L
* lists no table/chains.
*/
if
(
!
list_empty
(
&
h
->
obj_list
))
{
nft_commit
(
h
);
flush_chain_cache
(
h
,
NULL
);
}
}
if
(
!
nft_is_table_compatible
(
h
,
table
))
{
xtables_error
(
OTHER_PROBLEM
,
"table `%s' is incompatible, use 'nft' tool.
\n
"
,
table
);
return
0
;
}
list
=
nft_chain_dump
(
h
);
...
...
@@ -2219,6 +2484,11 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
if
(
iter
==
NULL
)
goto
err
;
if
(
counters
<
0
)
format
=
FMT_C_COUNTS
;
else
if
(
counters
==
0
)
format
=
FMT_NOCOUNTS
;
c
=
nftnl_chain_list_iter_next
(
iter
);
while
(
c
!=
NULL
)
{
const
char
*
chain_table
=
...
...
@@ -2232,7 +2502,7 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
goto
next
;
ret
=
__nft_rule_list
(
h
,
chain_name
,
table
,
rulenum
,
counters
?
0
:
FMT_NOCOUNTS
,
list_save
);
format
,
list_save
);
/* we printed the chain we wanted, stop processing. */
if
(
chain
)
...
...
@@ -2243,8 +2513,6 @@ next:
nftnl_chain_list_iter_destroy
(
iter
);
err:
nftnl_chain_list_free
(
list
);
return
ret
;
}
...
...
@@ -2278,8 +2546,6 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
false
);
error:
flush_rule_cache
(
h
);
return
ret
;
}
...
...
@@ -2289,10 +2555,9 @@ static void nft_compat_table_batch_add(struct nft_handle *h, uint16_t type,
{
struct
nlmsghdr
*
nlh
;
nlh
=
nftnl_table_nlmsg_build_hdr
(
mnl_nlmsg_batch_current
(
h
->
batch
),
nlh
=
nftnl_table_nlmsg_build_hdr
(
nftnl_batch_buffer
(
h
->
batch
),
type
,
h
->
family
,
flags
,
seq
);
nftnl_table_nlmsg_build_payload
(
nlh
,
table
);
nftnl_table_free
(
table
);
}
static
void
nft_compat_chain_batch_add
(
struct
nft_handle
*
h
,
uint16_t
type
,
...
...
@@ -2301,11 +2566,10 @@ static void nft_compat_chain_batch_add(struct nft_handle *h, uint16_t type,
{
struct
nlmsghdr
*
nlh
;
nlh
=
nftnl_chain_nlmsg_build_hdr
(
mnl_nlmsg_batch_current
(
h
->
batch
),
nlh
=
nftnl_chain_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
);
nftnl_chain_free
(
chain
);
}
static
void
nft_compat_rule_batch_add
(
struct
nft_handle
*
h
,
uint16_t
type
,
...
...
@@ -2314,96 +2578,162 @@ static void nft_compat_rule_batch_add(struct nft_handle *h, uint16_t type,
{
struct
nlmsghdr
*
nlh
;
nlh
=
nftnl_rule_nlmsg_build_hdr
(
mnl_nlmsg_batch_current
(
h
->
batch
),
nlh
=
nftnl_rule_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
);
nftnl_rule_free
(
rule
);
}
static
void
batch_obj_del
(
struct
nft_handle
*
h
,
struct
obj_update
*
o
)
{
switch
(
o
->
type
)
{
case
NFT_COMPAT_TABLE_ADD
:
case
NFT_COMPAT_TABLE_FLUSH
:
nftnl_table_free
(
o
->
table
);
break
;
case
NFT_COMPAT_CHAIN_ZERO
:
case
NFT_COMPAT_CHAIN_USER_ADD
:
break
;
case
NFT_COMPAT_CHAIN_ADD
:
case
NFT_COMPAT_CHAIN_USER_DEL
:
case
NFT_COMPAT_CHAIN_USER_FLUSH
:
case
NFT_COMPAT_CHAIN_UPDATE
:
case
NFT_COMPAT_CHAIN_RENAME
:
nftnl_chain_free
(
o
->
chain
);
break
;
case
NFT_COMPAT_RULE_APPEND
:
case
NFT_COMPAT_RULE_INSERT
:
case
NFT_COMPAT_RULE_REPLACE
:
case
NFT_COMPAT_RULE_DELETE
:
break
;
case
NFT_COMPAT_RULE_FLUSH
:
nftnl_rule_free
(
o
->
rule
);
break
;
}
h
->
obj_list_num
--
;
list_del
(
&
o
->
head
);
free
(
o
);
}
static
int
nft_action
(
struct
nft_handle
*
h
,
int
action
)
{
struct
obj_update
*
n
,
*
tmp
;
struct
mnl_err
*
err
,
*
ne
;
unsigned
int
buflen
,
i
,
len
;
bool
show_errors
=
true
;
char
errmsg
[
1024
];
uint32_t
seq
=
1
;
int
ret
=
0
;
mnl_nftnl_batch_begin
(
h
->
batch
,
seq
++
);
h
->
batch
=
mnl_batch_init
(
);
list_for_each_entry_safe
(
n
,
tmp
,
&
h
->
obj_list
,
head
)
{
mnl_batch_begin
(
h
->
batch
,
seq
++
);
list_for_each_entry
(
n
,
&
h
->
obj_list
,
head
)
{
n
->
seq
=
seq
++
;
switch
(
n
->
type
)
{
case
NFT_COMPAT_TABLE_ADD
:
nft_compat_table_batch_add
(
h
,
NFT_MSG_NEWTABLE
,
NLM_F_CREATE
,
seq
++
,
NLM_F_CREATE
,
n
->
seq
,
n
->
table
);
break
;
case
NFT_COMPAT_TABLE_FLUSH
:
nft_compat_table_batch_add
(
h
,
NFT_MSG_DELTABLE
,
0
,
n
->
seq
,
n
->
table
);
break
;
case
NFT_COMPAT_CHAIN_ADD
:
case
NFT_COMPAT_CHAIN_ZERO
:
nft_compat_chain_batch_add
(
h
,
NFT_MSG_NEWCHAIN
,
NLM_F_CREATE
,
seq
++
,
NLM_F_CREATE
,
n
->
seq
,
n
->
chain
);
break
;
case
NFT_COMPAT_CHAIN_USER_ADD
:
nft_compat_chain_batch_add
(
h
,
NFT_MSG_NEWCHAIN
,
NLM_F_EXCL
,
seq
++
,
NLM_F_EXCL
,
n
->
seq
,
n
->
chain
);
break
;
case
NFT_COMPAT_CHAIN_USER_DEL
:
nft_compat_chain_batch_add
(
h
,
NFT_MSG_DELCHAIN
,
0
,
seq
++
,
n
->
chain
);
NLM_F_NONREC
,
n
->
seq
,
n
->
chain
);
break
;
case
NFT_COMPAT_CHAIN_USER_FLUSH
:
nft_compat_chain_batch_add
(
h
,
NFT_MSG_DELCHAIN
,
0
,
n
->
seq
,
n
->
chain
);
break
;
case
NFT_COMPAT_CHAIN_UPDATE
:
nft_compat_chain_batch_add
(
h
,
NFT_MSG_NEWCHAIN
,
h
->
restore
?
NLM_F_CREATE
:
0
,
seq
++
,
n
->
chain
);
n
->
seq
,
n
->
chain
);
break
;
case
NFT_COMPAT_CHAIN_RENAME
:
nft_compat_chain_batch_add
(
h
,
NFT_MSG_NEWCHAIN
,
0
,
seq
++
,
n
->
chain
);
n
->
seq
,
n
->
chain
);
break
;
case
NFT_COMPAT_RULE_APPEND
:
nft_compat_rule_batch_add
(
h
,
NFT_MSG_NEWRULE
,
NLM_F_CREATE
|
NLM_F_APPEND
,
seq
++
,
n
->
rule
);
n
->
seq
,
n
->
rule
);
break
;
case
NFT_COMPAT_RULE_INSERT
:
nft_compat_rule_batch_add
(
h
,
NFT_MSG_NEWRULE
,
NLM_F_CREATE
,
seq
++
,
NLM_F_CREATE
,
n
->
seq
,
n
->
rule
);
break
;
case
NFT_COMPAT_RULE_REPLACE
:
nft_compat_rule_batch_add
(
h
,
NFT_MSG_NEWRULE
,
NLM_F_CREATE
|
NLM_F_REPLACE
,
seq
++
,
n
->
rule
);
n
->
seq
,
n
->
rule
);
break
;
case
NFT_COMPAT_RULE_DELETE
:
case
NFT_COMPAT_RULE_FLUSH
:
nft_compat_rule_batch_add
(
h
,
NFT_MSG_DELRULE
,
0
,
seq
++
,
n
->
rule
);
n
->
seq
,
n
->
rule
);
break
;
}
h
->
obj_list_num
--
;
list_del
(
&
n
->
head
);
free
(
n
);
if
(
!
mnl_nlmsg_batch_next
(
h
->
batch
))
h
->
batch
=
mnl_nftnl_batch_page_add
(
h
->
batch
);
mnl_nft_batch_continue
(
h
->
batch
);
}
switch
(
action
)
{
case
NFT_COMPAT_COMMIT
:
mnl_
nftnl_
batch_end
(
h
->
batch
,
seq
++
);
mnl_batch_end
(
h
->
batch
,
seq
++
);
break
;
case
NFT_COMPAT_ABORT
:
break
;
}
if
(
!
mnl_nlmsg_batch_is_empty
(
h
->
batch
))
h
->
batch
=
mnl_nftnl_batch_page_add
(
h
->
batch
);
ret
=
mnl_batch_talk
(
h
->
nl
,
h
->
batch
,
&
h
->
err_list
);
i
=
0
;
buflen
=
sizeof
(
errmsg
);
list_for_each_entry_safe
(
n
,
tmp
,
&
h
->
obj_list
,
head
)
{
list_for_each_entry_safe
(
err
,
ne
,
&
h
->
err_list
,
head
)
{
if
(
err
->
seqnum
>
n
->
seq
)
break
;
ret
=
mnl_nftnl_batch_talk
(
h
);
if
(
err
->
seqnum
==
n
->
seq
&&
show_errors
)
{
if
(
n
->
error
.
lineno
==
0
)
show_errors
=
false
;
len
=
mnl_append_error
(
h
,
n
,
err
,
errmsg
+
i
,
buflen
);
if
(
len
>
0
&&
len
<=
buflen
)
{
buflen
-=
len
;
i
+=
len
;
}
}
mnl_err_list_free
(
err
);
}
batch_obj_del
(
h
,
n
);
}
mnl_nlmsg_batch_reset
(
h
->
batch
);
mnl_batch_reset
(
h
->
batch
);
if
(
i
)
xtables_error
(
RESOURCE_PROBLEM
,
"%s"
,
errmsg
);
return
ret
==
0
?
1
:
0
;
}
...
...
@@ -2421,16 +2751,29 @@ int nft_abort(struct nft_handle *h)
int
nft_compatible_revision
(
const
char
*
name
,
uint8_t
rev
,
int
opt
)
{
struct
mnl_socket
*
nl
;
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
char
buf
[
16536
];
struct
nlmsghdr
*
nlh
;
uint32_t
portid
,
seq
,
type
;
uint32_t
portid
,
seq
,
type
=
0
;
uint32_t
pf
=
AF_INET
;
int
ret
=
0
;
if
(
opt
==
IPT_SO_GET_REVISION_MATCH
||
opt
==
IP6T_SO_GET_REVISION_MATCH
)
type
=
0
;
else
switch
(
opt
)
{
case
IPT_SO_GET_REVISION_MATCH
:
break
;
case
IP6T_SO_GET_REVISION_MATCH
:
pf
=
AF_INET6
;
break
;
case
IPT_SO_GET_REVISION_TARGET
:
type
=
1
;
break
;
case
IP6T_SO_GET_REVISION_TARGET
:
type
=
1
;
pf
=
AF_INET6
;
break
;
default:
/* No revision support (arp, ebtables), assume latest version ok */
return
1
;
}
nlh
=
mnl_nlmsg_put_header
(
buf
);
nlh
->
nlmsg_type
=
(
NFNL_SUBSYS_NFT_COMPAT
<<
8
)
|
NFNL_MSG_COMPAT_GET
;
...
...
@@ -2438,7 +2781,7 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt)
nlh
->
nlmsg_seq
=
seq
=
time
(
NULL
);
struct
nfgenmsg
*
nfg
=
mnl_nlmsg_put_extra_header
(
nlh
,
sizeof
(
*
nfg
));
nfg
->
nfgen_family
=
AF_INET
;
nfg
->
nfgen_family
=
pf
;
nfg
->
version
=
NFNETLINK_V0
;
nfg
->
res_id
=
0
;
...
...
@@ -2491,19 +2834,19 @@ const char *nft_strerror(int err)
{
nft_chain_user_del
,
EMLINK
,
"Can't delete chain with references left"
},
{
nft_chain_user_add
,
EEXIST
,
"Chain already exists"
},
{
nft_rule_
add
,
E2BIG
,
"Index of insertion too big"
},
{
nft_rule_
insert
,
ENOENT
,
"Index of insertion too big"
},
{
nft_rule_check
,
ENOENT
,
"Bad rule (does a matching rule exist in that chain?)"
},
{
nft_rule_replace
,
ENOENT
,
"Index of replacement too big"
},
{
nft_rule_delete_num
,
E
2BIG
,
"Index of deletion too big"
},
{
nft_rule_delete_num
,
E
NOENT
,
"Index of deletion too big"
},
/* { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
{ TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, */
{
nft_rule_add
,
ELOOP
,
"Loop found in table"
},
{
nft_rule_add
,
EINVAL
,
"Target problem"
},
/* ENOENT for DELETE probably means no matching rule */
{
nft_rule_delete
,
ENOENT
,
"Bad rule (does a matching rule exist in that chain?)"
},
{
nft_chain_set
,
ENOENT
,
"Bad built-in chain name"
},
{
nft_chain_set
,
EINVAL
,
"Bad policy name"
},
{
nft_chain_set
,
ENXIO
,
"Bad table name"
},
{
NULL
,
ELOOP
,
"Loop found in table"
},
{
NULL
,
EPERM
,
"Permission denied (you must be root)"
},
{
NULL
,
0
,
"Incompatible with this kernel"
},
{
NULL
,
ENOPROTOOPT
,
"iptables who? (do you need to insmod?)"
},
...
...
@@ -2533,11 +2876,11 @@ static void xtables_config_perror(uint32_t flags, const char *fmt, ...)
va_end
(
args
);
}
int
nft_xtables_config_load
(
struct
nft_handle
*
h
,
const
char
*
filename
,
static
int
__
nft_xtables_config_load
(
struct
nft_handle
*
h
,
const
char
*
filename
,
uint32_t
flags
)
{
struct
nftnl_table_list
*
table_list
=
nftnl_table_list_alloc
()
;
struct
nftnl_chain_list
*
chain_list
=
nftnl_chain_list_alloc
()
;
struct
nftnl_table_list
*
table_list
=
NULL
;
struct
nftnl_chain_list
*
chain_list
=
NULL
;
struct
nftnl_table_list_iter
*
titer
=
NULL
;
struct
nftnl_chain_list_iter
*
citer
=
NULL
;
struct
nftnl_table
*
table
;
...
...
@@ -2545,8 +2888,8 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename,
uint32_t
table_family
,
chain_family
;
bool
found
=
false
;
if
(
h
->
restore
)
return
0
;
table_list
=
nftnl_table_list_alloc
();
chain_list
=
nftnl_chain_list_alloc
()
;
if
(
xtables_config_parse
(
filename
,
table_list
,
chain_list
)
<
0
)
{
if
(
errno
==
ENOENT
)
{
...
...
@@ -2626,6 +2969,8 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename,
nftnl_chain_list_iter_destroy
(
citer
);
nftnl_chain_list_free
(
chain_list
);
h
->
config_done
=
1
;
return
0
;
err:
...
...
@@ -2637,11 +2982,22 @@ err:
if
(
citer
!=
NULL
)
nftnl_chain_list_iter_destroy
(
citer
);
h
->
config_done
=
-
1
;
return
-
1
;
}
int
nft_xtables_config_load
(
struct
nft_handle
*
h
,
const
char
*
filename
,
uint32_t
flags
)
{
if
(
!
h
->
config_done
)
return
__nft_xtables_config_load
(
h
,
filename
,
flags
);
return
h
->
config_done
;
}
int
nft_chain_zero_counters
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
)
const
char
*
table
,
bool
verbose
)
{
struct
nftnl_chain_list
*
list
;
struct
nftnl_chain_list_iter
*
iter
;
...
...
@@ -2669,23 +3025,15 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain,
if
(
chain
!=
NULL
&&
strcmp
(
chain
,
chain_name
)
!=
0
)
goto
next
;
if
(
verbose
)
fprintf
(
stdout
,
"Zeroing chain `%s'
\n
"
,
chain_name
);
nftnl_chain_set_u64
(
c
,
NFTNL_CHAIN_PACKETS
,
0
);
nftnl_chain_set_u64
(
c
,
NFTNL_CHAIN_BYTES
,
0
);
nftnl_chain_unset
(
c
,
NFTNL_CHAIN_HANDLE
);
if
(
h
->
batch_support
)
{
ret
=
batch_chain_add
(
h
,
NFT_COMPAT_CHAIN_ADD
,
c
);
}
else
{
struct
nlmsghdr
*
nlh
;
char
buf
[
MNL_SOCKET_BUFFER_SIZE
];
nlh
=
nftnl_chain_nlmsg_build_hdr
(
buf
,
NFT_MSG_NEWCHAIN
,
h
->
family
,
NLM_F_ACK
,
h
->
seq
);
nftnl_chain_nlmsg_build_payload
(
nlh
,
c
);
ret
=
mnl_talk
(
h
,
nlh
,
NULL
,
NULL
);
}
ret
=
batch_chain_add
(
h
,
NFT_COMPAT_CHAIN_ZERO
,
c
);
if
(
chain
!=
NULL
)
break
;
...
...
@@ -2693,9 +3041,6 @@ next:
c
=
nftnl_chain_list_iter_next
(
iter
);
}
if
(
!
h
->
batch_support
)
nftnl_chain_list_free
(
list
);
nftnl_chain_list_iter_destroy
(
iter
);
err:
...
...
@@ -2725,8 +3070,9 @@ static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
};
static
int
nft_is_expr_compatible
(
const
char
*
name
)
static
int
nft_is_expr_compatible
(
const
struct
nftnl_expr
*
expr
)
{
const
char
*
name
=
nftnl_expr_get_str
(
expr
,
NFTNL_EXPR_NAME
);
int
i
;
for
(
i
=
0
;
i
<
NFT_COMPAT_EXPR_MAX
;
i
++
)
{
...
...
@@ -2734,59 +3080,76 @@ static int nft_is_expr_compatible(const char *name)
return
0
;
}
if
(
!
strcmp
(
name
,
"limit"
)
&&
nftnl_expr_get_u32
(
expr
,
NFTNL_EXPR_LIMIT_TYPE
)
==
NFT_LIMIT_PKTS
&&
nftnl_expr_get_u32
(
expr
,
NFTNL_EXPR_LIMIT_FLAGS
)
==
0
)
return
0
;
return
1
;
}
static
int
nft_is_rule_compatible
(
struct
nftnl_rule
*
rule
)
static
bool
nft_is_rule_compatible
(
struct
nftnl_rule
*
rule
)
{
struct
nftnl_expr_iter
*
iter
;
struct
nftnl_expr
*
expr
;
int
ret
=
0
;
bool
compatible
=
false
;
iter
=
nftnl_expr_iter_create
(
rule
);
if
(
iter
==
NULL
)
return
-
1
;
return
false
;
expr
=
nftnl_expr_iter_next
(
iter
);
while
(
expr
!=
NULL
)
{
const
char
*
name
=
nftnl_expr_get_str
(
expr
,
NFTNL_EXPR_NAME
);
if
(
nft_is_expr_compatible
(
name
)
==
0
)
{
if
(
nft_is_expr_compatible
(
expr
)
==
0
)
{
expr
=
nftnl_expr_iter_next
(
iter
);
continue
;
}
ret
=
1
;
compatible
=
true
;
break
;
}
nftnl_expr_iter_destroy
(
iter
);
return
ret
;
return
compatible
;
}
static
int
nft_is_chain_compatible
(
const
char
*
table
,
const
char
*
chain
)
static
int
nft_is_chain_compatible
(
const
struct
nft_handle
*
h
,
const
struct
nftnl_chain
*
chain
)
{
const
char
*
cur_table
;
const
char
*
table
,
*
name
,
*
type
,
*
cur_table
;
struct
builtin_chain
*
chains
;
int
i
,
j
;
int
i
,
j
,
prio
;
enum
nf_inet_hooks
hook
;
table
=
nftnl_chain_get
(
chain
,
NFTNL_CHAIN_TABLE
);
name
=
nftnl_chain_get
(
chain
,
NFTNL_CHAIN_NAME
);
type
=
nftnl_chain_get
(
chain
,
NFTNL_CHAIN_TYPE
);
prio
=
nftnl_chain_get_u32
(
chain
,
NFTNL_CHAIN_PRIO
);
hook
=
nftnl_chain_get_u32
(
chain
,
NFTNL_CHAIN_HOOKNUM
);
for
(
i
=
0
;
i
<
TABLES_MAX
;
i
++
)
{
cur_table
=
x
tables
_ipv4
[
i
].
name
;
chains
=
x
tables
_ipv4
[
i
].
chains
;
cur_table
=
h
->
tables
[
i
].
name
;
chains
=
h
->
tables
[
i
].
chains
;
if
(
strcmp
(
table
,
cur_table
)
!=
0
)
if
(
!
cur_table
||
strcmp
(
table
,
cur_table
)
!=
0
)
continue
;
for
(
j
=
0
;
j
<
NF_INET_NUMHOOKS
&&
chains
[
j
].
name
;
j
++
)
{
if
(
strcmp
(
chain
,
chains
[
j
].
name
)
==
0
)
if
(
strcmp
(
name
,
chains
[
j
].
name
)
!=
0
)
continue
;
if
(
strcmp
(
type
,
chains
[
j
].
type
)
==
0
&&
prio
==
chains
[
j
].
prio
&&
hook
==
chains
[
j
].
hook
)
return
0
;
break
;
}
}
return
1
;
}
static
int
nft_are_chains_compatible
(
struct
nft_handle
*
h
)
static
int
nft_are_chains_compatible
(
struct
nft_handle
*
h
,
const
char
*
tablename
)
{
struct
nftnl_chain_list
*
list
;
struct
nftnl_chain_list_iter
*
iter
;
...
...
@@ -2803,104 +3166,62 @@ static int nft_are_chains_compatible(struct nft_handle *h)
chain
=
nftnl_chain_list_iter_next
(
iter
);
while
(
chain
!=
NULL
)
{
if
(
!
nft_chain_builtin
(
chain
))
goto
next
;
const
char
*
chain_table
;
const
char
*
table
=
nftnl_chain_get
(
chain
,
NFTNL_CHAIN_TABLE
);
const
char
*
name
=
nftnl_chain_get
(
chain
,
NFTNL_CHAIN_NAME
);
chain_table
=
nftnl_chain_get_str
(
chain
,
NFTNL_CHAIN_TABLE
);
if
(
nft_is_chain_compatible
(
table
,
name
)
==
1
)
{
ret
=
1
;
break
;
}
if
(
strcmp
(
chain_table
,
tablename
)
||
!
nft_chain_builtin
(
chain
))
goto
next
;
ret
=
nft_is_chain_compatible
(
h
,
chain
);
if
(
ret
!=
0
)
break
;
next:
chain
=
nftnl_chain_list_iter_next
(
iter
);
}
nftnl_chain_list_iter_destroy
(
iter
);
nftnl_chain_list_free
(
list
);
return
ret
;
}
static
int
nft_is_table_compatible
(
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
TABLES_MAX
;
i
++
)
{
if
(
strcmp
(
xtables_ipv4
[
i
].
name
,
name
)
==
0
)
return
0
;
}
return
1
;
}
static
int
nft_are_tables_compatible
(
struct
nft_handle
*
h
)
{
struct
nftnl_table_list
*
list
;
struct
nftnl_table_list_iter
*
iter
;
struct
nftnl_table
*
table
;
int
ret
=
0
;
list
=
nftnl_table_list_get
(
h
);
if
(
list
==
NULL
)
return
-
1
;
iter
=
nftnl_table_list_iter_create
(
list
);
if
(
iter
==
NULL
)
return
-
1
;
table
=
nftnl_table_list_iter_next
(
iter
);
while
(
table
!=
NULL
)
{
const
char
*
name
=
nftnl_table_get
(
table
,
NFTNL_TABLE_NAME
);
if
(
nft_is_table_compatible
(
name
)
==
0
)
{
table
=
nftnl_table_list_iter_next
(
iter
);
continue
;
}
ret
=
1
;
break
;
}
nftnl_table_list_iter_destroy
(
iter
);
nftnl_table_list_free
(
list
);
return
ret
;
}
int
nft_is_
ruleset
_compatible
(
struct
nft_handle
*
h
)
bool
nft_is_
table
_compatible
(
struct
nft_handle
*
h
,
const
char
*
tablename
)
{
struct
nftnl_rule_list
*
list
;
struct
nftnl_rule_list_iter
*
iter
;
struct
nftnl_rule
*
rule
;
int
ret
=
0
;
ret
=
nft_are_tables_compatible
(
h
);
if
(
ret
!=
0
)
return
ret
;
if
(
!
nft_table_builtin_find
(
h
,
tablename
))
return
false
;
ret
=
nft_are_chains_compatible
(
h
);
ret
=
nft_are_chains_compatible
(
h
,
tablename
);
if
(
ret
!=
0
)
return
ret
;
return
false
;
list
=
nft_rule_list_get
(
h
);
if
(
list
==
NULL
)
return
-
1
;
return
true
;
iter
=
nftnl_rule_list_iter_create
(
list
);
if
(
iter
==
NULL
)
return
-
1
;
return
true
;
rule
=
nftnl_rule_list_iter_next
(
iter
);
while
(
rule
!=
NULL
)
{
const
char
*
table
=
nftnl_rule_get_str
(
rule
,
NFTNL_RULE_TABLE
);
if
(
strcmp
(
table
,
tablename
))
goto
next_rule
;
ret
=
nft_is_rule_compatible
(
rule
);
if
(
ret
!=
0
)
break
;
next_rule:
rule
=
nftnl_rule_list_iter_next
(
iter
);
}
nftnl_rule_list_iter_destroy
(
iter
);
return
ret
;
return
ret
==
0
;
}
iptables/nft.h
View file @
dab1e98e
...
...
@@ -32,12 +32,19 @@ struct nft_handle {
uint32_t
seq
;
struct
list_head
obj_list
;
int
obj_list_num
;
struct
mnl_nlmsg_batch
*
batch
;
struct
nftnl_batch
*
batch
;
struct
list_head
err_list
;
struct
nft_family_ops
*
ops
;
struct
builtin_table
*
tables
;
struct
nftnl_chain_list
*
chain_cache
;
struct
nftnl_rule_list
*
rule_cache
;
bool
restore
;
bool
batch_support
;
int8_t
config_done
;
/* meta data, for error reporting */
struct
{
unsigned
int
lineno
;
}
error
;
};
extern
struct
builtin_table
xtables_ipv4
[
TABLES_MAX
];
...
...
@@ -56,25 +63,30 @@ void nft_fini(struct nft_handle *h);
struct
nftnl_table
;
struct
nftnl_chain_list
;
int
nft_table_add
(
struct
nft_handle
*
h
,
struct
nftnl_table
*
t
,
uint16_t
flags
);
int
nft_for_each_table
(
struct
nft_handle
*
h
,
int
(
*
func
)(
struct
nft_handle
*
h
,
const
char
*
tablename
,
bool
counters
),
bool
counters
);
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
);
void
nft_table_new
(
struct
nft_handle
*
h
,
const
char
*
table
);
struct
builtin_table
*
nft_table_builtin_find
(
struct
nft_handle
*
h
,
const
char
*
table
);
/*
* Operations with chains.
*/
struct
nftnl_chain
;
int
nft_chain_add
(
struct
nft_handle
*
h
,
struct
nftnl_chain
*
c
,
uint16_t
flags
);
int
nft_chain_set
(
struct
nft_handle
*
h
,
const
char
*
table
,
const
char
*
chain
,
const
char
*
policy
,
const
struct
xt_counters
*
counters
);
struct
nftnl_chain_list
*
nft_chain_dump
(
struct
nft_handle
*
h
);
struct
nftnl_chain
*
nft_chain_list_find
(
struct
nftnl_chain_list
*
list
,
const
char
*
table
,
const
char
*
chain
);
int
nft_chain_save
(
struct
nft_handle
*
h
,
struct
nftnl_chain_list
*
list
,
const
char
*
table
);
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
);
int
nft_chain_user_del
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
bool
verbose
);
int
nft_chain_user_flush
(
struct
nft_handle
*
h
,
struct
nftnl_chain_list
*
list
,
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
);
int
nft_chain_zero_counters
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
bool
verbose
);
struct
builtin_chain
*
nft_chain_builtin_find
(
struct
builtin_table
*
t
,
const
char
*
chain
);
bool
nft_chain_exists
(
struct
nft_handle
*
h
,
const
char
*
table
,
const
char
*
chain
);
/*
* Operations with rule-set.
...
...
@@ -89,8 +101,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *tab
int
nft_rule_replace
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
void
*
data
,
int
rulenum
,
bool
verbose
);
int
nft_rule_list
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
int
rulenum
,
unsigned
int
format
);
int
nft_rule_list_save
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
int
rulenum
,
int
counters
);
int
nft_rule_save
(
struct
nft_handle
*
h
,
const
char
*
table
,
bool
counters
);
int
nft_rule_flush
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
);
int
nft_rule_save
(
struct
nft_handle
*
h
,
const
char
*
table
,
unsigned
int
format
);
int
nft_rule_flush
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
bool
verbose
);
int
nft_rule_zero_counters
(
struct
nft_handle
*
h
,
const
char
*
chain
,
const
char
*
table
,
int
rulenum
);
/*
...
...
@@ -110,8 +122,7 @@ enum nft_rule_print {
NFT_RULE_DEL
,
};
void
nft_rule_print_save
(
const
void
*
data
,
struct
nftnl_rule
*
r
,
enum
nft_rule_print
type
,
void
nft_rule_print_save
(
const
struct
nftnl_rule
*
r
,
enum
nft_rule_print
type
,
unsigned
int
format
);
uint32_t
nft_invflags2cmp
(
uint32_t
invflags
,
uint32_t
flag
);
...
...
@@ -135,9 +146,12 @@ const char *nft_strerror(int err);
/* For xtables.c */
int
do_commandx
(
struct
nft_handle
*
h
,
int
argc
,
char
*
argv
[],
char
**
table
,
bool
restore
);
/* For xtables-arptables.c */
int
do_commandarp
(
struct
nft_handle
*
h
,
int
argc
,
char
*
argv
[],
char
**
table
);
int
nft_init_arp
(
struct
nft_handle
*
h
,
const
char
*
pname
);
int
do_commandarp
(
struct
nft_handle
*
h
,
int
argc
,
char
*
argv
[],
char
**
table
,
bool
restore
);
/* For xtables-eb.c */
int
do_commandeb
(
struct
nft_handle
*
h
,
int
argc
,
char
*
argv
[],
char
**
table
);
int
nft_init_eb
(
struct
nft_handle
*
h
,
const
char
*
pname
);
int
ebt_get_current_chain
(
const
char
*
chain
);
int
do_commandeb
(
struct
nft_handle
*
h
,
int
argc
,
char
*
argv
[],
char
**
table
,
bool
restore
);
/*
* Parse config for tables and chain helper functions
...
...
@@ -182,6 +196,6 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain,
void
nft_rule_to_arpt_entry
(
struct
nftnl_rule
*
r
,
struct
arpt_entry
*
fw
);
int
nft_is_
ruleset
_compatible
(
struct
nft_handle
*
h
);
bool
nft_is_
table
_compatible
(
struct
nft_handle
*
h
,
const
char
*
name
);
#endif
iptables/tests/shell/README
0 → 100644
View file @
dab1e98e
To run the test suite (as root):
$ cd iptables/tests/shell
# ./run-tests.sh
Test files are executable files with the pattern <<name_N>> , where N is the
expected return code of the executable. Since they are located with `find',
test-files can be spreaded in any sub-directories.
You can turn on a verbose execution by calling:
# ./run-tests.sh -v
And to run test suite for pariticular test files:
# ./run-tests.sh <PATH_OF_TESTFILES>
Also, test-files will receive the environment variable $XT_MULTI which contains
the path to the old iptables (xtables-legacy-multi) or new iptables (xtables-nft-multi)
binary being tested.
iptables/tests/shell/run-tests.sh
0 → 100755
View file @
dab1e98e
#!/bin/bash
#configuration
TESTDIR
=
"./
$(
dirname
$0
)
/"
RETURNCODE_SEPARATOR
=
"_"
XTABLES_NFT_MULTI
=
"
$(
dirname
$0
)
/../../xtables-nft-multi"
XTABLES_LEGACY_MULTI
=
"
$(
dirname
$0
)
/../../xtables-legacy-multi"
export
XTABLES_LIBDIR
=
${
TESTDIR
}
/../../../extensions
msg_error
()
{
echo
"E:
$1
..."
>
&2
exit
1
}
msg_warn
()
{
echo
"W:
$1
"
>
&2
}
msg_info
()
{
echo
"I:
$1
"
}
if
[
"
$(
id
-u
)
"
!=
"0"
]
;
then
msg_error
"this requires root!"
fi
if
[
!
-d
"
$TESTDIR
"
]
;
then
msg_error
"missing testdir
$TESTDIR
"
fi
if
[
"
$1
"
==
"-v"
]
;
then
VERBOSE
=
y
shift
fi
for
arg
in
"
$@
"
;
do
if
grep
^.
*${
RETURNCODE_SEPARATOR
}
[
0-9]
\\
+
$
<<<
$arg
>
/dev/null
;
then
SINGLE+
=
"
$arg
"
VERBOSE
=
y
else
msg_error
"unknown parameter '
$arg
'"
fi
done
find_tests
()
{
if
[
!
-z
"
$SINGLE
"
]
;
then
echo
$SINGLE
return
fi
find
${
TESTDIR
}
-executable
-regex
\
.
*${
RETURNCODE_SEPARATOR
}
[
0-9]+ |
sort
}
ok
=
0
failed
=
0
do_test
()
{
testfile
=
"
$1
"
xtables_multi
=
"
$2
"
rc_spec
=
`
echo
$(
basename
${
testfile
}
)
|
cut
-d
_
-f2-
`
msg_info
"[EXECUTING]
$testfile
"
if
[
"
$VERBOSE
"
=
"y"
]
;
then
XT_MULTI
=
$xtables_multi
unshare
-n
${
testfile
}
rc_got
=
$?
else
XT_MULTI
=
$xtables_multi
unshare
-n
${
testfile
}
>
/dev/null 2>&1
rc_got
=
$?
echo
-en
"
\0
33[1A
\0
33[K"
# clean the [EXECUTING] foobar line
fi
if
[
"
$rc_got
"
==
"
$rc_spec
"
]
;
then
msg_info
"[OK]
$testfile
"
((
ok++
))
else
((
failed++
))
msg_warn
"[FAILED]
$testfile
: expected
$rc_spec
but got
$rc_got
"
fi
}
echo
""
for
testfile
in
$(
find_tests
)
;
do
do_test
"
$testfile
"
"
$XTABLES_LEGACY_MULTI
"
done
msg_info
"legacy results: [OK]
$ok
[FAILED]
$failed
[TOTAL]
$((
ok+failed
))
"
legacy_ok
=
$ok
legacy_fail
=
$failed
ok
=
0
failed
=
0
for
testfile
in
$(
find_tests
)
;
do
do_test
"
$testfile
"
"
$XTABLES_NFT_MULTI
"
done
msg_info
"nft results: [OK]
$ok
[FAILED]
$failed
[TOTAL]
$((
ok+failed
))
"
ok
=
$((
legacy_ok+ok
))
failed
=
$((
legacy_fail+failed
))
msg_info
"combined results: [OK]
$ok
[FAILED]
$failed
[TOTAL]
$((
ok+failed
))
"
exit
0
iptables/tests/shell/testcases/arptables/0001-arptables-save-restore_0
0 → 100755
View file @
dab1e98e
#!/bin/bash
set
-e
#set -x
# there is no legacy backend to test
[[
$XT_MULTI
==
*
/xtables-nft-multi
]]
||
{
echo
"skip
$XT_MULTI
"
;
exit
0
;
}
# fill arptables manually
$XT_MULTI
arptables
-F
$XT_MULTI
arptables
-A
INPUT
-s
10.0.0.0/8
-j
ACCEPT
$XT_MULTI
arptables
-A
INPUT
-d
192.168.123.1
-j
ACCEPT
#$XT_MULTI arptables -A INPUT --source-mac fe:ed:ba:be:00:01 -j ACCEPT
#$XT_MULTI arptables -A INPUT --destination-mac fe:ed:ba:be:00:01 -j ACCEPT
$XT_MULTI
arptables
-N
foo
$XT_MULTI
arptables
-A
foo
-i
lo
-j
ACCEPT
$XT_MULTI
arptables
-A
foo
-l
6
-j
ACCEPT
$XT_MULTI
arptables
-A
foo
--opcode
Request
-j
ACCEPT
$XT_MULTI
arptables
-A
foo
--h-type
1
--proto-type
0x800
-j
ACCEPT
$XT_MULTI
arptables
-A
foo
-l
6
--h-type
1
--proto-type
0x800
-i
lo
--opcode
Request
-j
ACCEPT
$XT_MULTI
arptables
-A
INPUT
-j
foo
$XT_MULTI
arptables
-A
INPUT
$XT_MULTI
arptables
-A
OUTPUT
-o
lo
-j
ACCEPT
$XT_MULTI
arptables
-A
OUTPUT
-o
eth134
-j
mangle
--mangle-ip-s
10.0.0.1
$XT_MULTI
arptables
-A
OUTPUT
-o
eth432
-j
CLASSIFY
--set-class
feed:babe
$XT_MULTI
arptables
-A
OUTPUT
-o
eth432
--opcode
Request
-j
CLASSIFY
--set-class
feed:babe
$XT_MULTI
arptables
-P
OUTPUT DROP
# compare against stored arptables dump
DUMP
=
'*filter
:INPUT ACCEPT
:OUTPUT DROP
:foo -
-A INPUT -s 10.0.0.0/8 -j ACCEPT
-A INPUT -d 192.168.123.1 -j ACCEPT
-A INPUT -j foo
-A INPUT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -o eth134 -j mangle --mangle-ip-s 10.0.0.1
-A OUTPUT -o eth432 -j CLASSIFY --set-class feed:babe
-A OUTPUT -o eth432 --opcode 1 -j CLASSIFY --set-class feed:babe
-A foo -i lo -j ACCEPT
-A foo --h-length 6 -j ACCEPT
-A foo --opcode 1 -j ACCEPT
-A foo --h-type 1 --proto-type 0x800 -j ACCEPT
-A foo -i lo --h-length 6 --opcode 1 --h-type 1 --proto-type 0x800 -j ACCEPT
'
diff
-u
<
(
echo
-e
"
$DUMP
"
)
<
(
$XT_MULTI
arptables-save
)
# make sure dump can be restored and check it didn't change
$XT_MULTI
arptables
-F
$XT_MULTI
arptables-restore
<<<
$DUMP
diff
-u
<
(
echo
-e
"
$DUMP
"
)
<
(
$XT_MULTI
arptables-save
)
iptables/tests/shell/testcases/arptables/0002-arptables-restore-defaults_0
0 → 100755
View file @
dab1e98e
#!/bin/bash
set
-e
# there is no legacy backend to test
[[
$XT_MULTI
==
*
/xtables-nft-multi
]]
||
{
echo
"skip
$XT_MULTI
"
;
exit
0
;
}
# arptables-restore reuses preloaded targets and matches, make sure defaults
# apply to consecutive rules using the same target/match as a previous one
DUMP
=
'*filter
:OUTPUT ACCEPT
-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2
'
# note how mangle-ip-s is unset in second rule
EXPECT
=
'*filter
:INPUT ACCEPT
:OUTPUT ACCEPT
-A OUTPUT -j mangle --mangle-ip-s 10.0.0.1
-A OUTPUT -j mangle --mangle-ip-d 10.0.0.2
'
$XT_MULTI
arptables
-F
$XT_MULTI
arptables-restore
<<<
$DUMP
diff
-u
<
(
echo
-e
"
$EXPECT
"
)
<
(
$XT_MULTI
arptables-save |
grep
-v
'^#'
)
iptables/tests/shell/testcases/chain/0001duplicate_1
0 → 100755
View file @
dab1e98e
#!/bin/bash
set
-x
$XT_MULTI
iptables
-t
filter
-N
c1
||
exit
0
$XT_MULTI
iptables
-t
filter
-N
c1
||
exit
1
$XT_MULTI
ip6tables
-t
filter
-N
c1
||
exit
0
$XT_MULTI
ip6tables
-t
filter
-N
c1
||
exit
1
echo
"E: Duplicate chains"
>
&2
exit
0
iptables/tests/shell/testcases/chain/0002newchain_0
0 → 100755
View file @
dab1e98e
#!/bin/bash
set
-e
$XT_MULTI
iptables
-N
c1
$XT_MULTI
ip6tables
-N
c1
$XT_MULTI
iptables
-N
c2
$XT_MULTI
ip6tables
-N
c2
iptables/tests/shell/testcases/chain/0003rename_1
0 → 100755
View file @
dab1e98e
#!/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
iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
0 → 100755
View file @
dab1e98e
#!/bin/sh
set
-x
case
"
$XT_MULTI
"
in
*
/xtables-nft-multi
)
for
t
in
filter nat
;
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
$XT_MULTI
ebtables
-t
$t
-L
&&
$XT_MULTI
ebtables
-t
$t
-X
&&
$XT_MULTI
ebtables
-t
$t
-F
if
[
$?
-eq
0
]
;
then
echo
"Expect nonzero return for unsupported table"
exit
1
fi
done
$XT_MULTI
ebtables
-t
filter
-N
FOO
||
exit
1
$XT_MULTI
ebtables
-t
filter
-N
FOO
if
[
$?
-eq
0
]
;
then
echo
"Duplicate chain FOO"
$XT_MULTI
ebtables
-t
filter
-L
exit
1
fi
$XT_MULTI
ebtables
-L
FOO |
grep
-q
'entries: 0'
if
[
$?
-ne
0
]
;
then
echo
"Unexpected entries count in empty unreferenced chain"
$XT_MULTI
ebtables
-L
exit
1
fi
$XT_MULTI
ebtables
-A
FORWARD
-j
FOO
$XT_MULTI
ebtables
-L
FORWARD |
grep
-q
'entries: 1'
if
[
$?
-ne
0
]
;
then
echo
"Unexpected entries count in FORWARD chain"
$XT_MULTI
ebtables
-L
exit
1
fi
$XT_MULTI
ebtables
-L
FOO |
grep
-q
'entries: 0'
if
[
$?
-ne
0
]
;
then
echo
"Unexpected entries count in empty referenced chain"
$XT_MULTI
ebtables
-L
exit
1
fi
$XT_MULTI
ebtables
-A
FOO
-j
ACCEPT
$XT_MULTI
ebtables
-L
FOO |
grep
-q
'entries: 1'
if
[
$?
-ne
0
]
;
then
echo
"Unexpected entries count in non-empty referenced chain"
$XT_MULTI
ebtables
-L
exit
1
fi
$XT_MULTI
ebtables
-t
filter
-N
BAR
||
exit
1
$XT_MULTI
ebtables
-t
filter
-N
BAZ
||
exit
1
$XT_MULTI
ebtables
-t
filter
-L
|
grep
-q
FOO
||
exit
1
$XT_MULTI
ebtables
-t
filter
-L
|
grep
-q
BAR
||
exit
1
$XT_MULTI
ebtables
-t
filter
-L
|
grep
-q
BAZ
||
exit
1
$XT_MULTI
ebtables
-t
filter
-L
BAZ
||
exit
1
$XT_MULTI
ebtables
-t
filter
-X
BAZ
||
exit
1
$XT_MULTI
ebtables
-t
filter
-L
BAZ |
grep
-q
BAZ
if
[
$?
-eq
0
]
;
then
echo
"Deleted chain -L BAZ ok, expected failure"
$XT_MULTI
ebtables
-t
filter
-L
exit
1
fi
$XT_MULTI
ebtables
-t
$t
-F
||
exit
0
;;
*
)
echo
"skip
$XT_MULTI
"
;;
esac
iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
0 → 100755
View file @
dab1e98e
#!/bin/bash
set
-e
#set -x
# there is no legacy backend to test
[[
$XT_MULTI
==
*
/xtables-nft-multi
]]
||
{
echo
"skip
$XT_MULTI
"
;
exit
0
;
}
# fill ebtables manually
$XT_MULTI
ebtables
--init-table
$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 --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
$XT_MULTI
ebtables
-A
foo
-p
ARP
--arp-ip-src
10.0.0.1
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
ARP
--arp-ip-dst
10.0.0.0/8
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
ARP
--arp-mac-src
fe:ed:ba:be:00:01
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
ARP
--arp-mac-dst
fe:ed:ba:be:00:01/ff:ff:ff:00:00:00
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
IPv4
--ip-src
10.0.0.1
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
IPv4
--ip-dst
10.0.0.0/8
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
IPv4
--ip-tos
0x10
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
IPv4
--ip-protocol
tcp
-j
ACCEPT
#$XT_MULTI ebtables -A foo -p IPv4 --ip-sport 23 -j ACCEPT
#$XT_MULTI ebtables -A foo -p IPv4 --ip-dport 1024:4096 -j ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
IPv6
--ip6-src
feed:babe::1
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
IPv6
--ip6-dst
feed:babe::/64
-j
ACCEPT
$XT_MULTI
ebtables
-A
foo
-p
IPv6
--ip6-proto
tcp
-j
ACCEPT
#$XT_MULTI ebtables -A foo -p IPv6 --ip6-sport 23 -j ACCEPT
#$XT_MULTI ebtables -A foo -p IPv6 --ip6-dport 1024:4096 -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
--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
--pkttype-type
multicast
--log
$XT_MULTI
ebtables
-A
foo
--pkttype-type
multicast
--limit
100
-j
ACCEPT
$XT_MULTI
ebtables
-A
FORWARD
-j
foo
$XT_MULTI
ebtables
-t
nat
-A
PREROUTING
--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
$XT_MULTI
ebtables
-t
nat
-P
OUTPUT DROP
$XT_MULTI
ebtables
-t
nat
-A
POSTROUTING
-j
ACCEPT
#$XT_MULTI ebtables -t nat -A POSTROUTING --to-dst fe:ed:ba:be:00:01 --dnat-target ACCEPT
# compare against stored ebtables dump
DUMP
=
'*filter
:INPUT ACCEPT
:FORWARD DROP
:OUTPUT ACCEPT
: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 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
-A foo -p ARP --arp-ip-dst 10.0.0.0/8 -j ACCEPT
-A foo -p ARP --arp-mac-src fe:ed:ba:be:0:1 -j ACCEPT
-A foo -p ARP --arp-mac-dst fe:ed:ba:0:0:0/ff:ff:ff:0:0:0 -j ACCEPT
-A foo -p IPv4 --ip-src 10.0.0.1 -j ACCEPT
-A foo -p IPv4 --ip-dst 10.0.0.0/8 -j ACCEPT
-A foo -p IPv4 --ip-tos 0x10 -j ACCEPT
-A foo -p IPv4 --ip-proto tcp -j ACCEPT
-A foo -p IPv6 --ip6-src feed:babe::1 -j ACCEPT
-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 -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 --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT
*nat
:PREROUTING ACCEPT
:OUTPUT DROP
:POSTROUTING ACCEPT
-A PREROUTING -j redirect
-A OUTPUT -j ACCEPT
-A POSTROUTING -j ACCEPT
'
diff
-u
<
(
echo
-e
"
$DUMP
"
)
<
(
$XT_MULTI
ebtables-save |
grep
-v
'^#'
)
# make sure dump can be restored and check it didn't change
$XT_MULTI
ebtables
--init-table
$XT_MULTI
ebtables-restore
<<<
$DUMP
diff
-u
<
(
echo
-e
"
$DUMP
"
)
<
(
$XT_MULTI
ebtables-save |
grep
-v
'^#'
)
Prev
1
…
6
7
8
9
10
11
12
13
14
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