フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

CloudFlareの記事を読んでTCPでIP固定の場合の挙動をまとめる(IP_BIND_ADDRESS_NO_PORT)

これを噛み砕くのに CloudFlare の記事を参照したのだが、あんまりちゃんとみてなくて理解に時間がかかったので備忘がてらまとめる。

blog.cloudflare.com

CloudFlare の問題

エフェメラルポートが枯渇して、自分発の通信ができなくなった。

Linux のデフォルトの挙動

通信をする際には宛先情報と送信元情報が必要になる。Linux のデフォルトでは、OSが送信元IP・ポートを選択し付与する。

※↑引用

cd = socket.socket(AF_INET, SOCK_STREAM)
cd.connect(('104.1.1.229', 80))

となるので、connect() 時に送信元を選んでる

通常の方法では

  • 宛先が変われば、送信元IP&ポートの組み合わせは使いまわせる
  • 宛先が同じならエフェメラルポートの上限が通信数の限界

CloudFlare の送信元IPをアプリで指定する話

CDNは客のオリジンサーバにアクセスするため、顧客がIP制限をできるように意図したIPアドレスをつかう必要がある。そのためOSが決める方式ではなく、アプリで指定している。

bind() をつかってIPの固定化ができるのだが、bind 時は宛先ポートがわからないので通常の方法のような 送信元IP&ポートの組み合わせができない

つまり、通常よりも作成できる通信数が少なくなる。

ただしIP_BIND_ADDRESS_NO_PORT を使うと、送信元ポートの予約を遅らせることができる。これにより IP をとりあえず固定化しておき、送信元ポートは connect 時に発行する。

sd = socket.socket(SOCK_STREAM)
sd.setsockopt(IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, 1)
sd.bind( (src_IP, 0) )
sd.connect( (dst_IP, dst_port) )

わかったこと

  • 送信元の組み合わせが同じでも、宛先が違うなら使いまわせる
  • IP アドレスを増やせば送信元の組み合わせが増えるので、ポート枯渇の心配が減る
  • ただしアプリで特定のIPを強制したい場合は、OSではなくアプリ側で制御する必要がある
  • このとき IP_BIND_ADDRESS_NO_PORT を使わないと、宛先ごとに送信元の組み合わせが同じ物を使いまわせない