gitlab.com/gitlab-org/labkit@v1.21.0/correlation/inbound_http_options.go (about) 1 package correlation 2 3 import ( 4 "net" 5 "net/http" 6 7 "github.com/sebest/xff" 8 "github.com/sirupsen/logrus" 9 ) 10 11 // XFFAllowedFunc decides whether X-Forwarded-For headers are to be trusted. 12 type XFFAllowedFunc func(ip string) bool 13 14 // The configuration for InjectCorrelationID. 15 type inboundHandlerConfig struct { 16 propagation bool 17 sendResponseHeader bool 18 invalidCIDRsForPropagation bool 19 trustedCIDRsForPropagation []net.IPNet 20 trustedCIDRsForXForwardedFor []net.IPNet 21 xffAllowed XFFAllowedFunc 22 } 23 24 // InboundHandlerOption will configure a correlation handler 25 // currently there are no options, but this gives us the option 26 // to extend the interface in a backwards compatible way. 27 type InboundHandlerOption func(*inboundHandlerConfig) 28 29 func applyInboundHandlerOptions(opts []InboundHandlerOption) inboundHandlerConfig { 30 config := inboundHandlerConfig{ 31 propagation: false, 32 } 33 for _, v := range opts { 34 v(&config) 35 } 36 37 return config 38 } 39 40 // WithPropagation will configure the handler to propagate existing correlation_ids 41 // passed in from upstream services. 42 // This is not the default behaviour. 43 func WithPropagation() InboundHandlerOption { 44 return func(config *inboundHandlerConfig) { 45 config.propagation = true 46 } 47 } 48 49 // WithSetResponseHeader will configure the handler to set the correlation_id 50 // in the http response headers. 51 func WithSetResponseHeader() InboundHandlerOption { 52 return func(config *inboundHandlerConfig) { 53 config.sendResponseHeader = true 54 } 55 } 56 57 // WithCIDRsTrustedForPropagation will configure the handler to set a list of trusted 58 // CIDR blocks to allow propagation of correlation_ids. 59 func WithCIDRsTrustedForPropagation(trustedCIDRs []string) InboundHandlerOption { 60 return func(config *inboundHandlerConfig) { 61 for _, s := range trustedCIDRs { 62 _, ipNet, err := net.ParseCIDR(s) 63 if err != nil { 64 logrus.Errorf("Bad trusted CIDR for propagation %s: %v, propagation disabled", s, err) 65 config.invalidCIDRsForPropagation = true 66 } else { 67 config.trustedCIDRsForPropagation = append(config.trustedCIDRsForPropagation, *ipNet) 68 } 69 } 70 } 71 } 72 73 // WithCIDRsTrustedForXForwardedFor will configure the handler to trust 74 // X-Forwarded-For from trusted CIDR blocks. 75 func WithCIDRsTrustedForXForwardedFor(trustedCIDRs []string) InboundHandlerOption { 76 return func(config *inboundHandlerConfig) { 77 for _, s := range trustedCIDRs { 78 _, ipNet, err := net.ParseCIDR(s) 79 if err != nil { 80 logrus.Errorf("Bad trusted CIDR for XForwardedFor %s: %v", s, err) 81 } else { 82 config.trustedCIDRsForXForwardedFor = append(config.trustedCIDRsForXForwardedFor, *ipNet) 83 } 84 } 85 86 config.xffAllowed = func(ip string) bool { 87 return isTrustedIP(ip, config.trustedCIDRsForXForwardedFor) 88 } 89 } 90 } 91 92 func isTrustedIP(ipAddress string, trustedCIDRs []net.IPNet) bool { 93 ip := net.ParseIP(ipAddress) 94 95 for _, cidr := range trustedCIDRs { 96 if cidr.Contains(ip) { 97 return true 98 } 99 } 100 101 return false 102 } 103 104 func isTrustedAddr(addr string, trustedCIDRs []net.IPNet) bool { 105 host, _, err := net.SplitHostPort(addr) 106 if err != nil { 107 return false 108 } 109 110 return isTrustedIP(host, trustedCIDRs) 111 } 112 113 func (c *inboundHandlerConfig) shouldPropagate(r *http.Request) bool { 114 if !c.propagation || c.invalidCIDRsForPropagation { 115 return false 116 } 117 118 if len(c.trustedCIDRsForPropagation) == 0 { 119 return true 120 } 121 122 remoteAddr := r.RemoteAddr 123 124 if c.xffAllowed != nil { 125 // Unix domain sockets have a remote addr of @. This will make the 126 // xff package lookup the X-Forwarded-For address if available. 127 if remoteAddr == "@" { 128 r.RemoteAddr = "127.0.0.1:0" 129 } 130 131 remoteAddr = xff.GetRemoteAddrIfAllowed(r, c.xffAllowed) 132 133 // If X-Forwarded-For was allowed and returned a different address, check 134 // the original address against our trusted CIDRs for propagation, in case 135 // the reverse proxy is trusted 136 if remoteAddr != r.RemoteAddr && isTrustedAddr(r.RemoteAddr, c.trustedCIDRsForPropagation) { 137 return true 138 } 139 } 140 141 return isTrustedAddr(remoteAddr, c.trustedCIDRsForPropagation) 142 }