diff --git a/group_vars/dch-gw/dch-network.yml b/group_vars/dch-gw/dch-network.yml index a5cab49..8e68f32 100644 --- a/group_vars/dch-gw/dch-network.yml +++ b/group_vars/dch-gw/dch-network.yml @@ -40,6 +40,11 @@ dch_networks: router_iface: vlan254 +firemon_networks: +- 192.168.0.0/16 +- 172.28.33.0/24 + + nat_port_forwards: - protocol: tcp port: http @@ -62,3 +67,33 @@ nat_port_forwards: - protocol: udp port: ipsec-nat-t destination: 172.31.0.2 + + +allow_incoming: +- protocol: udp + port: domain +- protocol: tcp + port: domain +- protocol: udp + port: bootps +- protocol: tcp + port: ssh + + +allow_outgoing: +- protocol: udp + port: ntp +- protocol: udp + port: dhcpv6-server +- protocol: udp + port: bootps +- protocol: tcp + port: https +- protocol: tcp + port: http +- protocol: udp + port: domain +- protocol: tcp + port: domain + +trace_dropped: true diff --git a/host_vars/gw0/network.yml b/host_vars/gw0/network.yml index d284d55..5905020 100644 --- a/host_vars/gw0/network.yml +++ b/host_vars/gw0/network.yml @@ -1,6 +1,8 @@ +internet_iface: enp4s0 + network: ignore_interfaces: - - enp4s0 + - '{{ internet_iface }}' interfaces: - ifname: enp1s0 enabled: true @@ -66,7 +68,7 @@ dhcpcd_ntp_servers: false dhcpcd_noipv4: true dhcpcd_noipv6rs: true dhcpcd_interfaces: -- name: enp4s0 +- name: '{{ internet_iface }}' description: Internet config: - ipv4 diff --git a/roles/dch-gw/defaults/main.yml b/roles/dch-gw/defaults/main.yml index af62751..9091f79 100644 --- a/roles/dch-gw/defaults/main.yml +++ b/roles/dch-gw/defaults/main.yml @@ -1 +1,3 @@ nat_port_forwards: [] +allow_incoming: [] +trace_dropped: false diff --git a/roles/dch-gw/files/inet-filter.nft b/roles/dch-gw/files/inet-filter.nft new file mode 100644 index 0000000..cb92eff --- /dev/null +++ b/roles/dch-gw/files/inet-filter.nft @@ -0,0 +1,7 @@ +#! /usr/sbin/nft -f + +table inet filter { + chain input { type filter hook input priority 0; } + chain forward { type filter hook forward priority 0; } + chain output { type filter hook output priority 0; } +} diff --git a/roles/dch-gw/tasks/main.yml b/roles/dch-gw/tasks/main.yml index 4a7cc22..aa8a0e5 100644 --- a/roles/dch-gw/tasks/main.yml +++ b/roles/dch-gw/tasks/main.yml @@ -31,6 +31,33 @@ sysctl_file=/etc/sysctl.d/ip-forwarding.conf state=present +- name: ensure inet filter rules are configured + copy: + src=inet-filter.nft + dest=/etc/nftables/ruleset.d/10_inet-filter.nft + mode=0644 + notify: reload nftables +- name: ensure basic rules are defined + template: + src={{ item }}.nft.j2 + dest=/etc/nftables/ruleset.d/20_{{ item }}.nft + mode=0644 + with_items: + - incoming + - forward + - outgoing + notify: reload nftables +- name: ensure final reject rules are defined + template: + src=reject.nft.j2 + dest=/etc/nftables/ruleset.d/90_{{ item }}-reject.nft + mode=0644 + with_items: + - input + - forward + - output + notify: reload nftables + - name: ensure ipv4 nat rules are configured copy: src=ipv4-nat.nft diff --git a/roles/dch-gw/templates/forward.nft.j2 b/roles/dch-gw/templates/forward.nft.j2 new file mode 100644 index 0000000..792864e --- /dev/null +++ b/roles/dch-gw/templates/forward.nft.j2 @@ -0,0 +1,23 @@ +{#- vim: set sw=4 ts=4 sts=4 et : #} +table inet filter { + set firemon { + type ipv4_addr + flags interval + elements = { +{% for prefix in firemon_networks %} + {{ prefix }}, +{% endfor %} + } + } + + chain forward { + ct state established,related accept + iifname {{ dch_networks.guest.router_iface }} oif != {{ internet_iface }} drop + iif != {{ internet_iface }} oifname {{ dch_networks.guest.router_iface }} drop + iif != {{ internet_iface }} oif != {{ internet_iface }} counter accept + ip daddr @firemon counter accept + mark 323 counter accept + tcp dport smtp counter reject with icmpx type host-unreachable + oif {{ internet_iface }} accept + } +} diff --git a/roles/dch-gw/templates/incoming.nft.j2 b/roles/dch-gw/templates/incoming.nft.j2 new file mode 100644 index 0000000..e175bdc --- /dev/null +++ b/roles/dch-gw/templates/incoming.nft.j2 @@ -0,0 +1,34 @@ +{#- vim: set sw=4 ts=4 sts=4 et : #} +table inet filter { + set allow_tcp_in { + type inet_service + flags interval + elements = { +{% for item in allow_incoming if item.protocol|d('tcp') == 'tcp' %} + {{ item.port }}, +{% endfor %} + } + } + + set allow_udp_in { + type inet_service + flags interval + elements = { +{% for item in allow_incoming if item.protocol|d('tcp') == 'udp' %} + {{ item.port }}, +{% endfor %} + } + } + + chain input { + ct state established,related accept + iif lo accept + ip6 nexthdr ipv6-icmp accept + ip protocol icmp accept + udp sport dhcpv6-server counter accept + iif != {{ internet_iface }} tcp dport @allow_tcp_in ct state new counter accept + iif != {{ internet_iface }} udp dport @allow_udp_in ct state new counter accept + iif {{ internet_iface }} drop + pkttype != host drop + } +} diff --git a/roles/dch-gw/templates/outgoing.nft.j2 b/roles/dch-gw/templates/outgoing.nft.j2 new file mode 100644 index 0000000..67c14fe --- /dev/null +++ b/roles/dch-gw/templates/outgoing.nft.j2 @@ -0,0 +1,31 @@ +{#- vim: set sw=4 ts=4 sts=4 et : #} +table inet filter { + set allow_tcp_out { + type inet_service + flags interval + elements = { +{% for item in allow_outgoing if item.protocol|d('tcp') == 'tcp' %} + {{ item.port }}, +{% endfor %} + } + } + + set allow_udp_out { + type inet_service + flags interval + elements = { +{% for item in allow_outgoing if item.protocol|d('tcp') == 'udp' %} + {{ item.port }}, +{% endfor %} + } + } + + chain output { + ct state established,related accept + oif lo accept + ip6 nexthdr ipv6-icmp accept + ip protocol icmp accept + tcp dport @allow_tcp_out ct state new counter accept + udp dport @allow_udp_out ct state new counter accept + } +} diff --git a/roles/dch-gw/templates/port-forwards.nft.j2 b/roles/dch-gw/templates/port-forwards.nft.j2 index 567a039..afc0ff3 100644 --- a/roles/dch-gw/templates/port-forwards.nft.j2 +++ b/roles/dch-gw/templates/port-forwards.nft.j2 @@ -33,13 +33,13 @@ table ip nat { } chain prerouting { - ip daddr $outside_address dnat tcp dport map @tcp_forward - ip daddr $outside_address dnat udp dport map @udp_forward + ip daddr $outside_address meta mark set 323 dnat tcp dport map @tcp_forward + ip daddr $outside_address meta mark set 323 dnat udp dport map @udp_forward } chain postrouting { {% for item in nat_port_forwards %} - ip saddr @inside_networks ip daddr {{ item.destination }} {{ item.protocol|d('tcp') }} dport {{ item.port }} masquerade + ip saddr @inside_networks ip daddr {{ item.destination }} {{ item.protocol|d('tcp') }} dport {{ item.port }} meta mark set 323 masquerade {% endfor %} } } diff --git a/roles/dch-gw/templates/reject.nft.j2 b/roles/dch-gw/templates/reject.nft.j2 new file mode 100644 index 0000000..dc730b8 --- /dev/null +++ b/roles/dch-gw/templates/reject.nft.j2 @@ -0,0 +1,6 @@ +{#- vim: set sw=4 ts=4 sts=4 et : #} +table inet filter { + chain {{ item }} { + {% if trace_dropped %}nftrace set 1 {% endif %}counter reject with icmpx type host-unreachable + } +}