github.com/weaveworks/common@v0.0.0-20230728070032-dd9e68f319d5/middleware/source_ips_test.go (about) 1 package middleware 2 3 import ( 4 "net/http" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 ) 9 10 func TestGetSourceIPs(t *testing.T) { 11 tests := []struct { 12 name string 13 req *http.Request 14 want string 15 }{ 16 { 17 name: "no header", 18 req: &http.Request{RemoteAddr: "192.168.1.100:3454"}, 19 want: "192.168.1.100", 20 }, 21 { 22 name: "no header and remote has no port", 23 req: &http.Request{RemoteAddr: "192.168.1.100"}, 24 want: "192.168.1.100", 25 }, 26 { 27 name: "no header, remote address is invalid", 28 req: &http.Request{RemoteAddr: "192.168.100"}, 29 want: "192.168.100", 30 }, 31 { 32 name: "X-Forwarded-For and single forward address", 33 req: &http.Request{ 34 RemoteAddr: "192.168.1.100:3454", 35 Header: map[string][]string{ 36 http.CanonicalHeaderKey(xForwardedFor): {"172.16.1.1"}, 37 }, 38 }, 39 want: "172.16.1.1, 192.168.1.100", 40 }, 41 { 42 name: "X-Forwarded-For and single forward address which is same as remote", 43 req: &http.Request{ 44 RemoteAddr: "192.168.1.100:3454", 45 Header: map[string][]string{ 46 http.CanonicalHeaderKey(xForwardedFor): {"192.168.1.100"}, 47 }, 48 }, 49 want: "192.168.1.100", 50 }, 51 { 52 name: "single IPv6 X-Forwarded-For address", 53 req: &http.Request{ 54 RemoteAddr: "[2001:db9::1]:3454", 55 Header: map[string][]string{ 56 http.CanonicalHeaderKey(xForwardedFor): {"2001:db8::1"}, 57 }, 58 }, 59 want: "2001:db8::1, 2001:db9::1", 60 }, 61 { 62 name: "single X-Forwarded-For address no RemoteAddr", 63 req: &http.Request{ 64 Header: map[string][]string{ 65 http.CanonicalHeaderKey(xForwardedFor): {"172.16.1.1"}, 66 }, 67 }, 68 want: "172.16.1.1", 69 }, 70 { 71 name: "multiple X-Forwarded-For with remote", 72 req: &http.Request{ 73 RemoteAddr: "192.168.1.100:3454", 74 Header: map[string][]string{ 75 http.CanonicalHeaderKey(xForwardedFor): {"172.16.1.1, 10.10.13.20"}, 76 }, 77 }, 78 want: "172.16.1.1, 192.168.1.100", 79 }, 80 { 81 name: "multiple X-Forwarded-For with remote and no spaces", 82 req: &http.Request{ 83 RemoteAddr: "192.168.1.100:3454", 84 Header: map[string][]string{ 85 http.CanonicalHeaderKey(xForwardedFor): {"172.16.1.1,10.10.13.20,10.11.16.46"}, 86 }, 87 }, 88 want: "172.16.1.1, 192.168.1.100", 89 }, 90 { 91 name: "multiple X-Forwarded-For with IPv6 remote", 92 req: &http.Request{ 93 RemoteAddr: "192.168.1.100:3454", 94 Header: map[string][]string{ 95 http.CanonicalHeaderKey(xForwardedFor): {"[2001:db8:cafe::17]:4711, 10.10.13.20"}, 96 }, 97 }, 98 want: "2001:db8:cafe::17, 192.168.1.100", 99 }, 100 { 101 name: "no header, no remote", 102 req: &http.Request{}, 103 want: "", 104 }, 105 { 106 name: "X-Real-IP with IPv6 remote with port", 107 req: &http.Request{ 108 RemoteAddr: "192.168.1.100:3454", 109 Header: map[string][]string{ 110 http.CanonicalHeaderKey(xRealIP): {"[2001:db8:cafe::17]:4711"}, 111 }, 112 }, 113 want: "2001:db8:cafe::17, 192.168.1.100", 114 }, 115 { 116 name: "X-Real-IP with IPv4 remote", 117 req: &http.Request{ 118 RemoteAddr: "192.168.1.100:3454", 119 Header: map[string][]string{ 120 http.CanonicalHeaderKey(xRealIP): {"192.169.1.200"}, 121 }, 122 }, 123 want: "192.169.1.200, 192.168.1.100", 124 }, 125 { 126 name: "X-Real-IP with IPv4 remote and X-Forwarded-For", 127 req: &http.Request{ 128 RemoteAddr: "192.168.1.100:3454", 129 Header: map[string][]string{ 130 http.CanonicalHeaderKey(xForwardedFor): {"[2001:db8:cafe::17]:4711, 10.10.13.20"}, 131 http.CanonicalHeaderKey(xRealIP): {"192.169.1.200"}, 132 }, 133 }, 134 want: "192.169.1.200, 192.168.1.100", 135 }, 136 { 137 name: "Forwarded with IPv4 remote", 138 req: &http.Request{ 139 RemoteAddr: "192.168.1.100:3454", 140 Header: map[string][]string{ 141 http.CanonicalHeaderKey(forwarded): {"for=192.169.1.200"}, 142 }, 143 }, 144 want: "192.169.1.200, 192.168.1.100", 145 }, 146 { 147 name: "Forwarded with IPv4 and proto and by fields", 148 req: &http.Request{ 149 RemoteAddr: "192.168.1.100:3454", 150 Header: map[string][]string{ 151 http.CanonicalHeaderKey(forwarded): {"for=192.0.2.60;proto=http;by=203.0.113.43"}, 152 }, 153 }, 154 want: "192.0.2.60, 192.168.1.100", 155 }, 156 { 157 name: "Forwarded with IPv6 and IPv4 remote", 158 req: &http.Request{ 159 RemoteAddr: "192.168.1.100:3454", 160 Header: map[string][]string{ 161 http.CanonicalHeaderKey(forwarded): {"for=[2001:db8:cafe::17]:4711,for=192.169.1.200"}, 162 }, 163 }, 164 want: "2001:db8:cafe::17, 192.168.1.100", 165 }, 166 { 167 name: "Forwarded with X-Real-IP and X-Forwarded-For", 168 req: &http.Request{ 169 RemoteAddr: "192.168.1.100:3454", 170 Header: map[string][]string{ 171 http.CanonicalHeaderKey(xForwardedFor): {"[2001:db8:cafe::17]:4711, 10.10.13.20"}, 172 http.CanonicalHeaderKey(xRealIP): {"192.169.1.200"}, 173 http.CanonicalHeaderKey(forwarded): {"for=[2001:db8:cafe::17]:4711,for=192.169.1.200"}, 174 }, 175 }, 176 want: "2001:db8:cafe::17, 192.168.1.100", 177 }, 178 { 179 name: "Forwarded returns hostname", 180 req: &http.Request{ 181 RemoteAddr: "192.168.1.100:3454", 182 Header: map[string][]string{ 183 http.CanonicalHeaderKey(forwarded): {"for=workstation.local"}, 184 }, 185 }, 186 want: "workstation.local, 192.168.1.100", 187 }, 188 } 189 for _, tt := range tests { 190 t.Run(tt.name, func(t *testing.T) { 191 sourceIPs, err := NewSourceIPs("", "") 192 require.NoError(t, err) 193 194 if got := sourceIPs.Get(tt.req); got != tt.want { 195 t.Errorf("GetSource() = %v, want %v", got, tt.want) 196 } 197 }) 198 } 199 } 200 201 func TestGetSourceIPsWithCustomRegex(t *testing.T) { 202 tests := []struct { 203 name string 204 req *http.Request 205 want string 206 }{ 207 { 208 name: "no header", 209 req: &http.Request{RemoteAddr: "192.168.1.100:3454"}, 210 want: "192.168.1.100", 211 }, 212 { 213 name: "No matching entry in the header", 214 req: &http.Request{ 215 RemoteAddr: "192.168.1.100:3454", 216 Header: map[string][]string{ 217 http.CanonicalHeaderKey("SomeHeader"): {"not matching"}, 218 }, 219 }, 220 want: "192.168.1.100", 221 }, 222 { 223 name: "one matching entry in the header", 224 req: &http.Request{ 225 RemoteAddr: "192.168.1.100:3454", 226 Header: map[string][]string{ 227 http.CanonicalHeaderKey("SomeHeader"): {"172.16.1.1"}, 228 }, 229 }, 230 want: "172.16.1.1, 192.168.1.100", 231 }, 232 { 233 name: "multiple matching entries in the header, only first used", 234 req: &http.Request{ 235 RemoteAddr: "192.168.1.100:3454", 236 Header: map[string][]string{ 237 http.CanonicalHeaderKey("SomeHeader"): {"172.16.1.1", "172.16.2.1"}, 238 }, 239 }, 240 want: "172.16.1.1, 192.168.1.100", 241 }, 242 } 243 for _, tt := range tests { 244 t.Run(tt.name, func(t *testing.T) { 245 sourceIPs, err := NewSourceIPs("SomeHeader", "((?:[0-9]{1,3}\\.){3}[0-9]{1,3})") 246 require.NoError(t, err) 247 248 if got := sourceIPs.Get(tt.req); got != tt.want { 249 t.Errorf("GetSource() = %v, want %v", got, tt.want) 250 } 251 }) 252 } 253 } 254 func TestInvalid(t *testing.T) { 255 sourceIPs, err := NewSourceIPs("Header", "") 256 require.Empty(t, sourceIPs) 257 require.Error(t, err) 258 259 sourceIPs, err = NewSourceIPs("", "a(.*)b") 260 require.Empty(t, sourceIPs) 261 require.Error(t, err) 262 263 sourceIPs, err = NewSourceIPs("Header", "[*") 264 require.Empty(t, sourceIPs) 265 require.Error(t, err) 266 }