-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsetup.go
123 lines (104 loc) · 2.64 KB
/
setup.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package scw
import (
"fmt"
"net"
"net/http"
"strings"
"github.com/caddyserver/caddy"
"github.com/caddyserver/caddy/caddyhttp/httpserver"
)
// Handler represents a middleware instance
type Handler struct {
Next httpserver.Handler
BlockedIPs *BlockedIPs
Config Config
}
var privateIPBlocks []*net.IPNet
// Init initializes the plugin
func init() {
for _, cidr := range []string{
"127.0.0.0/8", // IPv4 loopback
"10.0.0.0/8", // RFC1918
"172.16.0.0/12", // RFC1918
"192.168.0.0/16", // RFC1918
"169.254.0.0/16", // RFC3927 link-local
"::1/128", // IPv6 loopback
"fe80::/10", // IPv6 link-local
"fc00::/7", // IPv6 unique local addr
} {
_, block, err := net.ParseCIDR(cidr)
if err != nil {
panic(fmt.Errorf("parse error on %q: %v", cidr, err))
}
privateIPBlocks = append(privateIPBlocks, block)
}
caddy.RegisterPlugin("scw", caddy.Plugin{
ServerType: "http",
Action: setup,
})
}
func isPrivateIP(ip net.IP) bool {
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
return true
}
for _, block := range privateIPBlocks {
if block.Contains(ip) {
return true
}
}
return false
}
func setup(c *caddy.Controller) error {
config, err := parseConfig(c)
if err != nil {
return err
}
blip, err := NewBlockedIPs(config.RedisURI, config.UpdateInterval)
if err != nil {
return c.Err("scw: Can't connect to redis: " + config.RedisURI)
}
// Create new middleware
newMiddleWare := func(next httpserver.Handler) httpserver.Handler {
return &Handler{
Next: next,
BlockedIPs: blip,
Config: config,
}
}
// Add middleware
cfg := httpserver.GetConfig(c)
cfg.AddMiddleware(newMiddleWare)
return nil
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
h.lookupIP(w, r)
return h.Next.ServeHTTP(w, r)
}
func (h Handler) lookupIP(w http.ResponseWriter, r *http.Request) {
replacer := newReplacer(r)
isBlocked := false
rip := r.RemoteAddr[0:strings.Index(r.RemoteAddr, ":")]
if !isPrivateIP(net.ParseIP(rip)) && h.BlockedIPs.IsBlocked(rip, true) {
isBlocked = true
}
OUTER:
for _, xff := range r.Header.Values("X-Forwarded-For") {
for _, ip := range strings.Split(xff, ",") {
rip = ip[0:strings.Index(strings.TrimSpace(ip), ":")]
if !isPrivateIP(net.ParseIP(rip)) && h.BlockedIPs.IsBlocked(rip, true) {
isBlocked = true
break OUTER
}
}
}
if !isBlocked {
return
}
replacer.Set("scw_is_blocked", "true")
if rr, ok := w.(*httpserver.ResponseRecorder); ok {
rr.Replacer = replacer
}
}
func newReplacer(r *http.Request) httpserver.Replacer {
return httpserver.NewReplacer(r, nil, "")
}