Skip to content

Commit 4165843

Browse files
gearnodepires
authored andcommitted
Add TrustProxyHeaderFrom policy function
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
1 parent 37053b0 commit 4165843

2 files changed

Lines changed: 63 additions & 5 deletions

File tree

policy.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,31 @@ func ipFromAddr(upstream net.Addr) (net.IP, error) {
186186
return upstreamIP, nil
187187
}
188188

189-
// IgnoreProxyHeaderNotOnInterface retuns a ConnPolicyFunc which can be used to
189+
// TrustProxyHeaderFrom returns a ConnPolicyFunc which can be used to decide
190+
// whether to use or reject PROXY headers based on the source IP of the
191+
// connection. This policy ensures that only trusted sources can set the PROXY
192+
// header. Connections from IPs not in the trusted list will be rejected.
193+
func TrustProxyHeaderFrom(trustedIPs ...net.IP) ConnPolicyFunc {
194+
return func(connOpts ConnPolicyOptions) (Policy, error) {
195+
ip, err := ipFromAddr(connOpts.Upstream)
196+
if err != nil {
197+
return REJECT, err
198+
}
199+
200+
for _, trustedIP := range trustedIPs {
201+
if trustedIP.Equal(ip) {
202+
return USE, nil
203+
}
204+
}
205+
206+
return REJECT, nil
207+
}
208+
}
209+
210+
// IgnoreProxyHeaderNotOnInterface returns a ConnPolicyFunc which can be used to
190211
// decide whether to use or ignore PROXY headers depending on the connection
191-
// being made on a specific interface. This policy can be used when the server
192-
// is bound to multiple interfaces but wants to allow on only one interface.
212+
// being made on specific interfaces. This policy can be used when the server
213+
// is bound to multiple interfaces but wants to allow on one or more interfaces.
193214
func IgnoreProxyHeaderNotOnInterface(allowedIP net.IP) ConnPolicyFunc {
194215
return func(connOpts ConnPolicyOptions) (Policy, error) {
195216
ip, err := ipFromAddr(connOpts.Downstream)

policy_test.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,44 @@ func TestSkipProxyHeaderForCIDR(t *testing.T) {
212212
}
213213
}
214214

215+
func TestTrustProxyHeaderFrom(t *testing.T) {
216+
upstream, err := net.ResolveTCPAddr("tcp", "10.0.0.3:45738")
217+
if err != nil {
218+
t.Fatalf("err: %v", err)
219+
}
220+
221+
var cases = []struct {
222+
name string
223+
policy ConnPolicyFunc
224+
upstreamAddr net.Addr
225+
expectedPolicy Policy
226+
expectError bool
227+
}{
228+
{"reject header from untrusted source", TrustProxyHeaderFrom(net.ParseIP("192.0.2.1")), upstream, REJECT, false},
229+
{"use header from trusted load balancer", TrustProxyHeaderFrom(net.ParseIP("10.0.0.3")), upstream, USE, false},
230+
{"use header when source matches any trusted IP", TrustProxyHeaderFrom(net.ParseIP("192.0.2.1"), net.ParseIP("10.0.0.3")), upstream, USE, false},
231+
{"invalid address should return error", TrustProxyHeaderFrom(net.ParseIP("10.0.0.3")), failingAddr{}, REJECT, true},
232+
}
233+
234+
for _, tc := range cases {
235+
t.Run(tc.name, func(t *testing.T) {
236+
policy, err := tc.policy(ConnPolicyOptions{
237+
Upstream: tc.upstreamAddr,
238+
})
239+
if !tc.expectError && err != nil {
240+
t.Fatalf("err: %v", err)
241+
}
242+
if tc.expectError && err == nil {
243+
t.Fatal("Expected error, got none")
244+
}
245+
246+
if policy != tc.expectedPolicy {
247+
t.Fatalf("Expected policy %v, got %v", tc.expectedPolicy, policy)
248+
}
249+
})
250+
}
251+
}
252+
215253
func TestIgnoreProxyHeaderNotOnInterface(t *testing.T) {
216254
downstream, err := net.ResolveTCPAddr("tcp", "10.0.0.3:45738")
217255
if err != nil {
@@ -225,7 +263,7 @@ func TestIgnoreProxyHeaderNotOnInterface(t *testing.T) {
225263
expectedPolicy Policy
226264
expectError bool
227265
}{
228-
{"ignore header for requests non on interface", IgnoreProxyHeaderNotOnInterface(net.ParseIP("192.0.2.1")), downstream, IGNORE, false},
266+
{"ignore header for requests not on interface", IgnoreProxyHeaderNotOnInterface(net.ParseIP("192.0.2.1")), downstream, IGNORE, false},
229267
{"use headers for requests on interface", IgnoreProxyHeaderNotOnInterface(net.ParseIP("10.0.0.3")), downstream, USE, false},
230268
{"invalid address should return error", IgnoreProxyHeaderNotOnInterface(net.ParseIP("10.0.0.3")), failingAddr{}, REJECT, true},
231269
}
@@ -247,5 +285,4 @@ func TestIgnoreProxyHeaderNotOnInterface(t *testing.T) {
247285
}
248286
})
249287
}
250-
251288
}

0 commit comments

Comments
 (0)