Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F118307010
test_nat.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
test_nat.py
View Options
#!/usr/bin/env python3
#
# Copyright (C) 2020 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import
os
import
jmespath
import
json
import
unittest
from
vyos.configsession
import
ConfigSession
from
vyos.configsession
import
ConfigSessionError
from
vyos.util
import
cmd
from
vyos.util
import
vyos_dict_search
base_path
=
[
'nat'
]
src_path
=
base_path
+
[
'source'
]
dst_path
=
base_path
+
[
'destination'
]
class
TestNAT
(
unittest
.
TestCase
):
def
setUp
(
self
):
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
self
.
session
=
ConfigSession
(
os
.
getpid
())
self
.
session
.
delete
(
base_path
)
def
tearDown
(
self
):
self
.
session
.
delete
(
base_path
)
self
.
session
.
commit
()
def
test_snat
(
self
):
""" Test source NAT (SNAT) rules """
rules
=
[
'100'
,
'110'
,
'120'
,
'130'
,
'200'
,
'210'
,
'220'
,
'230'
]
outbound_iface_100
=
'eth0'
outbound_iface_200
=
'eth1'
for
rule
in
rules
:
network
=
f
'192.168.{rule}.0/24'
# depending of rule order we check either for source address for NAT
# or configured destination address for NAT
if
int
(
rule
)
<
200
:
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'source'
,
'address'
,
network
])
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'outbound-interface'
,
outbound_iface_100
])
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'translation'
,
'address'
,
'masquerade'
])
else
:
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'destination'
,
'address'
,
network
])
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'outbound-interface'
,
outbound_iface_200
])
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'exclude'
])
self
.
session
.
commit
()
tmp
=
cmd
(
'sudo nft -j list table nat'
)
data_json
=
jmespath
.
search
(
'nftables[?rule].rule[?chain]'
,
json
.
loads
(
tmp
))
for
idx
in
range
(
0
,
len
(
data_json
)):
rule
=
str
(
rules
[
idx
])
data
=
data_json
[
idx
]
network
=
f
'192.168.{rule}.0/24'
self
.
assertEqual
(
data
[
'chain'
],
'POSTROUTING'
)
self
.
assertEqual
(
data
[
'comment'
],
f
'SRC-NAT-{rule}'
)
self
.
assertEqual
(
data
[
'family'
],
'ip'
)
self
.
assertEqual
(
data
[
'table'
],
'nat'
)
iface
=
vyos_dict_search
(
'match.right'
,
data
[
'expr'
][
0
])
direction
=
vyos_dict_search
(
'match.left.payload.field'
,
data
[
'expr'
][
1
])
address
=
vyos_dict_search
(
'match.right.prefix.addr'
,
data
[
'expr'
][
1
])
mask
=
vyos_dict_search
(
'match.right.prefix.len'
,
data
[
'expr'
][
1
])
if
int
(
rule
)
<
200
:
self
.
assertEqual
(
direction
,
'saddr'
)
self
.
assertEqual
(
iface
,
outbound_iface_100
)
# check for masquerade keyword
self
.
assertIn
(
'masquerade'
,
data
[
'expr'
][
3
])
else
:
self
.
assertEqual
(
direction
,
'daddr'
)
self
.
assertEqual
(
iface
,
outbound_iface_200
)
# check for return keyword due to 'exclude'
self
.
assertIn
(
'return'
,
data
[
'expr'
][
3
])
self
.
assertEqual
(
f
'{address}/{mask}'
,
network
)
def
test_dnat
(
self
):
""" Test destination NAT (DNAT) rules """
rules
=
[
'100'
,
'110'
,
'120'
,
'130'
,
'200'
,
'210'
,
'220'
,
'230'
]
inbound_iface_100
=
'eth0'
inbound_iface_200
=
'eth1'
inbound_proto_100
=
'udp'
inbound_proto_200
=
'tcp'
for
rule
in
rules
:
port
=
f
'10{rule}'
self
.
session
.
set
(
dst_path
+
[
'rule'
,
rule
,
'source'
,
'port'
,
port
])
self
.
session
.
set
(
dst_path
+
[
'rule'
,
rule
,
'translation'
,
'address'
,
'192.0.2.1'
])
self
.
session
.
set
(
dst_path
+
[
'rule'
,
rule
,
'translation'
,
'port'
,
port
])
if
int
(
rule
)
<
200
:
self
.
session
.
set
(
dst_path
+
[
'rule'
,
rule
,
'protocol'
,
inbound_proto_100
])
self
.
session
.
set
(
dst_path
+
[
'rule'
,
rule
,
'inbound-interface'
,
inbound_iface_100
])
else
:
self
.
session
.
set
(
dst_path
+
[
'rule'
,
rule
,
'protocol'
,
inbound_proto_200
])
self
.
session
.
set
(
dst_path
+
[
'rule'
,
rule
,
'inbound-interface'
,
inbound_iface_200
])
self
.
session
.
commit
()
tmp
=
cmd
(
'sudo nft -j list table nat'
)
data_json
=
jmespath
.
search
(
'nftables[?rule].rule[?chain]'
,
json
.
loads
(
tmp
))
for
idx
in
range
(
0
,
len
(
data_json
)):
rule
=
str
(
rules
[
idx
])
data
=
data_json
[
idx
]
port
=
int
(
f
'10{rule}'
)
self
.
assertEqual
(
data
[
'chain'
],
'PREROUTING'
)
self
.
assertEqual
(
data
[
'comment'
]
.
split
()[
0
],
f
'DST-NAT-{rule}'
)
self
.
assertEqual
(
data
[
'family'
],
'ip'
)
self
.
assertEqual
(
data
[
'table'
],
'nat'
)
iface
=
vyos_dict_search
(
'match.right'
,
data
[
'expr'
][
0
])
direction
=
vyos_dict_search
(
'match.left.payload.field'
,
data
[
'expr'
][
1
])
protocol
=
vyos_dict_search
(
'match.left.payload.protocol'
,
data
[
'expr'
][
1
])
dnat_addr
=
vyos_dict_search
(
'dnat.addr'
,
data
[
'expr'
][
3
])
dnat_port
=
vyos_dict_search
(
'dnat.port'
,
data
[
'expr'
][
3
])
self
.
assertEqual
(
direction
,
'sport'
)
self
.
assertEqual
(
dnat_addr
,
'192.0.2.1'
)
self
.
assertEqual
(
dnat_port
,
port
)
if
int
(
rule
)
<
200
:
self
.
assertEqual
(
iface
,
inbound_iface_100
)
self
.
assertEqual
(
protocol
,
inbound_proto_100
)
else
:
self
.
assertEqual
(
iface
,
inbound_iface_200
)
def
test_validation_logic
(
self
):
""" T2813: Ensure translation address is specified """
rule
=
'5'
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'source'
,
'address'
,
'192.0.2.0/24'
])
# check validate() - outbound-interface must be defined
with
self
.
assertRaises
(
ConfigSessionError
):
self
.
session
.
commit
()
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'outbound-interface'
,
'eth0'
])
# check validate() - translation address not specified
with
self
.
assertRaises
(
ConfigSessionError
):
self
.
session
.
commit
()
self
.
session
.
set
(
src_path
+
[
'rule'
,
rule
,
'translation'
,
'address'
,
'masquerade'
])
self
.
session
.
commit
()
if
__name__
==
'__main__'
:
unittest
.
main
()
File Metadata
Details
Attached
Mime Type
text/x-script.python
Expires
Sat, Oct 17, 12:23 AM (8 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4401725
Default Alt Text
test_nat.py (6 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment