socat を使った簡易プロキシと、自作シェルスクリプトの自動起動

自社のメールサーバを海外から使いたいが、自社の場合
海外 IP からの 587 番ポートの通信を許可しておらず SMTP 送信ができなかった、
そこで国内に別の Linux サーバを立てて、そこ経由で通信しようと企みました。

自身の IP アドレス以外から特定のサーバにアクセスする際の簡易プロキシとして
socat を試してみました。

自作スクリプトを systemctl enable する所まで記載してみます。
※ 本稿では SELinux やファイヤウォール設定などの記載を省略しています。


## 前提

アクセスしたいサーバ : example.co.jp
アクセスしたいポート : 587/tcp (SMTP Submittion) と 143/tcp (IMAP)
中継サーバで開放するポート（例） : 50587 と 50143

中継サーバには CentOS7 をインストールしました。


## socat をインストール

```bash
$ sudo yum -y install socat
```

## 自作スクリプト置き場を作成する

```bash
$ sudo mkdir -p /opt/socat-proxy/{bin,lib}
$ sudo chmod 0755 /opt/socat-proxy/bin
```

## 起動スクリプトを作成する

本稿では User=root Group=root で起動していますが、
環境に応じて適切なユーザ権限でサービスを動かすべきと思います。

まずサーバの 50587 ポートと目的サーバの 587 ポートを繋ぐ socat を作成します。

```bash
$ sudo vi /opt/socat-proxy/bin/tcp-50587.sh
```

```bash:/opt/socat-proxy/bin/tcp-50587.sh
#!/bin/sh

/usr/bin/socat -d -d -lm tcp-l:50587,fork,setgid=root,setuid=root tcp:example.co.jp:587 </dev/null &

echo $! >/var/run/tcp-50587.pid
```

同様に 50143 ポートと目的サーバの 143 ポートを繋ぐ socat を作成します。

```bash
$ sudo vi /opt/socat-proxy/bin/tcp-50143.sh
```

```bash:/opt/socat-proxy/bin/tcp-50143.sh
#!/bin/sh

/usr/bin/socat -d -d -lm tcp-l:50143,fork,setgid=root,setuid=root tcp:example.co.jp:143 </dev/null &

echo $! >/var/run/tcp-50143.pid
```


起動スクリプトに実行権限を付与します。

```bash
$ sudo chmod 0755 /opt/socat-proxy/bin/tcp-50587.sh
$ sudo chmod 0755 /opt/socat-proxy/bin/tcp-50143.sh
```

## ユニットファイルを用意する

まず 50587 ポート用ファイルを作成。

```bash
$ sudo vi /opt/socat-proxy/lib/tcp-50587.service
```

```bash:/opt/socat-proxy/lib/tcp-50587.service
[Unit]
Description = socat proxy tcp 50587
After=syslog.target network.target remote-fs.target nss-lookup.target
ConditionPathExists=/opt/socat-proxy/bin

[Service]
Type=forking
PIDFile=/var/run/tcp-50587.pid
ExecStart=/opt/socat-proxy/bin/tcp-50587.sh
ExecStop=/bin/kill -s QUIT $MAINPID

[Install]
WantedBy = multi-user.target
```

同様に 50143 ポート用ファイルも作成。

```bash
$ sudo vi /opt/socat-proxy/lib/tcp-50143.service
```

```bash:/opt/socat-proxy/lib/tcp-50143.service
[Unit]
Description = socat proxy tcp 50143
After=syslog.target network.target remote-fs.target nss-lookup.target
ConditionPathExists=/opt/socat-proxy/bin

[Service]
Type=forking
PIDFile=/var/run/tcp-50143.pid
ExecStart=/opt/socat-proxy/bin/tcp-50143.sh
ExecStop=/bin/kill -s QUIT $MAINPID

[Install]
WantedBy = multi-user.target
```

作成した 2 サービス分のファイルを /etc/systemd/system/ 配下にコピーします。

