Post

Iptables / Nftables

Iptables / Nftables

Iptables is the main packet filtering and firewalling tool in the Linux world. It’s developed by a company named NetFilter. So iptables becomes deprecated over the time and nftables is the new implementation of iptables.

Enable routing

With this command you can activate routing, but this setting is not perstistent and will get deactivated upon next reboot. What happens is we change the kernel parameter for ip forwarding.

1
sysctl -w net.ipv4.ip_forward=1

To make this option persistent due to reboots you have to edit /etc/sysctl.conf. On Debian-like distros this option is already there and just has to be uncommented and changed to 1.

1
net.ipv4.ip_forward = 1

Installation

1
apt install nftables

Converting iptables to nftables

If you want to set something with iptables and try out rules.

1
iptables -t nat -A POSTROUTING  -s 192.168.2.0/24 -o enp0s3 -j MASQUERADE

This command activates NAT-ing (Routing) on the “WAN”-Interface

1
nft list ruleset
1
2
3
4
5
table ip nat {
        chain POSTROUTING {
                type nat hook postrouting priority srcnat; policy accept;
                oifname "enp0s3" ip saddr { 192.168.2.0/24 } masquerade
        }

Then you have to copy the added line to /etc/nftables.conf

Enable simple NAT-ing

Edit `/etc/nftables.conf’.

1
2
3
4
5
6
7
8
9
10
11
12
13
flush ruleset
...

table ip nat {
    chain prerouting {
        type nat hook prerouting priority 0; policy accept;
    }

    chain postrouting {
        type nat hook postrouting srcnat; policy accept;
        oifname "eth0" ip saddr { 192.168.0.0/24, 10.12.0.0/24 } masquerade
    }
}
valuedescription
oifname “eth0”Specifies the WAN-Interface which is the NAT-Interface
ip saddr { }You can leave this option you route all incoming traffic or specify a single ip net without brackets or multiple ip nets within brackets.
masqueradeThis option must be set to swap the internal source ip address with the source ip address of the WAN/NAT interface

Troubleshooting

1
nft list ruleset

or

1
tcpdump -ni any icmp
parameterdescription
-nNo dns lookup
-iinteractive, lists actual traffic if there is any
anySpecifies the device, e.g. like eth0
icmpSpecifies the protocol, e.g. like ping (icmp) for testing

Use iptables as a script

For giving you an impression of how you can utilize iptables within a script with a few examples you can have a look at this script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#!/bin/bash
# IP-Tables script
#
# program in short
ipt=$(which iptables)

# activate debugging aktivieren  'set -x'
#deactivate debugging 'set +x'

# Adapteraliases
green=enp7s0       # Client net
orange=enp8s0     # dmz
red=enp1s0            # internet

# Netze
green_net=10.10.11.0/24
dmz_net=10.10.21.0/24

### functions
function start(){
	# activate routing
	sysctl -w net.ipv4.ip_forward=1 > /dev/null
	echo "+ Routing enabled"

	# set implicit deny to block all traffic and whitelist allowed traffic afterwards
	${ipt} -P INPUT   DROP
	${ipt} -P OUTPUT  DROP
	${ipt} -P FORWARD DROP
	echo "+ IMPLICIT DENY"

	# clear all existing rules
	${ipt} -F INPUT
	${ipt} -F OUTPUT
	${ipt} -F FORWARD
	${ipt} -t nat -F
	${ipt} -t filter -F

	# activate stateful-inspection
	# when writing a rule in a specific direction then iptables automatically opens the way back
	${ipt} -I INPUT   -m state --state ESTABLISHED,RELATED -j ACCEPT
	${ipt} -I OUTPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT
	${ipt} -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

	${ipt} -I INPUT  -i lo -j ACCEPT
	${ipt} -I OUTPUT -o lo -j ACCEPT
	echo "+ ACCEPT Loopback traffic"

		${ipt} -I OUTPUT -p icmp --icmp-type ping -j ACCEPT
	echo "+ Allow pinging from itself"

	${ipt} -A OUTPUT -p tcp --sport 1024: --dport 22 -j ACCEPT
	echo "+ Allow ssh to sshd port 22"

	${ipt} -A INPUT -p tcp -i ${green} --sport 1024: --dport 1337 -j ACCEPT
	echo "+ Allow ssh from green_net"

		${ipt} -A INPUT -p tcp -i ${red} --sport 1024: --dport 1337 -j ACCEPT
	echo "+ Allow ssh from red_net"

	${ipt} -A OUTPUT -p udp -o ${red} --sport 1024: --dport 53 -j ACCEPT
	${ipt} -A OUTPUT -p tcp -o ${red} --sport 1024: --dport 53 -j ACCEPT
	echo "+ Allow dns from internet"

	${ipt} -A INPUT -p udp -i ${green} --sport 1024: --dport 53 -j ACCEPT
	${ipt} -A INPUT -p tcp -i ${green} --sport 1024: --dport 53 -j ACCEPT
	echo "+ Allow dns from green_net"

	${ipt} -A INPUT -p udp -i ${orange} --sport 1024: --dport 53 -j ACCEPT
	${ipt} -A INPUT -p tcp -i ${orange} --sport 1024: --dport 53 -j ACCEPT
	echo "+ Allow dns from orange_net"

	${ipt} -A INPUT -p udp -i ${orange} --sport 123 --dport 123 -j ACCEPT
	${ipt} -A INPUT -p udp -i ${green} --sport 123 --dport 123 -j ACCEPT
	echo "+ Allow ntp from orange_net & green_net"

	${ipt} -A OUTPUT -p tcp -o ${red} --sport 1024: --dport 80 -j ACCEPT
	${ipt} -A OUTPUT -p tcp -o ${red} --sport 1024: --dport 443 -j ACCEPT
	echo "+ Allow https from internet"

	${ipt} -A OUTPUT -p udp -o ${red} --sport 123 --dport 123 -j ACCEPT
	echo "+ Allow ntp from internet"

	${ipt} -A INPUT -p tcp -i ${green} --sport 1024: --dport 3128 -j ACCEPT
	echo "+ Allow squid from green_net"

	${ipt} -A INPUT -p tcp -i ${orange} --sport 1024: --dport 3128 -j ACCEPT
	echo "+ Allow squid from orange_net"

	# allow forwarding ping from green_net or orange_net to red_net
	${ipt} -A FORWARD -p icmp -i ${green} -o ${red} --icmp-type ping -j ACCEPT
	${ipt} -A FORWARD -p icmp -i ${orange} -o ${red} --icmp-type ping -j ACCEPT

	# ssh
	${ipt} -A FORWARD -p tcp -i ${green} -o ${red} --sport 1024: --dport 22 -j ACCEPT

	# ftp
	${ipt} -A FORWARD -p tcp -i ${green} -o ${red} --sport 1024: --dport 21 -j ACCEPT #ftp signal
	${ipt} -A FORWARD -p tcp -i ${green} -o ${red} --sport 1024: --dport 20 -j ACCEPT #ftp trsp

	# rdp
	${ipt} -A FORWARD -p tcp -i ${green} -o ${red} --sport 1024: --dport 3389 -j ACCEPT

	# smtp(s)
	${ipt} -A FORWARD -p tcp -i ${green} -o ${red} --sport 1024: --dport 25 -j ACCEPT
	${ipt} -A FORWARD -p tcp -i ${green} -o ${red} --sport 1024: --dport 465 -j ACCEPT
	echo "+ Appending forwarding rules from green to red (icmp,ssh,ftp,rdp,smtp)"

	# forwarding from red to orange

	# http
	${ipt} -A FORWARD -p tcp -i ${red} -o ${orange} --dport 80 -j ACCEPT
	#${ipt} -A FORWARD -p tcp -i ${red} -o ${orange} --dport 443 -j ACCEPT

	# smtp
	${ipt} -A FORWARD -p tcp -i ${red} -o ${orange} --dport 25 -j ACCEPT

	# ssh
	${ipt} -A FORWARD -p tcp -i ${red} -o ${orange} --dport 22 -j ACCEPT

	# DNAT für orange_net zu  dmz-srv
	${ipt} -t nat -A PREROUTING -p tcp -i ${red} --dport 80 -j DNAT --to 10.10.21.2
	${ipt} -t nat -A PREROUTING -p tcp -i ${red} --dport 25 -j DNAT --to 10.10.21.2
	${ipt} -t nat -A PREROUTING -p tcp -i ${red} --dport 3333 -j DNAT --to 10.10.21.2:22
	echo "+ Portforwarding :22,:25,:80 to 10.10.21.2"

	# Enable SNAT
	${ipt} -t nat -A POSTROUTING -o ${red} -j MASQUERADE
	echo "+ Enable NAT"

	# Activate Logging for INPUT and FORWARD
	${ipt} -A INPUT -j LOG --log-prefix "INPUT_LOG: "
	${ipt} -A FORWARD -j LOG --log-prefix "FORWARD_LOG: "
	echo "+ Logging enabled"
}

function stop(){
	sysctl -w net.ipv4.ip_forward=0 > /dev/null
	echo "+ Routing disabled"

	${ipt} -P INPUT   ACCEPT
	${ipt} -P OUTPUT  ACCEPT
	${ipt} -P FORWARD ACCEPT
	echo "+ ALLOW ANY ANY"

	${ipt} -F INPUT
	${ipt} -F OUTPUT
	${ipt} -F FORWARD
	${ipt} -t nat -F
	${ipt} -t filter -F
	echo "+ Tables and rules flushed"

	${ipt} -D INPUT -j LOG --log-prefix "INPUT_LOG: "
	${ipt} -D FORWARD -j LOG --log-prefix "FORWARD_LOG: "
	echo "+ Logging disabled"
}

function save_rules(){
	sudo iptables-save > /etc/iptables/rules.v4
	echo "Rules saved"
}

function status(){
	${ipt} -L -n -v
	${ipt} -t nat -L -n -v
}

# Bildschirm löschen
clear

case "$1" in
	start)
		start
		;;
	stop)
		stop
		;;
	restart)
		stop
		start
		;;
	status)
		status
		;;
	save)
		save_rules
		;;
	*)
		echo "Command: ${0} {start|stop|restart|status|save}"
esac

Further reading: Gentoo nftables examples

This post is licensed under CC BY 4.0 by the author.