backlog の実験

今日は、backlog の実験をしてみます。

CentOS6.9 で、メモリ4Gbyte の仮想マシン上で実験しました。

よく使われるアプリケーションとして、Apache を上げてみます。

前提知識です。

```
syn backlog：接続確立中キューの最大値（不完全なソケットのキューの最大長）

backlog：接続待ちキューの最大値（完全に確立されたソケットのキューの最大長）

tcp_syncookies：

有効（値 1）：一定の基準を越えた場合、syncookies を送信する。
syn backlog と backlog の小さいほうの値を、付近の 2の累乗の値に
切り上げた数値を超えると、syncookie を送信します（注）。
その際、ソケット蓄積の概念は放棄されるため、syn backlogの最大値の概念
は無視されます。

無効（値 0）： 一定の基準を越えた場合、新たな要求を無視する。
接続確立中キューに syn backlog の 75 % + 1 を超えるソケットが溜まる
と、新しい要求を無視します。

（注）
syncookies は、TCP プロトコルにしたがっていない点があり、攻撃に対する
対処用法として存在し、予備的な機能（fallback functionality）でしか
ないため、SYN flood を起こさせるようなDOS 攻撃を受けていると考えられる
場合のみに発動されるべきです。
（参考）
Documentation/networking/ip-sysctl.txt
```

次に、それぞれの値の設定ヶ所の説明です。

```
- syn backlog の設定ヶ所
OS の設定か所：/proc/sys/net/ipv4/tcp_max_syn_backlog
Apache の設定ヶ所：なし

- backlog の設定ヶ所
OSの設定箇所： /proc/sys/net/core/somaxconn
Apache の設定か所： ListenBackLog ディレクティブの設定値
```

backlog の値について、OS および Apache で設定が可能ですが、以下の条件にしたがいます。

```
Apache の設定値 ≦ OS の設定値ならば、
Apache の設定値が有効

Apache の設定値 ＞ OS の設定値ならば、
OS の設定値が有効
```

- tcp_syncookies の設定ヶ所

```
OS の設定か所：/proc/sys/net/ipv4/tcp_syncookies
Apache の設定ヶ所：なし
```

backlog の値は、実際は 1 から 65535 まで設定可能です。

例えば、OS および Apache の設定値を 4096 にすると、backlog の設定値は、
Apache の値、4096 となります。

syn backlog の値を増やすかどうかは、そのマシンの通常の通信状況によります。

OS のデフォルト設定では、syncookies が有効になっていますので、
接続確立中の要求が syn backlog の値と、backlog 値の小さいほうの値を、
付近の 2 の累乗の値を切り上げた数値を超えた場合、syncookie が送信されます。

通常のトラフィックにおいて、接続確立中の要求が多くならいようであれば、
syn backlog の値を増やす必要はなく、通常の通信環境においても、
接続確立中の要求が多くなるようであれば、多くする必要があるかもしれませんね。

いずれにしても、設定の際は、通常のアプリケーションの通信状況を把握した上で、
各上限値を設定する必要があるといえます。

TCP ソケットを listen している情報は、以下のコマンドの結果が表示する、
Recv-Q,Send-Q により確認できます。ここで、Send-Q の値が、Apache の
backlog になります。

```
# ss -lti '( sport = :http )'
```

接続確立中の要求数の確認は、以下のコマンドで確認できます。

```
# netstat -antp | grep SYN_RECV | wc -l
```

（一例：syncookies=0 で syn backlog が 2048 の時、上限値に達した場合）
1537

私が行った設定で実験したら、このようになりました。
--------
・デフォルトの設定

```
128 /proc/sys/net/core/somaxconn
2048 /proc/sys/net/ipv4/tcp_max_syn_backlog
511 Apache の ListenBackLog ディレクティブ
```
```
backlog の最大値 128
tcp_syncookies=1 の場合
接続確立中の要求数の上限値 256（backlog の付近の2の累乗の値）
tcp_syncookies=0 の場合
接続確立中の要求数の上限値 1537（syn backlog * 0.75 + 1 の値）
```

・OS、Apache の設定値を上げる

```
2048 /proc/sys/net/core/somaxconn
2048 /proc/sys/net/ipv4/tcp_max_syn_backlog
2048 Apache の ListenBackLog ディレクティブ
```

```
backlog の最大値 2048
tcp_syncookies=1 の場合
接続確立中キューの最大値 4096（backlog の付近の2の累乗の値）
tcp_syncookies=0 の場合
接続確立中キューの最大値 1537（syn backlog * 0.75 + 1 の値）
```

・syn backlog 変化させず、さらにOS、Apacheの設定値を上げる

```
4096 /proc/sys/net/core/somaxconn
2048 /proc/sys/net/ipv4/tcp_max_syn_backlog
4096 Apache の ListenBackLog ディレクティブ
```

```
backlog の最大値 4096
tcp_syncookies=1 の場合
接続確立中キューの最大値 4096（syn backlog の付近の 2 の累乗の値）
tcp_syncookies=0 の場合
接続確立中キューの最大値 1537（syn backlog * 0.75 + 1 の値）
```

・syn backlog を、4096 に上げる

```
4096 /proc/sys/net/core/somaxconn
4096 /proc/sys/net/ipv4/tcp_max_syn_backlog
4096 Apache の ListenBackLog ディレクティブ

backlog の最大値 4096
tcp_syncookies=1 の場合
接続確立中キューの最大値 8192（backlog の付近の2の累乗の値）
tcp_syncookies=0 の場合
接続確立中キューの最大値 3073（syn backlog * 0.75 + 1 の値）
```
 
また、この実験の場合ですが、接続確立中の要求が syn backlog の値と、
backlog 値の小さいほうの値を、付近の 2 の累乗の値を切り上げた数値を超えた
場合、syncookie が送信されることになります。
そのとき、/va/log/messages には、以下のログが 60秒に 1回記録されます。

```
kernel: possible SYN flooding on port <PORT>. Sending cookies.
```
 
tcp_syncookies は OS で有効に設定されています。
tcp_syncookies が有効な場合、上述のとおり syn backlog の値を
変化させることにより、接続確立中キューの最大値は変化するので、

適宜設定したらいいと思います。


具体的にどうやって実験したかというと、次のようにやりましたよ。

以下のスクリプトを実行します。これを確認します。

```
#!/bin/bash
while :
do
netstat -antp | grep SYN_RECV | wc -l

sleep 1
done
```
 
下記のとおり、SYN FLOOD 攻撃を実行して、上記の表示を観察する（実際のシステムにやってはいけませんよ）。


```
# hping3 -c 10000 -d 120 -S -w 64 -p 21 --flood --rand-source <TARGET_IP>
```

おいしいもの食べたいなぁ。

(参考：用語解説等)

https://access.redhat.com/solutions/30453

http://d.hatena.ne.jp/nyant/20111216/1324043063

mpm_common - Apache HTTP サーバ バージョン 2.4

(参考：hping3)
https://www.blackmoreops.com/2015/04/21/denial-of-service-attack-dos-using-hping3-with-spoofed-ip-in-kali-linux/