diff --git a/http/query/query.go b/http/query/query.go index 5e28852..bfee435 100644 --- a/http/query/query.go +++ b/http/query/query.go @@ -7,13 +7,9 @@ package query import ( "errors" - "net" - "net/http" "net/url" "strconv" "strings" - - "github.com/chihaya/chihaya/config" ) // Query represents a parsed URL.Query. @@ -94,8 +90,8 @@ func New(query string) (*Query, error) { return q, nil } -// Uint64 is a helper to obtain a uints of any base from a Query. After being -// called, you can safely cast the uint64 to your desired base. +// Uint64 is a helper to obtain a uint of any length from a Query. After being +// called, you can safely cast the uint64 to your desired length. func (q *Query) Uint64(key string) (uint64, error) { str, exists := q.Params[key] if !exists { @@ -109,89 +105,3 @@ func (q *Query) Uint64(key string) (uint64, error) { return val, nil } - -// RequestedPeerCount returns the request peer count or the provided fallback. -func (q Query) RequestedPeerCount(fallback int) int { - if numWantStr, exists := q.Params["numwant"]; exists { - numWant, err := strconv.Atoi(numWantStr) - if err != nil { - return fallback - } - return numWant - } - - return fallback -} - -func getIPs(ipstr string, ipv4, ipv6 net.IP, cfg *config.NetConfig) (net.IP, net.IP, bool) { - var done bool - - if ip := net.ParseIP(ipstr); ip != nil { - newIPv4 := ip.To4() - - if ipv4 == nil && newIPv4 != nil { - ipv4 = newIPv4 - } else if ipv6 == nil && newIPv4 == nil { - ipv6 = ip - } - } - - if cfg.DualStackedPeers { - done = ipv4 != nil && ipv6 != nil - } else { - done = ipv4 != nil || ipv6 != nil - } - - return ipv4, ipv6, done -} - -// RequestedIP returns the requested IP address from a Query. -func (q Query) RequestedIP(r *http.Request, cfg *config.NetConfig) (v4, v6 net.IP, err error) { - var done bool - - if cfg.AllowIPSpoofing { - if str, ok := q.Params["ip"]; ok { - if v4, v6, done = getIPs(str, v4, v6, cfg); done { - return - } - } - - if str, ok := q.Params["ipv4"]; ok { - if v4, v6, done = getIPs(str, v4, v6, cfg); done { - return - } - } - - if str, ok := q.Params["ipv6"]; ok { - if v4, v6, done = getIPs(str, v4, v6, cfg); done { - return - } - } - } - - if cfg.RealIPHeader != "" { - if xRealIPs, ok := q.Params[cfg.RealIPHeader]; ok { - if v4, v6, done = getIPs(string(xRealIPs[0]), v4, v6, cfg); done { - return - } - } - } else { - if r.RemoteAddr == "" { - if v4 == nil { - v4 = net.ParseIP("127.0.0.1") - } - return - } - - if idx := strings.LastIndex(r.RemoteAddr, ":"); idx != -1 { - if v4, v6, done = getIPs(r.RemoteAddr[0:idx], v4, v6, cfg); done { - return - } - } - } - - if v4 == nil && v6 == nil { - err = errors.New("failed to parse IP address") - } - return -} diff --git a/http/tracker.go b/http/tracker.go index b319c1c..659b544 100644 --- a/http/tracker.go +++ b/http/tracker.go @@ -5,7 +5,11 @@ package http import ( + "errors" + "net" "net/http" + "strconv" + "strings" "github.com/julienschmidt/httprouter" @@ -23,7 +27,7 @@ func NewAnnounce(cfg *config.Config, r *http.Request, p httprouter.Params) (*mod compact := q.Params["compact"] != "0" event, _ := q.Params["event"] - numWant := q.RequestedPeerCount(cfg.NumWantFallback) + numWant := requestedPeerCount(q, cfg.NumWantFallback) infohash, exists := q.Params["info_hash"] if !exists { @@ -35,7 +39,7 @@ func NewAnnounce(cfg *config.Config, r *http.Request, p httprouter.Params) (*mod return nil, models.ErrMalformedRequest } - ipv4, ipv6, err := q.RequestedIP(r, &cfg.NetConfig) + ipv4, ipv6, err := requestedIP(q, r, &cfg.NetConfig) if err != nil { return nil, models.ErrMalformedRequest } @@ -99,3 +103,90 @@ func NewScrape(cfg *config.Config, r *http.Request, p httprouter.Params) (*model Infohashes: q.Infohashes, }, nil } + +// requestedPeerCount returns the wanted peer count or the provided fallback. +func requestedPeerCount(q *query.Query, fallback int) int { + if numWantStr, exists := q.Params["numwant"]; exists { + numWant, err := strconv.Atoi(numWantStr) + if err != nil { + return fallback + } + return numWant + } + + return fallback +} + +// requestedIP returns the IP addresses for a request. If there are multiple +// IP addresses in the request, one IPv4 and one IPv6 will be returned. +func requestedIP(q *query.Query, r *http.Request, cfg *config.NetConfig) (v4, v6 net.IP, err error) { + var done bool + + if cfg.AllowIPSpoofing { + if str, ok := q.Params["ip"]; ok { + if v4, v6, done = getIPs(str, v4, v6, cfg); done { + return + } + } + + if str, ok := q.Params["ipv4"]; ok { + if v4, v6, done = getIPs(str, v4, v6, cfg); done { + return + } + } + + if str, ok := q.Params["ipv6"]; ok { + if v4, v6, done = getIPs(str, v4, v6, cfg); done { + return + } + } + } + + if cfg.RealIPHeader != "" { + if xRealIPs, ok := q.Params[cfg.RealIPHeader]; ok { + if v4, v6, done = getIPs(string(xRealIPs[0]), v4, v6, cfg); done { + return + } + } + } else { + if r.RemoteAddr == "" { + if v4 == nil { + v4 = net.ParseIP("127.0.0.1") + } + return + } + + if idx := strings.LastIndex(r.RemoteAddr, ":"); idx != -1 { + if v4, v6, done = getIPs(r.RemoteAddr[0:idx], v4, v6, cfg); done { + return + } + } + } + + if v4 == nil && v6 == nil { + err = errors.New("failed to parse IP address") + } + return +} + +func getIPs(ipstr string, ipv4, ipv6 net.IP, cfg *config.NetConfig) (net.IP, net.IP, bool) { + var done bool + + if ip := net.ParseIP(ipstr); ip != nil { + newIPv4 := ip.To4() + + if ipv4 == nil && newIPv4 != nil { + ipv4 = newIPv4 + } else if ipv6 == nil && newIPv4 == nil { + ipv6 = ip + } + } + + if cfg.DualStackedPeers { + done = ipv4 != nil && ipv6 != nil + } else { + done = ipv4 != nil || ipv6 != nil + } + + return ipv4, ipv6, done +} diff --git a/tracker/announce.go b/tracker/announce.go index 2ed5ca3..5c6fe09 100644 --- a/tracker/announce.go +++ b/tracker/announce.go @@ -285,7 +285,7 @@ func appendSubnetPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, annou } // Iterate over the peers twice: first add only peers in the same subnet and - // if we still need more peers grab any that haven't already been added. + // if we still need more peers grab ones that haven't already been added. count := 0 for _, checkInSubnet := range [2]bool{true, false} { for _, peer := range peers { @@ -313,7 +313,7 @@ func appendSubnetPeers(ipv4s, ipv6s models.PeerList, ann *models.Announce, annou return ipv4s, ipv6s } -// peersEquivalent checks if two peers are one in the same. +// peersEquivalent checks if two peers represent the same entity. func peersEquivalent(a, b *models.Peer) bool { return a.ID == b.ID || a.UserID != 0 && a.UserID == b.UserID }