nftables.conf.tmpl 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #!/usr/sbin/nft -f
  2. #
  3. # /etc/nftables.conf - FFHO packet filter configuration
  4. #
  5. {%- set node_config = salt['pillar.get']('nodes:' ~ grains['id']) %}
  6. {%- set nf_cc = node_config.get ('nftables', {}) %}
  7. {%- set roles = node_config.get ('roles', []) %}
  8. {%- set services = node_config.get ('services', []) %}
  9. {%- set fw_policy = salt['pillar.get']('firewall:policy', {}) %}
  10. {%- set acls = salt['pillar.get']('firewall:acls') %}
  11. {%- set admin_access = salt['pillar.get']('firewall:admin_access') %}
  12. {%- set ssh = salt['pillar.get']("firewall:ssh") %}
  13. {%- set icinga2_queriers = salt['pillar.get']('monitoring:icinga2:queriers', []) %}
  14. {%- set nms_list = salt['pillar.get']('globals:snmp:nms_list', []) %}
  15. {%- set forward = salt['ffho_netfilter.generate_forward_policy'](fw_policy, roles, nf_cc) %}
  16. {%- set nat_policy = salt['ffho_netfilter.generate_nat_policy'](roles, nf_cc) %}
  17. {%- set urpf = salt['ffho_netfilter.generate_urpf_policy'](node_config['ifaces']) %}
  18. {%- set allow_dhcp = salt['ffho_netfilter.allow_dhcp'](fw_policy, roles) %}
  19. flush ruleset
  20. table ip filter {
  21. set ibgp-peers {
  22. type ipv4_addr
  23. elements = {
  24. 10.132.255.1, # cr01.in.ffho.net
  25. 10.132.255.2, # cr02.in.ffho.net
  26. 10.132.255.3, # cr03.in.ffho.net
  27. }
  28. }
  29. chain input {
  30. type filter hook input priority 0; policy drop;
  31. iifname "lo" counter accept
  32. udp dport 0 counter drop
  33. tcp dport 7 counter drop comment "Ignore echo protocol queries"
  34. udp dport 4789 jump vxlan
  35. jump urpf
  36. ip protocol icmp counter jump icmp_chain
  37. ct state invalid counter drop
  38. counter jump admin_access
  39. counter jump monitoring
  40. tcp dport 22 counter jump ssh
  41. {%- if 'router' in roles %}
  42. ip daddr { 224.0.0.5, 224.0.0.6 } meta l4proto ospf accept
  43. tcp dport 179 counter jump bgp
  44. {%- endif %}
  45. ct state related,established counter accept
  46. counter jump services
  47. meta pkttype broadcast counter drop comment "Drop broadcasts before logging"
  48. limit rate 1/second burst 3 packets counter log prefix "nf input: "
  49. limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
  50. counter drop
  51. }
  52. chain forward {
  53. type filter hook forward priority 0; policy {{ forward['policy'] }}; # {{ forward['policy_reason'] }}
  54. jump urpf
  55. {#- custom rules #}
  56. {%- for rule in forward['rules'].get ('4', []) %}
  57. {{ rule }}
  58. {%- endfor %}
  59. {%- if forward['policy'] == 'drop' %}
  60. limit rate 1/second burst 3 packets counter log prefix "nf forward: "
  61. limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
  62. {%- endif %}
  63. }
  64. chain icmp_chain {
  65. icmp type { echo-request, destination-unreachable, time-exceeded } counter accept
  66. }
  67. chain admin_access {
  68. {%- for pfx in admin_access[4].keys()|sort %}
  69. {%- set comment = admin_access[4][pfx] %}
  70. ip saddr {{ pfx }} counter accept comment "{{ comment }}"
  71. {%- endfor %}
  72. }
  73. {%- if 'router' in roles %}
  74. chain bgp {
  75. ip saddr @ibgp-peers counter accept comment "iBGP peers"
  76. # TODO: Add external BGP peers, if any
  77. }
  78. {%- endif %}
  79. chain monitoring {
  80. {%- for ip in icinga2_queriers if not ":" in ip %}
  81. ip saddr {{ ip }} counter accept comment "Icinga2"
  82. {%- endfor %}
  83. {%- for ip in nms_list if not ":" in ip %}
  84. ip saddr {{ ip }} udp dport 161 counter accept comment "NMS"
  85. {%- endfor %}
  86. }
  87. chain ssh {
  88. {%- for pfx in ssh[4].keys()|sort %}
  89. {%- set comment = ssh[4][pfx] %}
  90. ip saddr {{ pfx }} counter accept comment "{{ comment }}"
  91. {%- endfor %}
  92. }
  93. chain services {
  94. {%- if allow_dhcp %}
  95. udp dport 67 counter accept comment "DHCP"
  96. {%- endif %}
  97. {%- for rule in salt['ffho_netfilter.generate_service_rules'](services, acls, 4) %}
  98. {{ rule }}
  99. {%- endfor %}
  100. }
  101. chain urpf {
  102. {%- for iface_cfg in urpf %}
  103. {%- for pfx in iface_cfg[4] %}
  104. iif {{ iface_cfg['iface'] }} ip saddr {{ pfx }} return
  105. {%- endfor %}
  106. iif {{ iface_cfg['iface'] }} counter drop
  107. {%- endfor %}
  108. }
  109. chain vxlan {
  110. {%- for iface in node_config['ifaces'] if node_config['ifaces'][iface].get ('batman_connect_sites') %}
  111. iif {{ iface }} accept
  112. {%- endfor %}
  113. counter drop
  114. }
  115. chain log-drop {
  116. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  117. counter drop
  118. }
  119. chain log-reject {
  120. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  121. limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
  122. counter drop
  123. }
  124. }
  125. table ip6 filter {
  126. set ibgp-peers {
  127. type ipv6_addr
  128. elements = {
  129. 2a03:2260:2342:ffff::1, # cr01.in.ffho.net
  130. 2a03:2260:2342:ffff::2, # cr02.in.ffho.net
  131. 2a03:2260:2342:ffff::3, # cr03.in.ffho.net
  132. }
  133. }
  134. chain input {
  135. type filter hook input priority 0; policy drop;
  136. iifname "lo" counter accept
  137. tcp dport 7 counter drop comment "Ignore echo protocol queries"
  138. udp dport 4789 jump vxlan
  139. jump urpf
  140. meta l4proto icmpv6 counter jump icmp_chain
  141. ct state invalid counter drop
  142. counter jump admin_access
  143. counter jump monitoring
  144. tcp dport 22 counter jump ssh
  145. {%- if 'router' in roles %}
  146. ip6 saddr fe80::/64 ip6 daddr { fe80::/10, ff02::5, ff02::6 } meta l4proto ospf accept
  147. tcp dport 179 counter jump bgp
  148. {%- endif %}
  149. ct state related,established counter accept comment "Allow established connections."
  150. counter jump services
  151. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  152. limit rate 1/second burst 3 packets counter reject with icmpv6 type admin-prohibited
  153. counter drop
  154. }
  155. chain forward {
  156. type filter hook forward priority 0; policy {{ forward['policy'] }}; # {{ forward['policy_reason'] }}
  157. jump urpf
  158. {#- custom rules #}
  159. {%- for rule in forward['rules'].get ('6', []) %}
  160. {{ rule }}
  161. {%- endfor %}
  162. {%- if forward['policy'] == 'drop' %}
  163. limit rate 1/second burst 3 packets counter log prefix "nf forward: "
  164. limit rate 1/second burst 3 packets counter reject with icmp type admin-prohibited
  165. {%- endif %}
  166. }
  167. chain icmp_chain {
  168. icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, echo-reply } counter accept
  169. icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert } ip6 hoplimit 255 counter accept
  170. icmpv6 type { mld-listener-query, mld-listener-report } ip6 saddr fe80::/64 counter accept
  171. }
  172. chain admin_access {
  173. {%- for pfx in admin_access[6].keys()|sort %}
  174. {%- set comment = admin_access[6][pfx] %}
  175. ip6 saddr {{ pfx }} counter accept comment "{{ comment }}"
  176. {%- endfor %}
  177. }
  178. {%- if 'router' in roles %}
  179. chain bgp {
  180. ip6 saddr @ibgp-peers counter accept comment "iBGP peers"
  181. # TODO: Add external BGP peers, if any
  182. }
  183. {%- endif %}
  184. chain monitoring {
  185. {%- for ip in icinga2_queriers if ":" in ip %}
  186. ip6 saddr {{ ip }} counter accept comment "Icinga2"
  187. {%- endfor %}
  188. {%- for ip in nms_list if ":" in ip %}
  189. ip6 saddr {{ ip }} udp dport 161 counter accept comment "NMS"
  190. {%- endfor %}
  191. }
  192. chain ssh {
  193. {%- for pfx in ssh[6].keys()|sort %}
  194. {%- set comment = ssh[6][pfx] %}
  195. ip6 saddr {{ pfx }} counter accept comment "{{ comment }}"
  196. {%- endfor %}
  197. }
  198. chain services {
  199. {%- for rule in salt['ffho_netfilter.generate_service_rules'](services, acls, 6) %}
  200. {{ rule }}
  201. {%- endfor %}
  202. {#- Allow respondd queries on gateways #}
  203. {%- if 'batman_gw' in roles %}
  204. ip6 saddr fe80::/64 ip6 daddr ff05::2:1001 udp dport 1001 counter accept comment "responnd"
  205. {%- endif %}
  206. }
  207. chain urpf {
  208. ip6 saddr fe80::/64 return
  209. {%- for iface_cfg in urpf %}
  210. {%- for pfx in iface_cfg[6] %}
  211. iif {{ iface_cfg['iface'] }} ip6 saddr {{ pfx }} return
  212. {%- endfor %}
  213. iif {{ iface_cfg['iface'] }} counter drop
  214. {%- endfor %}
  215. }
  216. chain vxlan {
  217. {%- for iface in node_config['ifaces'] if node_config['ifaces'][iface].get ('batman_connect_sites') %}
  218. iif {{ iface }} accept
  219. {%- endfor %}
  220. counter drop
  221. }
  222. chain log-drop {
  223. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  224. counter drop
  225. }
  226. chain log-reject {
  227. limit rate 1/second burst 3 packets counter log prefix "netfilter: "
  228. limit rate 1/second burst 3 packets counter reject with icmpv6 type admin-prohibited
  229. counter drop
  230. }
  231. }
  232. {#-
  233. # NAT
  234. #}
  235. {%- for af in [ 4, 6 ] %}
  236. {%- if nat_policy[af] %}
  237. {%- set af_name = "ip" if af == 4 else "ip6" %}
  238. table {{ af_name }} nat {
  239. {%- for chain in ['output', 'prerouting', 'postrouting'] if chain in nat_policy[af] %}
  240. chain {{ chain }} {
  241. type nat hook {{ chain }} priority 0; policy accept;
  242. {%- for rule in nat_policy[af][chain] %}
  243. {{ rule }}
  244. {%- endfor %}
  245. }
  246. {%- endfor %}
  247. }
  248. {%- endif %}
  249. {%- endfor %}