Так лучше? :)Я, если честно, думал что возникнет вопрос, прежде всего, про iif daddr/oif saddr пары в правилах input/output для loopback. Но мне это не кажется избыточным.
#!/usr/bin/env -S bash -c 'nft -cof "${0}" && nft -f "${0}"'
flush ruleset
table inet filter {
define sshd_port = 2299;
set ssh_bad_ipv4_set {
type ipv4_addr;
flags dynamic;
timeout 15m;
}
set ssh_bad_ipv6_set {
type ipv6_addr;
flags dynamic;
timeout 15m;
}
set ssh_clients_ipv4_set {
type ipv4_addr;
flags dynamic;
timeout 3s;
}
set ssh_clients_ipv6_set {
type ipv6_addr;
flags dynamic;
timeout 3s;
}
set ssh_clients_candidates_ipv4_set {
type ipv4_addr . inet_service;
flags dynamic;
timeout 1s;
}
set ssh_clients_candidates_ipv6_set {
type ipv6_addr . inet_service;
flags dynamic;
timeout 1s;
}
### printf %d\\n 0x$(openssl rand -hex 2)
define ssh_port_knock_1 = changeme1;
define ssh_port_knock_2 = changeme2;
define ssh_port_knock_3 = changeme3;
define ssh_port_knock_4 = changeme4;
### opened ports
set serving_tcp_ports_set {
type inet_service;
flags constant;
# elements = {
# http,
# https,
# };
}
set trusted_ipv4_set {
type ipv4_addr;
flags constant, interval;
elements = {
169.254.169.254,
10.0.0.0/8,
192.168.0.0/16,
};
}
set trusted_ipv6_set {
type ipv6_addr;
flags constant, interval;
elements = {
fd00:ec2::254,
};
}
define dns_resolvers = {
0.0.0.0/0,
}
define allowed_icmp_types_input = {
echo-reply,
echo-request,
destination-unreachable,
}
define allowed_icmp_types_output = {
echo-reply,
echo-request,
destination-unreachable,
}
### rfc4890; assist mobility candidate codes: 144, 145, 146, 147
define allowed_icmpv6_types_input = {
echo-reply,
echo-request,
destination-unreachable,
packet-too-big,
time-exceeded,
parameter-problem,
nd-router-solicit,
nd-router-advert,
nd-neighbor-solicit,
nd-neighbor-advert,
ind-neighbor-solicit,
ind-neighbor-advert,
mld-listener-query,
mld-listener-report,
mld-listener-done,
mld2-listener-report,
}
### rfc4890; assist mobility candidate codes: 144, 145, 146, 147
define allowed_icmpv6_types_output = {
echo-reply,
echo-request,
destination-unreachable,
packet-too-big,
time-exceeded,
parameter-problem,
nd-router-solicit,
nd-router-advert,
nd-neighbor-solicit,
nd-neighbor-advert,
ind-neighbor-solicit,
ind-neighbor-advert,
mld-listener-query,
mld-listener-report,
mld-listener-done,
mld2-listener-report,
}
chain INPUT {
type filter hook input priority filter + 20; policy drop;
iif lo accept comment "accept input connections via loopback";
iif != lo ip saddr 127.0.0.0/8 counter drop comment "drop loopback connections not coming from loopback";
iif != lo ip daddr 127.0.0.0/8 counter drop comment "drop loopback connections not coming from loopback";
iif != lo ip6 saddr ::1/128 counter drop comment "drop loopback connections not coming from loopback";
iif != lo ip6 daddr ::1/128 counter drop comment "drop loopback connections not coming from loopback";
### as little rules as possible for trusted hosts
ip saddr @trusted_ipv4_set accept comment "accept trusted hosts";
ip6 saddr @trusted_ipv6_set accept comment "accept trusted hosts";
### before ct
meta l4proto icmp icmp type $allowed_icmp_types_input limit rate 10/second burst 20 packets counter accept comment "accept icmp with limits";
meta l4proto icmpv6 icmpv6 type $allowed_icmpv6_types_input limit rate 10/second burst 20 packets counter accept comment "accept icmpv6 with limits";
meta l4proto { icmp, icmpv6 } counter drop comment "drop icmp over limit";
ct state vmap { established : accept, related : accept, invalid : drop };
tcp dport @serving_tcp_ports_set ct state new counter accept comment "accept connections to serving tcp ports";
### port knocking
#tcp dport $ssh_port_knock_1 add @ssh_clients_candidates_ipv4_set { ip saddr . $ssh_port_knock_2 };
#tcp dport $ssh_port_knock_1 add @ssh_clients_candidates_ipv6_set { ip6 saddr . $ssh_port_knock_2 };
#tcp dport $ssh_port_knock_2 ip saddr . tcp dport @ssh_clients_candidates_ipv4_set add @ssh_clients_candidates_ipv4_set { ip saddr . $ssh_port_knock_3 };
#tcp dport $ssh_port_knock_2 ip6 saddr . tcp dport @ssh_clients_candidates_ipv6_set add @ssh_clients_candidates_ipv6_set { ip6 saddr . $ssh_port_knock_3 };
#tcp dport $ssh_port_knock_3 ip saddr . tcp dport @ssh_clients_candidates_ipv4_set add @ssh_clients_candidates_ipv4_set { ip saddr . $ssh_port_knock_4 };
#tcp dport $ssh_port_knock_3 ip6 saddr . tcp dport @ssh_clients_candidates_ipv6_set add @ssh_clients_candidates_ipv6_set { ip6 saddr . $ssh_port_knock_4 };
#tcp dport $ssh_port_knock_4 ip saddr . tcp dport @ssh_clients_candidates_ipv4_set add @ssh_clients_ipv4_set { ip saddr } counter log prefix "ssh port knocked : ";
#tcp dport $ssh_port_knock_4 ip6 saddr . tcp dport @ssh_clients_candidates_ipv6_set add @ssh_clients_ipv6_set { ip6 saddr } counter log prefix "ssh port knocked : ";
#tcp dport $sshd_port ip saddr @ssh_clients_ipv4_set counter accept;
#tcp dport $sshd_port ip6 saddr @ssh_clients_ipv6_set counter accept;
### rate limits
tcp dport $sshd_port ct state new, untracked meter ssh_conns_ratemeter4 { ip saddr timeout 5m limit rate over 1/minute burst 7 packets } counter update @ssh_bad_ipv4_set { ip saddr } comment "update ssh bruteforce set with saddr of attacker; hint: nft list meter inet filter ssh_conns_ratemeter4";
tcp dport $sshd_port ct state new, untracked meter ssh_conns_ratemeter6 { ip6 saddr timeout 5m limit rate over 1/minute burst 7 packets } counter update @ssh_bad_ipv6_set { ip6 saddr } comment "update ssh bruteforce set with saddr of attacker; hint: nft list meter inet filter ssh_conns_ratemeter6";
tcp dport $sshd_port ip saddr @ssh_bad_ipv4_set counter drop comment "drop ssh bruteforce; hint: nft list set inet filter ssh_bad_ipv4_set";
tcp dport $sshd_port ip6 saddr @ssh_bad_ipv6_set counter drop comment "drop ssh bruteforce; hint: nft list set inet filter ssh_bad_ipv6_set";
tcp dport $sshd_port counter accept comment "accept ssh connections";
### new rules place here:
counter comment "count dropped packets";
#log prefix "nft drop IN : " comment "log dropped packets";
}
chain OUTPUT {
type filter hook output priority filter + 20; policy drop;
oif lo accept comment "accept input connections via loopback";
oif != lo ip saddr 127.0.0.0/8 counter drop comment "drop loopback connections not coming to loopback";
oif != lo ip daddr 127.0.0.0/8 counter drop comment "drop loopback connections not coming to loopback";
oif != lo ip6 saddr ::1/128 counter drop comment "drop loopback connections not coming to loopback";
oif != lo ip6 daddr ::1/128 counter drop comment "drop loopback connections not coming to loopback";
### as little rules as possible for trusted hosts
ip daddr @trusted_ipv4_set accept comment "accept trusted hosts";
ip6 daddr @trusted_ipv6_set accept comment "accept trusted hosts";
### before ct
meta l4proto icmp icmp type $allowed_icmp_types_output limit rate 10/second burst 20 packets counter accept comment "accept icmp with limits";
meta l4proto icmpv6 icmpv6 type $allowed_icmpv6_types_output limit rate 10/second burst 20 packets counter accept comment "accept icmpv6 with limits";
meta l4proto { icmp, icmpv6 } counter drop comment "drop icmp over limit";
ct state vmap { established : accept, related : accept, invalid : drop };
meta skuid { root, uadm, chrony } meta skgid { root, uadm, chrony } counter accept comment "accept connections from specified users";
meta skuid postfix meta skgid postfix tcp dport { smtp, smtps, submission } counter accept comment "accept connections from postfix user";
meta l4proto { tcp, udp } th dport 53 ip daddr $dns_resolvers counter accept comment "accept dns; for paranoia specify comma separated list of resolvers in $dns_resolvers";
### new rules place here:
counter comment "count dropped packets";
log prefix "nft drop OUT : " comment "log dropped packets";
}
chain FORWARD {
type filter hook forward priority filter + 20; policy drop;
log prefix "nft drop FWD : " comment "log dropped packets";
}
}