```bash
$ sudo cp /opt/socat-proxy/lib/tcp-50587.service /etc/systemd/system/tcp-50587.service
$ sudo cp /opt/socat-proxy/lib/tcp-50143.service /etc/systemd/system/tcp-50143.service
```


ユニットファイルを変更したあとは毎回 daemon-reload を唱えます。

```bash
$ sudo systemctl daemon-reload
```

サービスに含まれていることを確認します。

```bash
$ sudo systemctl list-unit-files --type=service | grep tcp-50
tcp-50143.service                             disabled
tcp-50587.service                             disabled
```

### 起動確認

ここで、もっとサービス名らしいサービス名にすればよかったと後悔。

```bash
$ sudo systemctl start tcp-50587
$ sudo systemctl start tcp-50143
```

サービスがポートを使用していることを確認します。

```bash
$ netstat -ltup4
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN      617/sshd            
tcp        0      0 0.0.0.0:50587           0.0.0.0:*               LISTEN      27009/socat         
tcp        0      0 0.0.0.0:50143           0.0.0.0:*               LISTEN      27018/socat         
```

```bash
$ sudo systemctl status tcp-50587
● tcp-50587.service - socat proxy tcp 50587
   Loaded: loaded (/etc/systemd/system/tcp-50587.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2018-05-01 00:00:00 JST; 0min 01s ago
  Process: 27008 ExecStart=/opt/socat-proxy/bin/tcp-50587.sh (code=exited, status=0/SUCCESS)
 Main PID: 27009 (socat)
   CGroup: /system.slice/tcp-50587.service
           └─27009 /usr/bin/socat -d -d -lm tcp-l:50587,fork,setgid=root,setuid=root tcp:example.co.jp:587

 May 01 00:00:00 hostname systemd[1]: Starting socat proxy tcp 50587...
 May 01 00:00:00 hostname systemd[1]: Started socat proxy tcp 50587.
 May 01 00:00:00 hostname socat[27009]: N listening on AF=2 0.0.0.0:50587
```

```bash
$ sudo systemctl status tcp-50143
● tcp-50143.service - socat proxy tcp 50143
   Loaded: loaded (/etc/systemd/system/tcp-50143.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2018-05-01 00:00:00 JST; 0min 01s ago
  Process: 27017 ExecStart=/opt/socat-proxy/bin/tcp-50143.sh (code=exited, status=0/SUCCESS)
 Main PID: 27018 (socat)
   CGroup: /system.slice/tcp-50143.service
           └─27018 /usr/bin/socat -d -d -lm tcp-l:50143,fork,setgid=root,setuid=root tcp:example.co.jp:143

 May 01 00:00:00 hostname systemd[1]: Starting socat proxy tcp 50143...
 May 01 00:00:00 hostname systemd[1]: Started socat proxy tcp 50143.
 May 01 00:00:00 hostname socat[27018]: N listening on AF=2 0.0.0.0:50143
```

メールソフトの SMTP 先を中継サーバの IP アドレス：ポート 50587 に変更。
メールソフトの IMAP 先を中継サーバの IP アドレス：ポート 50143 に変更。
メールサーバと透過的に通信できていることを確認します。

問題なければ enable して、サーバ再起動後に自動起動されることを確認します。

```bash
$ sudo systemctl enable tcp-50587
$ sudo systemctl enable tcp-50143
```

## 参考エントリ

[Linux経由でリモートデスクトップ接続をフォワーディング](https://qiita.com/Daisuke-Otaka/items/b6140f94023510b7873a)
[systemdで簡易中継サーバを作る](https://qiita.com/pasela/items/a387711c7a39c3aa4ec0)
[systemdを用いたプログラムの自動起動](https://qiita.com/tkato/items/6a227e7c2c2bde19521c)
[Systemdを使ってさくっと自作コマンドをサービス化してみる](https://qiita.com/DQNEO/items/0b5d0bc5d3cf407cb7ff)