Linux での Global Protect VPN の代替

> Alternatives to Global Protect VPN on Linux

後輩が意外にも知らなかったので記事としておいといて，適宜リンクをぶん投げる用めも．

# TL;DR

- PaloAltoのGlobal Protect VPNを介して接続しろという．
    - Linux版がないんだが．
    - 全部の通信がVPNのGWを通るんだが（そういうセキュリティポリシーとか伺ってない）．
        - 正直開発用のSSHが通ればよいのだ．
        - **指定IP範囲（CIDR範囲）だけVPNに飛ばしますよ...**
    - **IPSec Xauth PSK**がサポートされているようだ．
        - **`vpnc`なるものを利用**すれヴぁよいようだ．

### ATTENTION!

VPN?, IPSec?, ルーティング? がわからんって人は組織に大変な迷惑を掛ける可能性あるのでやらないでください．

## Environment/Requirement

- Ubuntu君（それ以外のDistroは適宜読み替えてください）
    - root privilege
    - `ip`コマンド環境（確かUbuntu18あたり以降）
- bash君
    - スクリプト用

### Installation


VPN接続用 vpnc: Cisco-compatible VPN client

```shell-session
$ sudo apt install vpnc
```

TAPデバイス用設定用 uml-utilities: User-mode Linux (utility programs)

```shell-session
$ sudo apt install uml-utilities
```

## Configuration

`sudo vi /etc/vpnc/default.conf`

```text
IPSec ID [IPSecのID]
IPSec gateway [VPNサーバーのFQDN]
IPSec secret [IPSecのシークレットキー]

Xauth username [組織アカウントユーザー]
Xauth password [組織アカウントパスワード（セキュアな環境か注意してください）]

IKE Authmode psk

# Virtual Ethernet Adaptor Mode
## TAPの名前は任意で．Optional name 'hoge'
Interface name hoge
Interface mode tap
```

TAPをつくる

```shell_session
$ sudo tunctl -t hoge
Set 'hoge' persistent and owned by uid 0
```

## Routing Test

あらかじめデフォルトゲートウェイのアドレスを確認しておく．

> FIXME: `ip route get` でもっとスマートできる場合がないか検証の余地あり．

```shell-session
$ ip route | grep default | grep -oP 'via [^\ ]*' | cut -d' ' -f2 | head -1
192.168.0.1 
$ # ↑ デフォルトゲートウェイのアドレス - default gw address
```

つなげてみる（全部の通信が組織ネットワーク側に向く）

```shell-session
$ sudo vpnc
$ # or
$ sudo vpnc-connect
```

`ip route`で`default via`が上書きされているのがわかる．`tracepath`/`mtr`等で確認してみる．

```shell-session
$ mtr -T 1.1.1.1 # 例
```

これを置き換える．

**IPアドレス等適宜読み替えてください**

```shell-session
$ip route | grep default | grep -oP 'via [^\ ]*' | cut -d' ' -f2 | head -1
10.10.15.1  
$ # ↑ VPN接続先例
$ sudo ip route replace default via 192.168.0.1
$
$ ip route | grep default | grep -oP 'via [^\ ]*' | cut -d' ' -f2 | head -1
192.168.0.1 
$ # ↑ 戻った
$ # 再度確認してみる
mtr -T 1.1.1.1
```

経路を追加する(例: 組織ネットワーク内の `172.22.1.0/24` を追加する）

```shell-session
$ ping -W1 -c1 172.22.1.254
PING 172.22.1.254 (172.22.1.254) 56(84) bytes of data.

--- 172.22.1.254 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
$ # ↑ つながらない ;-(
$
$ # 経路追加 - 172.22.1.0/24をTAPデバイス hoge 宛にルート張る．
$ ip route add 172.22.1.0/24 dev hoge
$
$ ping -W1 -c1 172.22.1.254
PING 172.22.1.254 (172.22.1.254) 56(84) bytes of data.
64 bytes from 172.22.1.254: icmp_seq=1 ttl=252 time=1.37 ms

--- 172.22.1.254 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.372/1.372/1.372/0.000 ms
$
$ # つながった :-)
```

## Script

これをスクリプトにしておく．

`vpn.sh`

```bash
#!/bin/bash
# /etc/vpnc/default.confで下記のように定義し変数とする．
# Interface name [IFNAME]
IFNAME="hoge"

_usage()
{
  echo "usage1: $ sudo $0 [up|down]"
  echo "usage2: # $0 [up|down]"
  exit 1
}

if    [[ "$USER" != "root" ]] || [[ $# -ne 1 ]];then
  _usage
elif  [[ "$1" != "up" ]] && [[ "$1" != "down" ]];then
  _usage
fi

set -eu

default_gw="$(ip route  | grep default | grep -o 'via [^\ ]*' | cut -d' ' -f2| head -1)"

case "$1" in
  "up") timeout 10 vpnc-connect;;
  "down") timeout 10 vpnc-disconnect;;
esac

if [[ "$1" == "down" ]];then
  # Note: 接続を切ると元に戻るので何もしない．
  exit 0
fi

# デフォルトゲートウェイの変更（通常のゲートウェイへ）
ip route replace default via "$default_gw"

while read cidr
do
  timeout 10 ip route add "$cidr" dev "$IFNAME"
done << ADDRESSES
10.0.0.0/8
172.16.0.0/16
ADDRESSES
# 組織ネットワークのアドレスを↑に追加する．
```

### Note

- VPN接続時の `/etc/resolv.conf` を確認し，組織アドレスを持っていたら，それも追加しないと名前解決失敗するので注意．
-  複数接続先を持つ場合は `/etc/vpnc` の中に`任意名.conf`の設定ファイルをぶち込んで，`vpnc-connect`に任意名をつければできるので，任意名で判断すればできます．改変はご自由に．

### Use it!

```shell-session
$ chmod u+x vpn.sh
$ # 接続
$ ./vpn.sh up
$ # 切断
$ ./vpn.sh down
```


## Use Cases

1. VPS上でコレを実行し，出先だろうと自宅だろうと，SOCKS5 Proxy経由で組織ネットワークに入ることができる．
2. 自宅から接続する際に必要な通信だけ外に向かすことができる．（SSH, SOCKS5 Proxy）
3. クライアントがLinuxなら，SOCKS5しなくていい．
4. 拠点間VPN仕様なら（というかそのはず？），VPN接続時の割当IPに向けて組織内からSSH接続することで自宅ネットワークのNASに接続したり，VPSを踏み台にできるはず．

## End Note

- 必要なトラヒックだけVPN経由させることで来たので，Spotifyとかガンガン使っても問題ないし，Teamsのセッションとかも経由しないからサクサク（なはず！）
- 正直手元にあるRTX810のコンフィグちょこちょこ弄れば同じことできるけど，まだ持っていないときは大変この手法が便利でした．あとは携帯から取り急ぎ繋ぎたいときとか，Juice SSH ClientでVPSをviaに指定すればよいだけなので楽でした．