Initial import
authorAntonio Ospite <ao2@ao2.it>
Fri, 27 Apr 2018 08:59:42 +0000 (10:59 +0200)
committerAntonio Ospite <ao2@ao2.it>
Fri, 27 Apr 2018 14:10:01 +0000 (16:10 +0200)
Makefile [new file with mode: 0644]
iptables-workstation.sh [new file with mode: 0755]
lib/utils.sh [new file with mode: 0755]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..1c26fe1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+all:
+
+deploy-workstation:
+       command -v /usr/sbin/nft > /dev/null && sudo nft flush ruleset
+       sudo ./iptables-workstation.sh
+       sudo iptables-save > iptables
+       sudo ip6tables-save > ip6tables
diff --git a/iptables-workstation.sh b/iptables-workstation.sh
new file mode 100755 (executable)
index 0000000..a00aa51
--- /dev/null
@@ -0,0 +1,133 @@
+#!/bin/bash
+#
+# iptables ruleset for an End Node acting as a workstation in a LAN.
+#
+# Copyright (C) 2018  Antonio Ospite <ao2@ao2.it>
+# SPDX-License-Identifier: MIT
+#
+# Based on updateipt.sh by Phil Sutter:
+# https://developers.redhat.com/blog/2017/01/10/migrating-my-iptables-setup-to-nftables/
+
+set -e
+
+[ $UID -eq 0 ] || { echo "This script must be run as root" 1>&2; exit 1; }
+
+. lib/utils.sh
+
+COMMON_OPEN_PORTS=(
+# XMPP
+5222
+5269
+# Link-local XMPP, for backward compatibility, XEP-0174
+5298
+)
+
+TCP_OPEN_PORTS=(
+"${COMMON_OPEN_PORTS[@]}"
+)
+
+UDP_OPEN_PORTS=(
+"${COMMON_OPEN_PORTS[@]}"
+)
+
+flush_ruleset
+
+
+### Define a custom chain for packets in NEW state.
+
+ip46t -N in-new
+
+# Silently drop DHCPv4 Discover and Request packets from other clients.
+ipt -A in-new -s 0.0.0.0 -d 255.255.255.255 -p udp -m udp --sport bootpc --dport bootps -j DROP
+
+# Silently drop DHCPv6 from other clients.
+ip6t -A in-new -s fe80::/64 -d fe80::/64 -p udp -m udp --sport dhcpv6-client --dport dhcpv6-server -j DROP
+
+# mDNS (ZeroConf/Bonjour)
+ipt  -A in-new -d 224.0.0.251 -p udp -m udp --dport 5353 -j ACCEPT
+ip6t -A in-new -d ff02::fb    -p udp -m udp --dport 5353 -j ACCEPT
+
+# SSDP: https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol
+ipt  -A in-new -d 239.255.255.250 -p udp -m udp --dport 1900 -j ACCEPT
+ip6t -A in-new -d ff02::c         -p udp -m udp --dport 1900 -j ACCEPT
+ip6t -A in-new -d ff05::c         -p udp -m udp --dport 1900 -j ACCEPT
+ip6t -A in-new -d ff08::c         -p udp -m udp --dport 1900 -j ACCEPT
+ip6t -A in-new -d ff0e::c         -p udp -m udp --dport 1900 -j ACCEPT
+
+
+for port in "${TCP_OPEN_PORTS[@]}";
+do
+  ip46t -A in-new -p tcp -m tcp --dport "$port" --syn -j ACCEPT
+done
+
+for port in "${UDP_OPEN_PORTS[@]}";
+do
+  ip46t -A in-new -p udp -m udp --dport "$port" -j ACCEPT
+done
+
+
+### INPUT chain
+ip46t -P INPUT DROP
+
+# Allow all loopback traffic.
+ip46t -A INPUT -i lo -j ACCEPT
+
+# Allow ICMP traffic.
+ipt -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
+ipt -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
+ipt -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
+ipt -A INPUT -p icmp --icmp-type parameter-problem -j ACCEPT
+ipt -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
+
+# Allow ICMPv6 traffic
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type echo-reply -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type echo-request -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
+
+# Allow IPv6 Neighbor Discovery (RFC4861).
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
+
+# Allow multicast listener discovery on link-local addresses.
+# RFC2710 specifies that a Hop-by-Hop Options header is used.
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type 130 -s fe80::/10 -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type 131 -s fe80::/10 -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type 132 -s fe80::/10 -j ACCEPT
+
+# Allow multicast router discovery messages on link-local addresses (hop limit 1).
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type router-solicitation -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT
+ip6t -A INPUT -p ipv6-icmp --icmpv6-type router-advertisement -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT
+
+# Allow IGMPv3 queries.
+ipt -A INPUT -d 224.0.0.1 -p igmp -j DROP
+
+
+# Stateful filtering for anything else.
+ip46t -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
+ip46t -A INPUT -m state --state INVALID -j DROP
+ip46t -A INPUT -m state --state NEW -j in-new
+
+# Silently drop other incoming broadcast and multicast traffic.
+ip46t -A INPUT -m pkttype --pkt-type broadcast -j DROP
+ip46t -A INPUT -m pkttype --pkt-type multicast -j DROP
+
+ip46t -A INPUT -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[INPUT]: "
+ip46t -A INPUT -j REJECT
+
+
+### OUTPUT chain
+ip46t -P OUTPUT DROP
+
+ip46t -A OUTPUT -j ACCEPT
+
+
+### FORWARD chain
+ip46t -P FORWARD DROP
+
+ip46t -A FORWARD -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[FORWARD]: "
+ip46t -A FORWARD -j REJECT
diff --git a/lib/utils.sh b/lib/utils.sh
new file mode 100755 (executable)
index 0000000..4d45cdb
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Based on updateipt.sh by Phil Sutter:
+# https://developers.redhat.com/blog/2017/01/10/migrating-my-iptables-setup-to-nftables/
+
+# useful wrappers for failure analysis
+cmd_or_print() { # command
+  "$@" || echo "failed at: '$*'"
+}
+
+ipt() { # iptables params
+  cmd_or_print iptables "$@"
+}
+
+ip6t() { # ip6tables params
+  cmd_or_print ip6tables "$@"
+}
+
+# have a simple way of doing things in iptables and ip6tables in parallel
+ip46t() { # ip(6)tables params
+  ipt "$@"
+  ip6t "$@"
+}
+
+# clear out everything
+flush_ruleset() {
+  for it in iptables ip6tables; do
+    for table in filter mangle nat raw; do
+      $it -t $table -nL >/dev/null 2>&1 || continue # non-existing table
+
+      $it -t $table -F        # delete rules
+      $it -t $table -X        # delete custom chains
+      $it -t $table -Z        # zero counters
+    done
+  done
+}