ginのリクエスト元のIPアドレス取得ソースコードを読んでみました
背景
リクエストが来る時に、リクエスト元のIPアドレスをみて、アクセスを制限させる要望はよくあると思います。
ginは一応そのIPの取り方をAPIとして用意されてます、今回そのAPIの中身を読んでみました。
ginのバージョン
github.com/gin-gonic/gin v1.8.1
API
まずgin.Contextの中に②種類のAPIが存在しています
- RemoteIP: 直接繋がるリクエスト先のIPを取っています。
- ClientIP: HTTPヘッダー情報からIP情報を解析しています。
1. RemoteIP####
実質はgin.Context.Request.RemoteAddrの価を取り出しています。
この値はginが依存しているnet/httpパッケージから取ってきています。
さらにnetパッケージから取ってきています。
この方法を使えば、直接ginが搭載しているサーバーと繋がるエンドユーザーのIPを取れますが、実際にdeployされる環境では、エンドユーザーとginのサーバーの間には複数proxyサーバーが存在する可能性は高いです。
そのため、エンドユーザーのIPを取るためには、このAPIは活用できない可能性は結構たかいです。
このAPIを使うなら、取れるのはginのサーバーと直接繋がる一個前のproxyサーバーのIPアドレスになります。
2. ClientIP
この方法を使えば、うまく設定すれば、エンドユーザーのIPアドレスを取れます。
まず中を見てみましょう
2-1. 一個前のproxyサーバーのIPアドレスを取ります
2-2. 一個前のproxyサーバーは信頼するべきかどうかを判断します
信頼するリストがあります。それはmain関数が走る時に、設定するものです。
gin1.8ではproxyサーバーのIPアドレスを信頼リストに登録する必要があります。
2-2-1. 一個前のproxyサーバーは信頼するものではないなら、そのまま一個前のproxyサーバーのIPアドレスを返します
2-2-2. 一個前のproxyサーバーは信頼するものなら
2-3. httpヘッダーにある情報を取り出して、検証します
デフォルトはこちらのヘッダーを取り出しています。
validationの中身を見てみると
ここに来るheaderは実際にこのような価になっています
142.222.149.55 ,172.16.25.116
,を区切って、配列にして、後ろから見ていますよ。
for i := len(items) - 1; i >= 0; i-- {
そして、最初のelementもしくは、信頼リストに入ってないIPを見つけたら、すぐ返します。
if (i == 0) || (!engine.isTrustedProxy(ip)) {
return ipStr, true
}
実際のイメージ
proxyサーバーは受け取ったリクエストのX-Forwarded-Forにリクエスト元のRemoteAddrを後ろに足して、次の先に投げています。
Discussion