diff --git a/cmd/chihaya/main.go b/cmd/chihaya/main.go index 6864341..cb493a3 100644 --- a/cmd/chihaya/main.go +++ b/cmd/chihaya/main.go @@ -15,6 +15,7 @@ import ( "github.com/chihaya/chihaya/server" "github.com/chihaya/chihaya/tracker" + _ "github.com/chihaya/chihaya/server/store/middleware/ip" _ "github.com/chihaya/chihaya/server/http" ) diff --git a/server/store/middleware/ip/README.md b/server/store/middleware/ip/README.md new file mode 100644 index 0000000..2a10e57 --- /dev/null +++ b/server/store/middleware/ip/README.md @@ -0,0 +1,32 @@ +## IP Blacklisting/Whitelisting Middlewares + +This package provides the announce middlewares `IPBlacklist` and `IPWhitelist` for blacklisting or whitelisting IP addresses and networks for announces. + +### `IPBlacklist` + +The `IPBlacklist` middleware uses all IP addresses and networks stored in the `IPStore` to blacklist, i.e. block announces. + +Both the IPv4 and the IPv6 addresses contained in the announce are matched against the `IPStore`. +If one or both of the two are contained in the `IPStore`, the announce will be rejected _completely_. + +### `IPWhitelist` + +The `IPWhitelist` middleware uses all IP addresses and networks stored in the `IPStore` to whitelist, i.e. allow announces. + +If present, both the IPv4 and the IPv6 addresses contained in the announce are matched against the `IPStore`. +Only if all IP address that are present in the announce are also present in the `IPStore` will the announce be allowed, otherwise it will be rejected _completely_. + +### Important things to notice + +Both middlewares operate on announce requests only. +The middlewares will check the IPv4 and IPv6 IPs a client announces to the tracker against an `IPStore`. +Normally the IP address embedded in the announce is the public IP address of the machine the client is running on. +Note however, that a client can override this behaviour by specifying an IP address in the announce itself. +_This middleware does not (dis)allow announces coming from certain IP addresses, but announces containing certain IP addresses_. +Always keep that in mind. + +Both middlewares use the same `IPStore`. +It is therefore not advised to have both the `IPBlacklist` and the `IPWhitelist` middleware running. +(If you add an IP address or network to the `IPStore`, it will be used for blacklisting and whitelisting. +If your store contains no addresses, no announces will be blocked by the blacklist, but all announces will be blocked by the whitelist. +If your store contains all addresses, no announces will be blocked by the whitelist, but all announces will be blocked by the blacklist.) \ No newline at end of file diff --git a/server/store/middleware/ip/blacklist.go b/server/store/middleware/ip/blacklist.go new file mode 100644 index 0000000..b73b02b --- /dev/null +++ b/server/store/middleware/ip/blacklist.go @@ -0,0 +1,49 @@ +// Copyright 2016 The Chihaya Authors. All rights reserved. +// Use of this source code is governed by the BSD 2-Clause license, +// which can be found in the LICENSE file. + +package ip + +import ( + "net" + + "github.com/chihaya/chihaya" + "github.com/chihaya/chihaya/config" + "github.com/chihaya/chihaya/errors" + "github.com/chihaya/chihaya/server/store" + "github.com/chihaya/chihaya/tracker" +) + +func init() { + tracker.RegisterAnnounceMiddleware("IPBlacklist", blacklistAnnounceIP) +} + +// ErrBlockedIP is returned by an announce middleware if any of the announcing +// IPs is disallowed. +var ErrBlockedIP = errors.NewMessage("disallowed IP address") + +// blacklistAnnounceIP provides a middleware that only allows IPs to announce +// that are not stored in an IPStore. +func blacklistAnnounceIP(next tracker.AnnounceHandler) tracker.AnnounceHandler { + return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) (err error) { + blacklisted := false + storage := store.MustGetStore() + + // We have to check explicitly if they are present, because someone + // could have added a net.IP to the store. + if req.IPv6 != nil && req.IPv4 != nil { + blacklisted, err = storage.HasAnyIP([]net.IP{req.IPv4, req.IPv6}) + } else if req.IPv4 != nil { + blacklisted, err = storage.HasIP(req.IPv4) + } else { + blacklisted, err = storage.HasIP(req.IPv6) + } + + if err != nil { + return err + } else if blacklisted { + return ErrBlockedIP + } + return next(cfg, req, resp) + } +} diff --git a/server/store/middleware/ip/whitelist.go b/server/store/middleware/ip/whitelist.go new file mode 100644 index 0000000..7376768 --- /dev/null +++ b/server/store/middleware/ip/whitelist.go @@ -0,0 +1,44 @@ +// Copyright 2016 The Chihaya Authors. All rights reserved. +// Use of this source code is governed by the BSD 2-Clause license, +// which can be found in the LICENSE file. + +package ip + +import ( + "net" + + "github.com/chihaya/chihaya" + "github.com/chihaya/chihaya/config" + "github.com/chihaya/chihaya/server/store" + "github.com/chihaya/chihaya/tracker" +) + +func init() { + tracker.RegisterAnnounceMiddleware("IPWhitelist", whitelistAnnounceIP) +} + +// whitelistAnnounceIP provides a middleware that only allows IPs to announce +// that are stored in an IPStore. +func whitelistAnnounceIP(next tracker.AnnounceHandler) tracker.AnnounceHandler { + return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) (err error) { + whitelisted := false + storage := store.MustGetStore() + + // We have to check explicitly if they are present, because someone + // could have added a net.IP to the store. + if req.IPv4 != nil && req.IPv6 != nil { + whitelisted, err = storage.HasAllIPs([]net.IP{req.IPv4, req.IPv6}) + } else if req.IPv4 != nil { + whitelisted, err = storage.HasIP(req.IPv4) + } else { + whitelisted, err = storage.HasIP(req.IPv6) + } + + if err != nil { + return err + } else if !whitelisted { + return ErrBlockedIP + } + return next(cfg, req, resp) + } +}