Skip to content

Commit 815bf2b

Browse files
authored
feat: flag to allow blacklisting CIDR ranges (#2589)
* feat: flag to allow blacklisting CIDR ranges
1 parent ebcb9f1 commit 815bf2b

14 files changed

Lines changed: 175 additions & 66 deletions

File tree

client/v1/client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"io"
1111
"io/ioutil"
12+
"net"
1213
"net/http"
1314
"net/http/httptest"
1415
"net/url"
@@ -450,6 +451,10 @@ func New(conf Config) (*Client, error) {
450451
if rt == nil {
451452
tr = khttp.NewDefaultTransportWithTLS(&tls.Config{
452453
InsecureSkipVerify: conf.InsecureSkipVerify,
454+
}, &net.Dialer{
455+
Timeout: 30 * time.Second,
456+
KeepAlive: 30 * time.Second,
457+
Control: khttp.Control(khttp.DefaultValidator),
453458
})
454459
if conf.TLSConfig != nil {
455460
tr.TLSClientConfig = conf.TLSConfig

cmd/kapacitord/run/command.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import (
1212
"strings"
1313

1414
"github.com/BurntSushi/toml"
15+
furl "github.com/influxdata/flux/dependencies/url"
1516
"github.com/influxdata/flux/fluxinit"
17+
khttp "github.com/influxdata/kapacitor/http"
1618
"github.com/influxdata/kapacitor/server"
1719
"github.com/influxdata/kapacitor/services/diagnostic"
1820
)
@@ -104,6 +106,18 @@ func (cmd *Command) Run(args ...string) error {
104106
if options.LogLevel != "" {
105107
config.Logging.Level = options.LogLevel
106108
}
109+
110+
switch options.BlackListCIDRS {
111+
case "":
112+
khttp.DefaultValidator = furl.PassValidator{}
113+
case "private":
114+
khttp.DefaultValidator = furl.PrivateIPValidator{}
115+
default:
116+
if khttp.DefaultValidator, err = khttp.ParseCIDRsString(options.BlackListCIDRS); err != nil {
117+
return fmt.Errorf("flag error: improper CIDRs: %s", err)
118+
}
119+
}
120+
107121
// Initialize Logging Services
108122
cmd.diagService = diagnostic.NewService(config.Logging, cmd.Stdout, cmd.Stderr)
109123
if err := cmd.diagService.Open(); err != nil {
@@ -197,6 +211,7 @@ func (cmd *Command) ParseFlags(args ...string) (Options, error) {
197211
fs.StringVar(&options.MemProfile, "memprofile", "", "")
198212
fs.StringVar(&options.LogFile, "log-file", "", "")
199213
fs.StringVar(&options.LogLevel, "log-level", "", "")
214+
fs.StringVar(&options.BlackListCIDRS, "blacklist-cidrs", "", "")
200215
fs.StringVar(&options.DisabledAlertHandlers, "disable-handlers", "", "")
201216
fs.Usage = func() { fmt.Fprintln(cmd.Stderr, usage) }
202217
if err := fs.Parse(args); err != nil {
@@ -248,10 +263,18 @@ func (cmd *Command) ParseConfig(path string) (*server.Config, error) {
248263
var usage = `usage: run [flags]
249264
250265
run starts the Kapacitor server.
266+
-blacklist-cidrs <CIDR1,CIDR2,...>
267+
Comma seperated list of CIDRs to blacklist for
268+
most http get/post operations
251269
252270
-config <path>
253271
Set the path to the configuration file.
254272
273+
-disable-handlers <comma-separated list of alert-handlers>
274+
Disables certain alert handlers. This is useful for
275+
security, reasons. For example: disabling exec on
276+
a shared system.
277+
255278
-hostname <name>
256279
Override the hostname, the 'hostname' configuration
257280
option will be overridden.
@@ -265,8 +288,6 @@ run starts the Kapacitor server.
265288
-log-level <level>
266289
Sets the log level. One of debug,info,error.
267290
268-
-disable-handlers <comma-separated list of alert-handlers>
269-
Disables certain alert handlers. This is useful for security, reasons. For example: disabling exec on a shared system.
270291
`
271292

272293
// Options represents the command line options that can be parsed.
@@ -279,4 +300,5 @@ type Options struct {
279300
LogFile string
280301
LogLevel string
281302
DisabledAlertHandlers string
303+
BlackListCIDRS string
282304
}

http/transport.go

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,32 @@ package http
22

33
import (
44
"crypto/tls"
5+
"fmt"
56
"net"
67
"net/http"
8+
"net/url"
9+
"strings"
10+
"syscall"
711
"time"
12+
13+
furl "github.com/influxdata/flux/dependencies/url"
814
)
915

1016
// NewDefaultTransport creates a new transport with sane defaults.
11-
func NewDefaultTransport() *http.Transport {
12-
// These defaults are copied from http.DefaultTransport.
13-
return &http.Transport{
14-
Proxy: http.ProxyFromEnvironment,
15-
DialContext: (&net.Dialer{
17+
func NewDefaultTransport(dialer *net.Dialer) *http.Transport {
18+
19+
if dialer == nil {
20+
dialer = &net.Dialer{
1621
Timeout: 30 * time.Second,
1722
KeepAlive: 30 * time.Second,
1823
DualStack: true,
19-
}).DialContext,
24+
}
25+
}
26+
27+
// These defaults are copied from http.DefaultTransport.
28+
return &http.Transport{
29+
Proxy: http.ProxyFromEnvironment,
30+
DialContext: (dialer).DialContext,
2031
MaxIdleConns: 100,
2132
IdleConnTimeout: 90 * time.Second,
2233
TLSHandshakeTimeout: 10 * time.Second,
@@ -27,8 +38,93 @@ func NewDefaultTransport() *http.Transport {
2738
}
2839

2940
// NewDefaultTransportWithTLS creates a new transport with the specified TLS configuration.
30-
func NewDefaultTransportWithTLS(tlsConfig *tls.Config) *http.Transport {
31-
t := NewDefaultTransport()
41+
func NewDefaultTransportWithTLS(tlsConfig *tls.Config, dialer *net.Dialer) *http.Transport {
42+
t := NewDefaultTransport(dialer)
3243
t.TLSClientConfig = tlsConfig
3344
return t
3445
}
46+
47+
// Control is called after DNS lookup, but before the network connection is
48+
// initiated.
49+
func Control(urlValidator furl.Validator) func(network, address string, c syscall.RawConn) error {
50+
return func(network, address string, c syscall.RawConn) error {
51+
host, _, err := net.SplitHostPort(address)
52+
if err != nil {
53+
return err
54+
}
55+
56+
ip := net.ParseIP(host)
57+
return urlValidator.ValidateIP(ip)
58+
}
59+
}
60+
61+
// NewDefaultClientWithTLS creates a tls client with sane defaults.
62+
func NewDefaultClientWithTLS(tlsConfig *tls.Config, urlValidator furl.Validator) *http.Client {
63+
64+
// These defaults are copied from http.DefaultTransport.
65+
return &http.Client{
66+
Transport: NewDefaultTransportWithTLS(tlsConfig, &net.Dialer{
67+
Timeout: 30 * time.Second,
68+
KeepAlive: 30 * time.Second,
69+
Control: Control(urlValidator),
70+
}),
71+
Timeout: 30 * time.Second,
72+
}
73+
}
74+
75+
// NewDefaultClient creates a client with sane defaults.
76+
func NewDefaultClient(urlValidator furl.Validator) *http.Client {
77+
78+
// These defaults are copied from http.DefaultTransport.
79+
return &http.Client{
80+
Transport: NewDefaultTransport(&net.Dialer{
81+
Timeout: 30 * time.Second,
82+
KeepAlive: 30 * time.Second,
83+
Control: Control(urlValidator),
84+
// DualStack is deprecated
85+
}),
86+
}
87+
}
88+
89+
// DefaultValidator is the default validator, it can be replaced at start time with a different validator
90+
var DefaultValidator furl.Validator = furl.PassValidator{}
91+
92+
type cidrValidator struct {
93+
cidrs []*net.IPNet
94+
}
95+
96+
func (v cidrValidator) Validate(u *url.URL) error {
97+
ips, err := net.LookupIP(u.Hostname())
98+
if err != nil {
99+
return err
100+
}
101+
for _, ip := range ips {
102+
err = v.ValidateIP(ip)
103+
if err != nil {
104+
return err
105+
}
106+
}
107+
return nil
108+
}
109+
110+
func (v cidrValidator) ValidateIP(ip net.IP) error {
111+
for i := range v.cidrs {
112+
if v.cidrs[i].Contains(ip) {
113+
return fmt.Errorf("ip '%s' is blacklisted", ip)
114+
}
115+
}
116+
return nil
117+
}
118+
119+
func ParseCIDRsString(s string) (furl.Validator, error) {
120+
cidrStrings := strings.Split(s, ",")
121+
cidrs := make([]*net.IPNet, 0, len(cidrStrings))
122+
for i := range cidrStrings {
123+
_, cidr, err := net.ParseCIDR(cidrStrings[i])
124+
if err != nil {
125+
return nil, err
126+
}
127+
cidrs = append(cidrs, cidr)
128+
}
129+
return cidrValidator{cidrs: cidrs}, nil
130+
}

influxdb/client.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"io"
1010
"io/ioutil"
11+
"net"
1112
"net/http"
1213
"net/url"
1314
"strconv"
@@ -157,8 +158,21 @@ func NewHTTPClient(conf Config) (*HTTPClient, error) {
157158
return nil, errors.Wrap(err, "invalid URLs")
158159
}
159160
if conf.Transport == nil {
160-
conf.Transport = khttp.NewDefaultTransport()
161+
conf.Transport = khttp.NewDefaultTransport(&net.Dialer{
162+
Timeout: 30 * time.Second, // I am not sure if this is the right value to set it to
163+
KeepAlive: 30 * time.Second, // I am not sure if this is the right value to set it to
164+
Control: khttp.Control(khttp.DefaultValidator),
165+
// DualStack is deprecated
166+
})
161167
}
168+
169+
conf.Transport.DialContext = (&net.Dialer{
170+
Timeout: 30 * time.Second, // I am not sure if this is the right value to set it to
171+
KeepAlive: 30 * time.Second, // I am not sure if this is the right value to set it to
172+
Control: khttp.Control(khttp.DefaultValidator),
173+
// DualStack is deprecated
174+
}).DialContext
175+
162176
c := &HTTPClient{
163177
config: conf,
164178
urls: urls,
@@ -243,6 +257,12 @@ func (c *HTTPClient) Update(new Config) error {
243257
if tr == nil {
244258
tr = old.Transport
245259
}
260+
tr.DialContext = (&net.Dialer{
261+
Timeout: 30 * time.Second, // I am not sure if this is the right value to set it to
262+
KeepAlive: 30 * time.Second, // I am not sure if this is the right value to set it to
263+
Control: khttp.Control(khttp.DefaultValidator),
264+
// DualStack is deprecated
265+
}).DialContext
246266
c.client = &http.Client{
247267
Timeout: new.Timeout,
248268
Transport: tr,

services/alerta/service.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,8 @@ func NewService(c Config, d Diagnostic) *Service {
4545
diag: d,
4646
}
4747
s.configValue.Store(c)
48-
s.clientValue.Store(&http.Client{
49-
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
50-
})
48+
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))
49+
5150
return s
5251
}
5352

@@ -128,9 +127,7 @@ func (s *Service) Update(newConfig []interface{}) error {
128127
return fmt.Errorf("expected config object to be of type %T, got %T", c, newConfig[0])
129128
} else {
130129
s.configValue.Store(c)
131-
s.clientValue.Store(&http.Client{
132-
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
133-
})
130+
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))
134131
}
135132

136133
return nil

services/bigpanda/service.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ func NewService(c Config, d Diagnostic) (*Service, error) {
4040
diag: d,
4141
}
4242
s.configValue.Store(c)
43-
s.clientValue.Store(&http.Client{
44-
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
45-
})
43+
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))
4644

4745
return s, nil
4846
}
@@ -67,9 +65,7 @@ func (s *Service) Update(newConfig []interface{}) error {
6765
return fmt.Errorf("expected config object to be of type %T, got %T", c, newConfig[0])
6866
} else {
6967
s.configValue.Store(c)
70-
s.clientValue.Store(&http.Client{
71-
Transport: khttp.NewDefaultTransportWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}),
72-
})
68+
s.clientValue.Store(khttp.NewDefaultClientWithTLS(&tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}, khttp.DefaultValidator))
7369
}
7470
return nil
7571
}

services/discord/service.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,9 @@ func NewWorkspace(c Config) (*Workspace, error) {
3939
return nil, err
4040
}
4141

42-
cl := &http.Client{
43-
Transport: khttp.NewDefaultTransportWithTLS(tlsConfig),
44-
}
45-
4642
return &Workspace{
4743
config: c,
48-
client: cl,
44+
client: khttp.NewDefaultClientWithTLS(tlsConfig, khttp.DefaultValidator),
4945
}, nil
5046
}
5147

@@ -67,11 +63,7 @@ func (w *Workspace) Update(c Config) error {
6763
return err
6864
}
6965

70-
cl := &http.Client{
71-
Transport: khttp.NewDefaultTransportWithTLS(tlsConfig),
72-
}
73-
74-
w.client = cl
66+
w.client = khttp.NewDefaultClientWithTLS(tlsConfig, khttp.DefaultValidator)
7567
w.config = c
7668

7769
return nil

services/httppost/service.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,7 @@ func (h *handler) Handle(event alert.Event) {
369369
}
370370
}
371371

372-
httpClient := &http.Client{
373-
Transport: khttp.NewDefaultTransportWithTLS(tlsConfig),
374-
}
372+
httpClient := khttp.NewDefaultClientWithTLS(tlsConfig, khttp.DefaultValidator)
375373

376374
// Execute the request
377375
resp, err := httpClient.Do(req)

services/influxdb/service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ func httpConfig(c Config) (influxdb.Config, error) {
504504
if err != nil {
505505
return influxdb.Config{}, errors.Wrap(err, "invalid TLS options")
506506
}
507-
tr := khttp.NewDefaultTransportWithTLS(tlsConfig)
507+
tr := khttp.NewDefaultTransportWithTLS(tlsConfig, nil)
508508
var credentials influxdb.Credentials
509509
if c.Token != "" {
510510
credentials = influxdb.Credentials{

services/k8s/client/client.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,7 @@ func New(c Config) (Client, error) {
123123
return &httpClient{
124124
config: c,
125125
urls: urls,
126-
client: &http.Client{
127-
Transport: khttp.NewDefaultTransportWithTLS(c.TLSConfig),
128-
},
126+
client: khttp.NewDefaultClientWithTLS(c.TLSConfig, khttp.DefaultValidator),
129127
}, nil
130128
}
131129

@@ -165,9 +163,7 @@ func (c *httpClient) Update(new Config) error {
165163
c.urls = urls
166164

167165
if old.TLSConfig != new.TLSConfig {
168-
c.client = &http.Client{
169-
Transport: khttp.NewDefaultTransportWithTLS(new.TLSConfig),
170-
}
166+
c.client = khttp.NewDefaultClientWithTLS(new.TLSConfig, khttp.DefaultValidator)
171167
}
172168
return nil
173169
}

0 commit comments

Comments
 (0)