(ctx context.Context)
| 103 | } |
| 104 | |
| 105 | func (h *ProxyHeaders) intercept(ctx context.Context) (context.Context, metadata.MD) { |
| 106 | md, _ := metadata.FromIncomingContext(ctx) |
| 107 | |
| 108 | p, ok := peer.FromContext(ctx) |
| 109 | if !ok { |
| 110 | // The gRPC server should always set this. |
| 111 | panic(fmt.Errorf("no peer in gRPC context")) |
| 112 | } |
| 113 | remoteAddr := p.Addr.String() |
| 114 | if remoteAddr == "pipe" { |
| 115 | remoteAddr = "127.0.0.0:0" |
| 116 | } |
| 117 | remoteIP, _, err := net.SplitHostPort(remoteAddr) |
| 118 | if err != nil { |
| 119 | // Either the gRPC server should have set the peer address to "IP:port" |
| 120 | // or we have converted the pipe address to localhost above. |
| 121 | panic(fmt.Errorf("invalid peer %q in gRPC context: %w", remoteAddr, err)) |
| 122 | } |
| 123 | if h.trustedIP(net.ParseIP(remoteIP)) { |
| 124 | // We trust the proxy, so we parse the headers if present. |
| 125 | forwardedFor, _, _ := parseForwardedHeaders(getLastFromMD(md)) // ignore forwardedScheme and forwardedHost. |
| 126 | if forwardedFor != "" { |
| 127 | md.Set(headerXRealIP, strings.TrimSpace(strings.Split(forwardedFor, ",")[0])) |
| 128 | } |
| 129 | if cert, ok, err := mtls.FromProxyHeaders(getLastFromMD(md)); err != nil { |
| 130 | log.FromContext(ctx).WithError(err).Warn("Failed to parse client certificate from proxy headers") |
| 131 | } else if ok { |
| 132 | ctx = mtls.NewContextWithClientCertificate(ctx, cert) |
| 133 | } |
| 134 | } else { |
| 135 | // We don't trust the proxy, remove its headers. |
| 136 | for _, header := range proxyHeaders { |
| 137 | delete(md, header) |
| 138 | } |
| 139 | md.Set(headerXRealIP, remoteIP) |
| 140 | } |
| 141 | return ctx, md |
| 142 | } |
| 143 | |
| 144 | type getLastFromMD metadata.MD |
| 145 |
no test coverage detected