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  }