GoのgRPCでRemote IPを取得する方法


結論

contextの中にpeerの情報があるのでそこにnet.Addrが入っている。

import (
    "google.golang.org/grpc/peer"
)

func foo(ctx context.Context, ...) {
    var addr string
    if pr, ok := peer.FromContext(ctx); ok {
        addr = pr.Addr.String()
    }
}

詳細

gRPCのgo実装であるgrpc-goはサーバ側でリクエストを受け取ってprotobufで生成されたハンドラを呼び出す部分とhttp2自体の実装部分とに分かれています。前者はserver.go、後者はhtt2_server.goになります。

Remote IPは接続元の情報(Peer)としてhttp2の実装側でstreamの中のcontextに格納されています。格納しているのはここ

あとはハンドラの第一引数としてcontext.Contextが渡されるのでpeer.FromContext(ctx)でPeerを取得します。peerのAddrがnet.AddrなのでそのままString()でも良いですが、IPアドレスのみを取得したい場合は*net.TCPAddrに変換すると良いでしょう。

import (
    "google.golang.org/grpc/peer"
)

func (s *EchoServer) Echo(ctx context.Context, in *echo.EchoRequest) (*echo.EchoResponse, error) {
    var addr string
    if pr, ok := peer.FromContext(ctx); ok {
        if tcpAddr, ok := pr.Addr.(*net.TCPAddr); ok {
            addr = tcpAddr.IP.String()
        } else {
            addr = pr.Addr.String()
        }
    }
    log.Printf("remote addr: %v", addr)

    return &echo.EchoResponse{Message: in.Message}, nil
}