macOSのpfでGlobalProtect用にNATを設定する

はじめに

macOS で GlobalProtect - Palo Alto Networks でVPNに接続した際に Multipass で作成したHypervisor.frameworkベースのVMとそのVM上のLXDコンテナからの通信をNATにする方法を調べたのでメモです。

Troubleshooting networking on macOS | Multipass documentation の “Potential workaround for VPN conflicts” に書いてありました。

GlobalProtect のネットワークインターフェース名を ifconfig で確認

GlobalProtect でVPNに接続した状態で、以下のコマンドを実行して GlobalProtect のネットワークインターフェース名を確認します。

ifconfig

私の環境では gpd0 でした。 また WiFi のインターフェース名は en0 で、 Hypervisor.framework のブリッジのインターフェース名は bridge100 でした。

pf.conf を編集して反映

man pf.conf すると pf.confpacket filter configuration file とのことです。 PF (firewall) - Wikipedia も参照。

/etc/pf.conf は変更前はコメントを除くと以下のようになっていました。

scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"

これを以下のコマンドを実行し

sudo vim /etc/pf.conf

以下のように編集しました。

scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
table <privbutvm> const { 10/8, 172.16/12, 192.168/16, !192.168.254/24, !192.168.255/24 }
table <myglobal> const { 0/0, !10/8, !172.16/12, !192.168/16 }
nat on gpd0 from bridge100:network to <privbutvm> -> (gpd0)
nat on en0 from bridge100:network to <myglobal> -> (en0)
rdr-anchor "com.apple/*"
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"

192.168.254/24192.168.255/24macOSでHypervisor.frameworkのVMのサブネットIPアドレスを変える · hnakamur’s blog に書いたようにVMとLXDコンテナーのネットワークです。これを除いたプライベートアドレスは GlobalProtect に、グローバルアドレスは WiFi に向けてそれぞれNATを設定しました。

以下のコマンドで反映します。

sudo pfctl -f /etc/pf.conf

実行すると以下のようなメッセージが出ました。

% sudo pfctl -f /etc/pf.conf
pfctl: Use of -f option, could result in flushing of rules
present in the main ruleset added by the system at startup.
See /etc/pf.conf for further details.
No ALTQ support in kernel
ALTQ related functions disabled

macOSでtcpdumpを実行しつつ VMやLXDコンテナから ping で動作確認

macOS 側で以下のように tcpdump を実行しておきます。 -k A を指定しておくとインターフェース名も出力されるので便利です。

sudo tcpdump -n -k A -vvv -i any icmp

対象のインターフェースを限定したいが複数指定したい場合は man tcpdump に書いてある pktap を使ってこの後に複数のインターフェースを指定できます。

sudo tcpdump -n -k A -vvv -i pktap,bridge100,gpd0,en0 icmp

LXDコンテナ内からグローバルアドレスに ping を打ったときの出力は以下のような感じでした。 ping 8.8.8.8 で試しました。 192.168.2.207en0 についている IP アドレスです。

15:28:09.233218 (en7, svc BE, in) IP (tos 0x0, ttl 64, id 39934, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.254.2 > 8.8.8.8: ICMP echo request, id 9752, seq 1, length 64
15:28:09.233225 (bridge100, svc BE, in) IP (tos 0x0, ttl 64, id 39934, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.254.2 > 8.8.8.8: ICMP echo request, id 9752, seq 1, length 64
15:28:09.233277 (en0, proc :0:, eproc :0:, svc BE, out) IP (tos 0x0, ttl 63, id 39934, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.207 > 8.8.8.8: ICMP echo request, id 35952, seq 1, length 64
15:28:09.238693 (en0, svc BE, in) IP (tos 0x0, ttl 57, id 0, offset 0, flags [none], proto ICMP (1), length 84)
    8.8.8.8 > 192.168.2.207: ICMP echo reply, id 35952, seq 1, length 64
15:28:09.238717 (bridge100, proc :0:, eproc :0:, svc BE, out) IP (tos 0x0, ttl 56, id 0, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->b3ee)!)
    8.8.8.8 > 192.168.254.2: ICMP echo reply, id 9752, seq 1, length 64
15:28:09.238720 (en7, proc :0:, eproc :0:, svc BE, out) IP (tos 0x0, ttl 56, id 0, offset 0, flags [none], proto ICMP (1), length 84)

LXDコンテナ内から VPN 内のプライベートアドレス (XXX.XXX.XXX.XXX とします) に ping を打ったときの出力は以下のような感じでした。 gpd0 のアドレスを YYY.YYY.YYY.YYY とします。

15:25:30.464462 (en7, svc BE, in) IP (tos 0x0, ttl 63, id 44537, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.254.2 > XXX.XXX.XXX.XXX: ICMP echo request, id 3367, seq 1, length 64
15:25:30.464468 (bridge100, svc BE, in) IP (tos 0x0, ttl 63, id 44537, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.254.2 > XXX.XXX.XXX.XXX: ICMP echo request, id 3367, seq 1, length 64
15:25:30.464517 (gpd0, proc :0:, eproc :0:, svc BE, out) IP (tos 0x0, ttl 62, id 44537, offset 0, flags [none], proto ICMP (1), length 84)
    YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX: ICMP echo request, id 56265, seq 1, length 64
15:25:30.495240 (gpd0, svc BE, in) IP (tos 0x0, ttl 60, id 38184, offset 0, flags [none], proto ICMP (1), length 84)
    XXX.XXX.XXX.XXX > YYY.YYY.YYY.YYY: ICMP echo reply, id 56265, seq 1, length 64
15:25:30.495273 (bridge100, proc :0:, eproc :0:, svc BE, out) IP (tos 0x0, ttl 59, id 38184, offset 0, flags [none], proto ICMP (1), length 84, bad cksum 0 (->1f8a)!)
    XXX.XXX.XXX.XXX > 192.168.254.2: ICMP echo reply, id 3367, seq 1, length 64
15:25:30.495277 (en7, proc :0:, eproc :0:, svc BE, out) IP (tos 0x0, ttl 59, id 38184, offset 0, flags [none], proto ICMP (1), length 84)
    XXX.XXX.XXX.XXX > 192.168.254.2: ICMP echo reply, id 3367, seq 1, length 64

en7ifconfig で確認すると以下のようになっています(MACアドレスは伏せてます)が、これが何のインターフェースなのかは私はわかっていません。

en7: flags=8b63<UP,BROADCAST,SMART,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
        options=400<CHANNEL_IO>
        ether xx:xx:xx:xx:xx:xx 
        media: autoselect
        status: active

NATを設定する前は 192.168.254.2 からターゲットのIPアドレスへのパケットだけがあって、 en0gpd0 のアドレスからターゲットのIPアドレスへのパケットはありませんでした。

ついでにルーティングの表示・追加・削除コマンドをメモ

Troubleshooting networking on macOS | Multipass documentation を見て最初はルーティングも変更してみたので、ついでにメモ。

ルーティング表示

netstat -rn

ルーティング追加(ターゲットは -interface bridge100 のような指定方法もある。また -static というオプションもある)。

sudo route add -net 192.168.255.0/24 192.168.64.2

ルーティング削除

sudo route delete -net 192.168.255.0/24