kristrev

OpenWRT + nftables - first attempt

Jul 14th, 2019
587
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.55 KB | None | 0 0
  1. nftables is the successor to iptables and it is time for OpenWRT to make the switch. Before we can start implementing firewall4, we need to get a feel for how nftables works, possibilities etc. The set of commands below represents my attempt at understanding nftables, and how we initially can leverage at least some of the new features. My commands are a manual conversion of an iptables filter-table corresponding to the configuration at the bottom of this document. I have not tested my nftables configuration very thorougly, but at least the base functionality works.
  2.  
  3. nftables has gotten rid of the default tables and chains from iptables, and leaves the configuration completely up to a user. A table is just a collection of chains, and base chains are given a hook and a priority. In other words, a user has completely control over when a chain is hit and the order in which chains are hit. base chains roughly works in the same way as the default iptables chains, and more information about hooks and priorities can be found here: https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
  4.  
  5. My nftables-configuration closely matches the structure of the iptables rules. There are three base chains - filter_input, filter_forward and filter_output - that all have the filter priority and run on the correct hooks. On the machine I used for testing there were two firewall zones - wan and lan - so the rest of the chains are the normal "zone_lan_input", "zone_lan_forward", etc. The only difference is that all the chains are prefixed with "filter_".
  6.  
  7. The biggest difference from iptables, if you ask me, is that there is one table and one set of chains for both ipv4 and ipv6. nftables supports dual-configuration via the "inet"-family, and not having to main two set of rules greatly reduces size of ruleset and complexity if you ask me. Some rules only apply to either family, but instead of creating a complex structure with new tables and sets of chains, I have instead just added a match on l3-protocol. Another approach would be to keep ipv4/ipv6-specific rules in separate chains, and only jump to this chain if the l3-protcol matches.
  8.  
  9. Another big difference is that the use of sets eliminates or at least reduces the size of the old zone_lan_src_ACCEPT, zone_wan_dest_ACCEPT, etc. chains. By adding the interfaces belonging to a chain to a set, we can match on this set and for example accept right away or jump to a much smaller version of zone_wan_dest_ACCEPT.
  10.  
  11. I originally planned to use maps (which is built on top of sets) plus a feature called concatination for the traffic rules as well. Concatination enables set elements to consist of multiple selectors, so it is possible to create for example tuples. However, I chose not to do this as it is for example not possible to do wildcard-matching or cidr-matching in a set. Thus, we would have to create a large number of different types of set. While it would be possible to for example create the different set types on demand, this might quicly grow complex. I think we should stick with traffic rules as they are today, and then monitor/contribute to upstream. Sets can probably still be used for DNAT/SNAT, as well as rules for ICMP (already done in my example commands).
  12.  
  13. Based on this experience, forking firewall3 and adding initial nftables support should not be that hard. There are some things that are not available in nftables (like date), but it seems like all features we need are already present. We need to decide on an overall structure, but once those are out of the way then the amount of work should not be overwhelming. I hope my set of rules and description can serve as useful input to OpenWRT + nftables.
  14.  
  15. ## Rules
  16.  
  17. #C&P to a file, then load the filter with nft -f <filename>
  18.  
  19. #Flush all nftables rules
  20. flush ruleset
  21.  
  22. #Create table, it will be used for both ipv4 and ipv6
  23. add table inet firewall4
  24.  
  25. #Create base filter chains
  26. add chain inet firewall4 filter_input {type filter hook input priority 0; policy accept;}
  27. add chain inet firewall4 filter_forward {type filter hook forward priority 0; policy drop;}
  28. add chain inet firewall4 filter_output {type filter hook output priority 0; policy accept;}
  29.  
  30. #Create output/forward/input zone rules
  31. add chain inet firewall4 filter_zone_lan_input
  32. add chain inet firewall4 filter_zone_lan_forward
  33. add chain inet firewall4 filter_zone_lan_output
  34.  
  35. add chain inet firewall4 filter_zone_wan_input
  36. add chain inet firewall4 filter_zone_wan_forward
  37. add chain inet firewall4 filter_zone_wan_output
  38.  
  39. #Create chains for user controlled rules
  40. add chain inet firewall4 filter_input_rule
  41. add chain inet firewall4 filter_forwarding_rule
  42. add chain inet firewall4 filter_output_rule
  43.  
  44. #Create lan zone user chains
  45. add chain inet firewall4 filter_input_lan_rule
  46. add chain inet firewall4 filter_forwarding_lan_rule
  47. add chain inet firewall4 filter_output_lan_rule
  48.  
  49. #Create wan zone user chains
  50. add chain inet firewall4 filter_input_wan_rule
  51. add chain inet firewall4 filter_forwarding_wan_rule
  52. add chain inet firewall4 filter_output_wan_rule
  53.  
  54. #Create and populate reject chain. The reason for not keeping the reject rules
  55. #in a map, is that we have no guarantee the tcp match is evalued before the any
  56. #match. Reason for the strange chain name is that reject is a
  57. add chain inet firewall4 filter_reject_c
  58. add rule inet firewall4 filter_reject_c ip protocol tcp reject with tcp reset
  59. add rule inet firewall4 filter_reject_c reject #Default reject action is port-unreachable
  60.  
  61. #Create and populate zone interface sets
  62. add set inet firewall4 zone_lan_if { type ifname; }
  63. add set inet firewall4 zone_wan_if { type ifname; }
  64. add element inet firewall4 zone_lan_if { eth2, eth2.245 }
  65. add element inet firewall4 zone_wan_if { eth0, eth1 }
  66.  
  67. #Populate input
  68. add rule inet firewall4 filter_input iif lo accept
  69. add rule inet firewall4 filter_input jump filter_input_rule
  70. add rule inet firewall4 filter_input ct state { related, established } accept
  71. add rule inet firewall4 filter_input tcp flags & (fin|syn|rst|ack) == syn limit rate over 25/second burst 50 packets drop
  72. add rule inet firewall4 filter_input iifname @zone_lan_if jump filter_zone_lan_input
  73. add rule inet firewall4 filter_input iifname @zone_wan_if jump filter_zone_wan_input
  74.  
  75. #Populate forwarding
  76. add rule inet firewall4 filter_forward jump filter_forwarding_rule
  77. add rule inet firewall4 filter_forward ct state { related, established } accept
  78. add rule inet firewall4 filter_forward iifname @zone_lan_if jump filter_zone_lan_forward
  79. add rule inet firewall4 filter_forward iifname @zone_wan_if jump filter_zone_wan_forward
  80. add rule inet firewall4 filter_forward jump filter_reject_c
  81.  
  82. #Populate output
  83. add rule inet firewall4 filter_output oif lo accept
  84. add rule inet firewall4 filter_output jump filter_output_rule
  85. add rule inet firewall4 filter_output ct state { related, established } accept
  86. add rule inet firewall4 filter_output iifname @zone_lan_if jump filter_zone_lan_output
  87. add rule inet firewall4 filter_output iifname @zone_wan_if jump filter_zone_wan_output
  88.  
  89. #zone_wan_dest_ACCEPT, no need to check for interface since we use the set as a match before jumping here
  90. add chain inet firewall4 filter_zone_wan_dest_ACCEPT
  91. add rule inet firewall4 filter_zone_wan_dest_ACCEPT ct state invalid drop
  92. add rule inet firewall4 filter_zone_wan_dest_ACCEPT accept
  93.  
  94. #zone_lan_forward
  95. add rule inet firewall4 filter_zone_lan_forward jump filter_forwarding_lan_rule
  96. add rule inet firewall4 filter_zone_lan_forward oifname @zone_wan_if jump filter_zone_wan_dest_ACCEPT
  97. add rule inet firewall4 filter_zone_lan_forward ip version 4 ct status dnat accept
  98. add rule inet firewall4 filter_zone_lan_forward oifname @zone_lan_if accept
  99.  
  100. #zone_lan_input
  101. add rule inet firewall4 filter_zone_lan_input jump filter_input_lan_rule
  102. add rule inet firewall4 filter_zone_lan_input ct status dnat accept
  103. add rule inet firewall4 filter_zone_lan_input iifname @zone_lan_if ct state { new, untracked } accept
  104.  
  105. #zone_lan_output
  106. add rule inet firewall4 filter_zone_lan_output jump filter_output_lan_rule
  107. add rule inet firewall4 filter_zone_lan_output oifname @zone_lan_if accept
  108.  
  109. #zone_wan_output
  110. add rule inet firewall4 filter_zone_wan_output jump filter_output_wan_rule
  111. add rule inet firewall4 filter_zone_wan_output oifname @zone_wan_if jump filter_zone_wan_dest_ACCEPT
  112.  
  113. #zone_wan_forward
  114. add rule inet firewall4 filter_zone_wan_forward jump filter_forwarding_wan_rule
  115. add rule inet firewall4 filter_zone_wan_forward icmpv6 type { echo-request, echo-reply, destination-unreachable, packet-too-big, time-exceeded } limit rate 1000/second burst 5 packets accept
  116. add rule inet firewall4 filter_zone_wan_forward icmpv6 type parameter-problem icmpv6 code {0,1} limit rate 1000/second burst 5 packets accept
  117. add rule inet firewall4 filter_zone_wan_forward meta l4proto esp oifname @zone_lan_if accept
  118. add rule inet firewall4 filter_zone_wan_forward udp dport 500 oifname @zone_lan_if accept
  119. add rule inet firewall4 filter_zone_wan_forward tcp sport . tcp dport { 1234 . 5678 } oifname @zone_lan_if jump filter_reject_c
  120. add rule inet firewall4 filter_zone_wan_forward meta l4proto {tcp, udp} @th,16,16 9997 oifname @zone_lan_if drop
  121. add rule inet firewall4 filter_zone_wan_forward meta protocol ip ct status dnat accept
  122. add rule inet firewall4 filter_zone_wan_forward oifname @zone_wan_if jump filter_reject_c
  123.  
  124. #zone_wan_input
  125. add rule inet firewall4 filter_zone_wan_input jump filter_input_wan_rule
  126. add rule inet firewall4 filter_zone_wan_input meta protocol ip udp dport 68 accept
  127. add rule inet firewall4 filter_zone_wan_input ip6 saddr fc00::/6 udp dport 546 accept
  128. add rule inet firewall4 filter_zone_wan_input meta protocol ip meta l4proto igmp accept
  129. add rule inet firewall4 filter_zone_wan_input icmp type echo-request accept
  130. add rule inet firewall4 filter_zone_wan_input ip6 saddr fe80::/10 icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-reduction } icmpv6 code 0 accept
  131. add rule inet firewall4 filter_zone_wan_forward icmpv6 type { echo-request, echo-reply, destination-unreachable, packet-too-big, time-exceeded, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } limit rate 1000/second burst 5 packets accept
  132. add rule inet firewall4 filter_zone_wan_forward icmpv6 type parameter-problem icmpv6 code {0,1} limit rate 1000/second burst 5 packets accept
  133. add rule inet firewall4 filter_zone_wan_input meta protocol ip ct status dnat accept
  134. add rule inet firewall4 filter_zone_wan_input iifname @zone_wan_if drop
  135.  
  136. ## Firewall configuration
  137. config defaults
  138. option syn_flood 1
  139. option input ACCEPT
  140. option output ACCEPT
  141. option forward REJECT
  142. # Uncomment this line to disable ipv6 rules
  143. # option disable_ipv6 1
  144.  
  145. config zone
  146. option name lan
  147. list network 'lan'
  148. list network 'lan2'
  149. option input ACCEPT
  150. option output ACCEPT
  151. option forward ACCEPT
  152.  
  153. config zone
  154. option name wan
  155. list network 'wan'
  156. list network 'wan6'
  157. list network 'wan2'
  158. option input DROP
  159. option output ACCEPT
  160. option forward REJECT
  161. option masq 1
  162. option mtu_fix 1
  163.  
  164. config forwarding
  165. option src lan
  166. option dest wan
  167.  
  168. # We need to accept udp packets on port 68,
  169. # see https://dev.openwrt.org/ticket/4108
  170. config rule
  171. option name Allow-DHCP-Renew
  172. option src wan
  173. option proto udp
  174. option dest_port 68
  175. option target ACCEPT
  176. option family ipv4
  177.  
  178. # Allow IPv4 ping
  179. config rule
  180. option name Allow-Ping
  181. option src wan
  182. option proto icmp
  183. option icmp_type echo-request
  184. option family ipv4
  185. option target ACCEPT
  186.  
  187. config rule
  188. option name Allow-IGMP
  189. option src wan
  190. option proto igmp
  191. option family ipv4
  192. option target ACCEPT
  193.  
  194. # Allow DHCPv6 replies
  195. # see https://dev.openwrt.org/ticket/10381
  196. config rule
  197. option name Allow-DHCPv6
  198. option src wan
  199. option proto udp
  200. option src_ip fc00::/6
  201. option dest_ip fc00::/6
  202. option dest_port 546
  203. option family ipv6
  204. option target ACCEPT
  205.  
  206. config rule
  207. option name Allow-MLD
  208. option src wan
  209. option proto icmp
  210. option src_ip fe80::/10
  211. list icmp_type '130/0'
  212. list icmp_type '131/0'
  213. list icmp_type '132/0'
  214. list icmp_type '143/0'
  215. option family ipv6
  216. option target ACCEPT
  217.  
  218. # Allow essential incoming IPv6 ICMP traffic
  219. config rule
  220. option name Allow-ICMPv6-Input
  221. option src wan
  222. option proto icmp
  223. list icmp_type echo-request
  224. list icmp_type echo-reply
  225. list icmp_type destination-unreachable
  226. list icmp_type packet-too-big
  227. list icmp_type time-exceeded
  228. list icmp_type bad-header
  229. list icmp_type unknown-header-type
  230. list icmp_type router-solicitation
  231. list icmp_type neighbour-solicitation
  232. list icmp_type router-advertisement
  233. list icmp_type neighbour-advertisement
  234. option limit 1000/sec
  235. option family ipv6
  236. option target ACCEPT
  237.  
  238. # Allow essential forwarded IPv6 ICMP traffic
  239. config rule
  240. option name Allow-ICMPv6-Forward
  241. option src wan
  242. option dest *
  243. option proto icmp
  244. list icmp_type echo-request
  245. list icmp_type echo-reply
  246. list icmp_type destination-unreachable
  247. list icmp_type packet-too-big
  248. list icmp_type time-exceeded
  249. list icmp_type bad-header
  250. list icmp_type unknown-header-type
  251. option limit 1000/sec
  252. option family ipv6
  253. option target ACCEPT
  254.  
  255. config rule
  256. option name Allow-IPSec-ESP
  257. option src wan
  258. option dest lan
  259. option proto esp
  260. option target ACCEPT
  261.  
  262. config rule
  263. option name Allow-ISAKMP
  264. option src wan
  265. option dest lan
  266. option dest_port 500
  267. option proto udp
  268. option target ACCEPT
  269.  
  270. config rule
  271. option name test-1
  272. option src wan
  273. option dest lan
  274. option src_port 1234
  275. option dest_port 5678
  276. option proto tcp
  277. option target REJECT
  278.  
  279. config rule
  280. option name test-2
  281. option src wan
  282. option dest lan
  283. option dest_port 9997
  284. option proto 'tcpudp'
  285. option target DROP
  286.  
  287. # include a file with users custom iptables rules
  288. config include
  289. option path /etc/firewall.user
  290.  
  291. ## Network configuration
  292. config interface 'loopback'
  293. option ifname 'lo'
  294. option proto 'static'
  295. option ipaddr '127.0.0.1'
  296. option netmask '255.0.0.0'
  297.  
  298. config globals 'globals'
  299. option ula_prefix 'fdc2:5b52:f3c6::/48'
  300.  
  301. config interface 'lan'
  302. option ifname 'eth2'
  303. option proto 'static'
  304. option ipaddr '192.168.1.1'
  305. option netmask '255.255.255.0'
  306. option ip6assign '60'
  307.  
  308. config interface 'lan2'
  309. option ifname 'eth2.245'
  310. option proto 'static'
  311. option ipaddr '192.168.2.1'
  312. option netmask '255.255.255.0'
  313.  
  314. config interface 'wan'
  315. option ifname 'eth0'
  316. option proto 'dhcp'
  317. option ip4table '1000'
  318.  
  319. config interface 'wan2'
  320. option ifname 'eth1'
  321. option proto 'dhcp'
  322. option ip4table '1001'
  323.  
  324. config interface 'wan6'
  325. option ifname 'eth0'
  326. option proto 'dhcpv6'
Advertisement
Add Comment
Please, Sign In to add comment