-
Notifications
You must be signed in to change notification settings - Fork 343
/
source.go
96 lines (74 loc) · 2.33 KB
/
source.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/*
Package source implements a custom predicate to match routes
based on the source IP of a request.
It is similar in function and usage to the header predicate but
has explicit support for IP adresses and netmasks to conveniently
create routes based on a whole network of adresses, like a company
network or something similar.
It is important to note, that this predicate should not be used as
the only gatekeeper for secure endpoints. Always use proper authorization
and authentication for access control!
To enable usage of this predicate behind loadbalancers or proxies, the
X-Forwared-For header is used to determine the source of a request if it
is available. If the X-Forwarded-For header is not present or does not contain
a valid source address, the source IP of the incoming request is used for
matching.
The source predicate supports one or more IP addresses with or without a netmask.
Examples:
// only match requests from 1.2.3.4
example1: Source("1.2.3.4") -> "http://example.org";
// only match requests from 1.2.3.0 - 1.2.3.255
example2: Source("1.2.3.0/24") -> "http://example.org";
// only match requests from 1.2.3.4 and the 2.2.2.0/24 network
example3: Source("1.2.3.4", "2.2.2.0/24") -> "http://example.org";
*/
package source
import (
"errors"
snet "github.com/zalando/skipper/net"
"github.com/zalando/skipper/routing"
"net"
"net/http"
"strings"
)
const Name = "Source"
var InvalidArgsError = errors.New("invalid arguments")
type spec struct{}
type predicate struct {
acceptedSourceNets []net.IPNet
}
func New() routing.PredicateSpec { return &spec{} }
func (s *spec) Name() string {
return Name
}
func (s *spec) Create(args []interface{}) (routing.Predicate, error) {
if len(args) == 0 {
return nil, InvalidArgsError
}
p := &predicate{}
for i := range args {
if s, ok := args[i].(string); ok {
var netmask = s
if !strings.Contains(s, "/") {
netmask = s + "/32"
}
_, net, err := net.ParseCIDR(netmask)
if err != nil {
return nil, InvalidArgsError
}
p.acceptedSourceNets = append(p.acceptedSourceNets, *net)
} else {
return nil, InvalidArgsError
}
}
return p, nil
}
func (p *predicate) Match(r *http.Request) bool {
src := snet.RemoteHost(r)
for _, acceptedNet := range p.acceptedSourceNets {
if acceptedNet.Contains(src) {
return true
}
}
return false
}