frontend/udp: add request sanitization

This commit is contained in:
Jimmy Zelinskie 2017-10-08 17:35:50 -04:00
parent 6dee48ce17
commit 47b5e67345
2 changed files with 46 additions and 23 deletions

View file

@ -70,8 +70,8 @@ type Config struct {
Addr string `yaml:"addr"`
PrivateKey string `yaml:"private_key"`
MaxClockSkew time.Duration `yaml:"max_clock_skew"`
AllowIPSpoofing bool `yaml:"allow_ip_spoofing"`
EnableRequestTiming bool `yaml:"enable_request_timing"`
ParseOptions `yaml:",inline"`
}
// LogFields renders the current config as a set of Logrus fields.
@ -80,8 +80,11 @@ func (cfg Config) LogFields() log.Fields {
"addr": cfg.Addr,
"privateKey": cfg.PrivateKey,
"maxClockSkew": cfg.MaxClockSkew,
"allowIPSpoofing": cfg.AllowIPSpoofing,
"enableRequestTiming": cfg.EnableRequestTiming,
"allowIPSpoofing": cfg.AllowIPSpoofing,
"maxNumWant": cfg.MaxNumWant,
"defaultNumWant": cfg.DefaultNumWant,
"maxScrapeInfohashes": cfg.MaxScrapeInfoHashes,
}
}
@ -278,7 +281,7 @@ func (t *Frontend) handleRequest(r Request, w ResponseWriter) (actionName string
actionName = "announce"
var req *bittorrent.AnnounceRequest
req, err = ParseAnnounce(r, t.AllowIPSpoofing, actionID == announceV6ActionID)
req, err = ParseAnnounce(r, actionID == announceV6ActionID, t.ParseOptions)
if err != nil {
WriteError(w, txID, err)
return
@ -302,7 +305,7 @@ func (t *Frontend) handleRequest(r Request, w ResponseWriter) (actionName string
actionName = "scrape"
var req *bittorrent.ScrapeRequest
req, err = ParseScrape(r)
req, err = ParseScrape(r, t.ParseOptions)
if err != nil {
WriteError(w, txID, err)
return

View file

@ -45,14 +45,19 @@ var (
errUnknownOptionType = bittorrent.ClientError("unknown option type")
)
// ParseOptions is the configuration used to parse an Announce Request.
//
// If AllowIPSpoofing is true, IPs provided via params will be used.
type ParseOptions struct {
AllowIPSpoofing bool `yaml:"allowIPSpoofing"`
bittorrent.RequestSanitizer `yaml:",inline"`
}
// ParseAnnounce parses an AnnounceRequest from a UDP request.
//
// If allowIPSpoofing is true, IPs provided via params will be used.
//
// If v6 is true the announce will be parsed as an IPv6 announce "the
// opentracker way", see
// If v6 is true, the announce is parsed the "opentracker way":
// http://opentracker.blog.h3q.com/2007/12/28/the-ipv6-situation/
func ParseAnnounce(r Request, allowIPSpoofing, v6 bool) (*bittorrent.AnnounceRequest, error) {
func ParseAnnounce(r Request, v6 bool, opts ParseOptions) (*bittorrent.AnnounceRequest, error) {
ipEnd := 84 + net.IPv4len
if v6 {
ipEnd = 84 + net.IPv6len
@ -74,12 +79,14 @@ func ParseAnnounce(r Request, allowIPSpoofing, v6 bool) (*bittorrent.AnnounceReq
}
ip := r.IP
ipProvided := false
ipbytes := r.Packet[84:ipEnd]
if allowIPSpoofing {
if opts.AllowIPSpoofing {
// Make sure the bytes are copied to a new slice.
copy(ip, net.IP(ipbytes))
ipProvided = true
}
if !allowIPSpoofing && r.IP == nil {
if !opts.AllowIPSpoofing && r.IP == nil {
// We have no IP address to fallback on.
return nil, errMalformedIP
}
@ -92,20 +99,29 @@ func ParseAnnounce(r Request, allowIPSpoofing, v6 bool) (*bittorrent.AnnounceReq
return nil, err
}
return &bittorrent.AnnounceRequest{
Event: eventIDs[eventID],
InfoHash: bittorrent.InfoHashFromBytes(infohash),
NumWant: uint32(numWant),
Left: left,
Downloaded: downloaded,
Uploaded: uploaded,
request := &bittorrent.AnnounceRequest{
Event: eventIDs[eventID],
InfoHash: bittorrent.InfoHashFromBytes(infohash),
NumWant: uint32(numWant),
Left: left,
Downloaded: downloaded,
Uploaded: uploaded,
IPProvided: ipProvided,
NumWantProvided: true,
EventProvided: true,
Peer: bittorrent.Peer{
ID: bittorrent.PeerIDFromBytes(peerID),
IP: bittorrent.IP{IP: ip},
Port: port,
},
Params: params,
}, nil
}
if err := opts.SanitizeAnnounce(request); err != nil {
return nil, err
}
return request, nil
}
type buffer struct {
@ -170,7 +186,7 @@ func handleOptionalParameters(packet []byte) (bittorrent.Params, error) {
}
// ParseScrape parses a ScrapeRequest from a UDP request.
func ParseScrape(r Request) (*bittorrent.ScrapeRequest, error) {
func ParseScrape(r Request, opts ParseOptions) (*bittorrent.ScrapeRequest, error) {
// If a scrape isn't at least 36 bytes long, it's malformed.
if len(r.Packet) < 36 {
return nil, errMalformedPacket
@ -190,7 +206,11 @@ func ParseScrape(r Request) (*bittorrent.ScrapeRequest, error) {
r.Packet = r.Packet[20:]
}
return &bittorrent.ScrapeRequest{
InfoHashes: infohashes,
}, nil
// Sanitize the request.
request := &bittorrent.ScrapeRequest{InfoHashes: infohashes}
if err := opts.SanitizeScrape(request); err != nil {
return nil, err
}
return request, nil
}