以前設定していた国内(日本のIP)からのみ許可するsetの作成、VPN通信のTCP SynのMSSサイズを変更する設定も行っています。
nftablesの設定ファイル指定
以下で設定ファイルを指定します。vi /etc/sysconfig/nftables.conf
/etc配下のinet-filter.nftだけを使用するので、以下のコメントアウトを削除します。
# include "/etc/nftables/inet-filter.nft" ↓ include "/etc/nftables/inet-filter.nft"
nftablesの起動
systemctl start nftables
日本のIPリスト作成
日本のIPレンジの取得から設定までをスクリプトで実施します。このスクリプトは、IPレンジを更新する際にも使用することを想定しています。
vi nft_AcceptCountry.sh
#!/bin/sh # IPアドレスリスト作成 IP_LIST=/tmp/cidr.txt if [ ! -f $IP_LIST ]; then wget -q http://nami.jp/ipv4bycc/cidr.txt.gz gunzip -c cidr.txt.gz > $IP_LIST rm -f cidr.txt.gz fi # 既存Accept_Countryをflush nft flush set inet filter Accept_Country # 新規Accept_Countryを作成 nft add set inet filter Accept_Country { type ipv4_addr \; flags interval \; } # /tmp/cidr.txtのJPのアドレスをAccept_Countryに追加 for addr in `cat /tmp/cidr.txt|grep ^JP | awk '{print $2}'` do nft add element inet filter Accept_Country { $addr } done # 設定を保存 nft list ruleset > /etc/nftables/inet-filter.nft
sh nft_AcceptCountry.sh初回は、Accept_Countryのsetが無いため、エラーとなります。
また、全IPレンジを一行ずつ入力するため、少々時間が掛かります。
もっと良いやり方があるかもしれません。
スクリプトは以下のサイトを参考にさせて頂きました。
https://centossrv.com/iptables.shtml
各ルールの設定
input policy
inputにルールを入れていきます。1行目はサーバ自身のループバック通信の許可。
2行目はローカルネットワークの許可。我が家ではローカルのネットワークとVPNのネットワークをまとめて指定しました。
3行目、4行目は外部に公開しているサービスです。(ポート番号指定でも可)
前項で作成した日本のIPリスト(Accept_Country)からのみ許可します。
5行目は、セッションを張ったTCP通信の許可、
6行目は、DHCPの許可(DHCP DiscoverのソースIPが0.0.0.0であるため)、
7行目は、IPv6で使用するプロトコルを許可します。これが無いとログが沢山でます。
8行目は、拒否した通信のカウンターとログ吐き出しをしています。
nft add rule inet filter input iifname lo accept nft add rule inet filter input ip saddr 192.168.0.0/16 accept nft add rule inet filter input ip saddr @Accept_Country udp dport { isakmp, ipsec-nat-t } accept nft add rule inet filter input ip saddr @Accept_Country tcp dport https accept nft add rule inet filter input ct state established,related accept nft add rule inet filter input udp sport { bootps, bootpc } udp dport { bootps, bootpc } accept nft add rule inet filter input icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept nft add rule inet filter input counter log prefix \"[nftables INPUT DROP] : \"
最後に、input policyのデフォルトをDropに変更します。
ローカルネットワークを指定していないと、SSHが切断され、入れなくなるため注意しましょう。
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
VPN用 policy
strongSwan等のVPNをしている人専用です。VPN内を通るTCP synのmss値を適切な値に書き換えます。
以前の記事ではIPTABLESでしたので、IPsecを通ってきた or 通っていく通信を判断できたようですが、nftablesでは出来なさそうなので、次のようにしています。
1行目と3行目は、チェインの作成。
2行目は、VPNのIP範囲から来る通信のMSS値の書き換え、
4行目は、VPNのIP範囲への通信のMSS値の書き換えです。
nft add chain inet filter prerouting { type filter hook prerouting priority 0 \; } nft add rule inet filter prerouting ip saddr 192.168.255.0/24 tcp flags syn tcp option maxseg size set 1334 nft add chain inet filter postrouting { type filter hook postrouting priority 0 \; } nft add rule inet filter postrouting ip daddr 192.168.255.0/24 tcp flags syn tcp option maxseg size set 1334また、IPTABLESでは元々のMSS値のマッチングもできましたが、nftablesでは出来なさそうです。
ですが、元々のMSSが、設定するMSSより小さい場合は書き換わらなかったため、動作としては問題ないと思います。
最適MTU/MSSの計算はこちらのページで。
IPsecパケットのフォーマットと最適MTUの計算方法をまとめ、計算機を作成しました。最適MTUを設定することでVPNが快適になるかもしれません。
設定の確認
以下のコマンドで設定を表示します。nft list ruleset前項を設定すると以下のようになるはずです。
table inet filter { set Accept_Country { type ipv4_addr flags interval elements = { 1.0.16.0/20, 1.0.64.0/18, (略) 223.252.64.0/19, 223.252.112.0/20 } } chain input { type filter hook input priority 0; policy drop; iifname "lo" accept ip saddr 192.168.0.0/16 accept ip saddr @Accept_Country udp dport { isakmp, ipsec-nat-t } accept ip saddr @Accept_Country tcp dport https accept ct state established,related accept udp sport { bootps, bootpc } udp dport { bootps, bootpc } accept icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept counter packets 5 bytes 248 log prefix "[nftables INPUT DROP] : " } chain forward { type filter hook forward priority 0; policy accept; } chain output { type filter hook output priority 0; policy accept; } chain prerouting { type filter hook prerouting priority 0; policy accept; ip saddr 192.168.255.0/24 tcp flags syn tcp option maxseg size set 1334 } chain postrouting { type filter hook postrouting priority 0; policy accept; ip daddr 192.168.255.0/24 tcp flags syn tcp option maxseg size set 1334 } }
問題なければ、設定を保存します。
nft list ruleset > /etc/nftables/inet-filter.nft
一部のテーブルのみを指定する場合は以下の通りです。
nft list table inet filter > /etc/nftables/inet-filter.nft
個人的な感想
なんとかやりたいことが設定できました。他にもセキュリティ関連の設定ができますが、日本からのトラフィックのみを許可ができたので、まずは良いかと思っています。
nftablesは、IPTABLESよりネットワークエンジニアが理解しやすい構文だと感じました。
nft -iで設定することもできますが、tab補完や構文の候補が見られると使いやすくなるのですが。
追記
ルールの追加 ESP
我が家のVPNは、UDPではなくESPが飛んでくることもあるため、ルールを追加しました。ルールを途中に挿入するには、挿入したい行の直前のhandle番号を調べ、その番号をコマンドに入れます。
handle番号は以下で確認ができます。
nft list ruleset --handle または nft --handle list ruleset
table inet filter {
(略)
chain input {
type filter hook input priority 0; policy drop;
iifname "lo" accept # handle 11
ip saddr 192.168.0.0/16 accept # handle 12
ip saddr @Accept_Country udp dport { isakmp, ipsec-nat-t } accept # handle 13
ip saddr @Accept_Country tcp dport https accept # handle 14
ct state established,related accept # handle 15
udp sport { bootps, bootpc } udp dport { bootps, bootpc } accept # handle 16
icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept # handle 17
counter packets 907 bytes 42202 log prefix "[nftables INPUT DROP] : " # handle 18
}
(略)
}
送信元IPが日本で、ESPを許可するルールを挿入します。
nft add rule inet filter input handle 15 ip saddr @Accept_Country ip protocol esp accept
nft list ruleset
table inet filter {
(略)
chain input {
type filter hook input priority 0; policy drop;
iifname "lo" accept
ip saddr 192.168.0.0/16 accept
ip saddr @Accept_Country udp dport { isakmp, ipsec-nat-t } accept
ip saddr @Accept_Country tcp dport https accept
ct state established,related accept
ip saddr @Accept_Country ip protocol esp accept
udp sport { bootps, bootpc } udp dport { bootps, bootpc } accept
icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept
counter packets 908 bytes 42242 log prefix "[nftables INPUT DROP] : "
}
(略)
}
指定した番号の直後に挿入されました。
handle 15でなく、position 15 と指定すると直前に挿入となります。
ルールの追加 LLMNR
IPv6 UDP 5535 が沢山ログに出ていたため、追加しました。これはLLMNRというもので、Windowsで名前解決をする物のようです。
以下のコマンドで追加しました。
nft add rule inet filter input handle 18 udp dport 5355 accept
入れるとhostmonに変わります。
chain input { type filter hook input priority 0; policy drop; iifname "lo" accept ip saddr 192.168.0.0/16 accept ip saddr @Accept_Country udp dport { isakmp, ipsec-nat-t } accept ip saddr @Accept_Country tcp dport https accept ct state established,related accept ip saddr @Accept_Country ip protocol esp accept udp sport { bootps, bootpc } udp dport { bootps, bootpc } accept icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept udp dport hostmon accept counter packets 4307 bytes 198793 log prefix "[nftables INPUT DROP] : " }
ルールの変更 IPv6周り
IPv6 LLMNR を許可したら今度は、IPv6 TCP 445 が出てくるようになりました。これはWindowsファイル共有の通信で、最初にリンクローカルアドレスで開始し、失敗するとグローバルアドレスでアクセスしようとします。
そのため、リンクローカルアドレスをすべて許可することにました。
LLMNR のルールは、このルールで賄えるため、不要になりました。
順番なども整理し、以下となりました。
chain input { type filter hook input priority 0; policy drop; iifname "lo" accept ct state established,related accept ip saddr 192.168.0.0/16 accept ip6 saddr fe80::/10 accept ip saddr @Accept_Country udp dport { isakmp, ipsec-nat-t } accept ip saddr @Accept_Country tcp dport https accept ip saddr @Accept_Country ip protocol esp accept udp sport { bootps, bootpc } udp dport { bootps, bootpc } accept icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept counter packets 6039 bytes 278960 log prefix "[nftables INPUT DROP] : " }SAMBAにIPv6を許可する場合は、smb.conf内にリンクローカルの追加が必要です。
hosts allow = 127.0.0.1 192.168. fe80::/10
ルールの追加 DSCP値書き換え
サーバから送信される特定のポート番号のDSCP値を書き換えます。この例では、送信元のTCPポート50000をDSCP 48(cs6)にしています。
nft add rule inet filter postrouting tcp sport 50000 ip dscp set cs6
chain postrouting { type filter hook postrouting priority filter; policy accept; ip daddr 192.168.255.0/24 tcp flags syn tcp option maxseg size set 1334 tcp sport 58118 ip dscp set cs6 }