Merge pull request #465 from elotreum/custom-routes

http: allow for customized routes
This commit is contained in:
mrd0ll4r 2020-01-18 11:40:37 +01:00 committed by GitHub
commit 85d646d1ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 25 deletions

View file

@ -54,6 +54,22 @@ type QueryParams struct {
infoHashes []InfoHash infoHashes []InfoHash
} }
type routeParamsKey struct{}
// RouteParamsKey is a key for the context of a request that
// contains the named parameters from the http router.
var RouteParamsKey = routeParamsKey{}
// RouteParam is a type that contains the values from the named parameters
// on the route.
type RouteParam struct {
Key string
Value string
}
// RouteParams is a collection of RouteParam instances.
type RouteParams []RouteParam
// ParseURLData parses a request URL or UDP URLData as defined in BEP41. // ParseURLData parses a request URL or UDP URLData as defined in BEP41.
// It expects a concatenated string of the request's path and query parts as // It expects a concatenated string of the request's path and query parts as
// defined in RFC 3986. As both the udp: and http: scheme used by BitTorrent // defined in RFC 3986. As both the udp: and http: scheme used by BitTorrent

View file

@ -41,15 +41,25 @@ chihaya:
# Disabling this should increase performance/decrease load. # Disabling this should increase performance/decrease load.
enable_request_timing: false enable_request_timing: false
# Whether to listen on /announce.php and /scrape.php in addition to their # An array of routes to listen on for announce requests. This is an option
# non-.php counterparts. # to support trackers that do not listen for /announce or need to listen
# This is an option for compatibility with (very) old clients or otherwise # on multiple routes.
# outdated systems. #
# This might be useful to retracker.local users, for more information see # This supports named parameters and catch-all parameters as described at
# http://rutracker.wiki/Оптимизация_обмена_битторрент_траффиком_в_локальных_сетях # https://github.com/julienschmidt/httprouter#named-parameters
# and announce_routes:
# http://rutracker.wiki/Retracker.local - "/announce"
enable_legacy_php_urls: false # - "/announce.php"
# An array of routes to listen on for scrape requests. This is an option
# to support trackers that do not listen for /scrape or need to listen
# on multiple routes.
#
# This supports named parameters and catch-all parameters as described at
# https://github.com/julienschmidt/httprouter#named-parameters
scrape_routes:
- "/scrape"
# - "/scrape.php"
# When enabled, the IP address used to connect to the tracker will not # When enabled, the IP address used to connect to the tracker will not
# override the value clients advertise as their IP address. # override the value clients advertise as their IP address.

View file

@ -16,7 +16,10 @@ chihaya:
enable_keepalive: false enable_keepalive: false
idle_timeout: 30s idle_timeout: 30s
enable_request_timing: false enable_request_timing: false
enable_legacy_php_urls: false announce_routes:
- "/announce"
scrape_routes:
- "/scrape"
allow_ip_spoofing: false allow_ip_spoofing: false
real_ip_header: "x-real-ip" real_ip_header: "x-real-ip"
max_numwant: 100 max_numwant: 100

View file

@ -16,7 +16,10 @@ chihaya:
enable_keepalive: false enable_keepalive: false
idle_timeout: 30s idle_timeout: 30s
enable_request_timing: false enable_request_timing: false
enable_legacy_php_urls: false announce_routes:
- "/announce"
scrape_routes:
- "/scrape"
allow_ip_spoofing: false allow_ip_spoofing: false
real_ip_header: "x-real-ip" real_ip_header: "x-real-ip"
max_numwant: 100 max_numwant: 100

View file

@ -29,7 +29,8 @@ type Config struct {
EnableKeepAlive bool `yaml:"enable_keepalive"` EnableKeepAlive bool `yaml:"enable_keepalive"`
TLSCertPath string `yaml:"tls_cert_path"` TLSCertPath string `yaml:"tls_cert_path"`
TLSKeyPath string `yaml:"tls_key_path"` TLSKeyPath string `yaml:"tls_key_path"`
EnableLegacyPHPURLs bool `yaml:"enable_legacy_php_urls"` AnnounceRoutes []string `yaml:"announce_routes"`
ScrapeRoutes []string `yaml:"scrape_routes"`
EnableRequestTiming bool `yaml:"enable_request_timing"` EnableRequestTiming bool `yaml:"enable_request_timing"`
ParseOptions `yaml:",inline"` ParseOptions `yaml:",inline"`
} }
@ -45,7 +46,8 @@ func (cfg Config) LogFields() log.Fields {
"enableKeepAlive": cfg.EnableKeepAlive, "enableKeepAlive": cfg.EnableKeepAlive,
"tlsCertPath": cfg.TLSCertPath, "tlsCertPath": cfg.TLSCertPath,
"tlsKeyPath": cfg.TLSKeyPath, "tlsKeyPath": cfg.TLSKeyPath,
"enableLegacyPHPURLs": cfg.EnableLegacyPHPURLs, "announceRoutes": cfg.AnnounceRoutes,
"scrapeRoutes": cfg.ScrapeRoutes,
"enableRequestTiming": cfg.EnableRequestTiming, "enableRequestTiming": cfg.EnableRequestTiming,
"allowIPSpoofing": cfg.AllowIPSpoofing, "allowIPSpoofing": cfg.AllowIPSpoofing,
"realIPHeader": cfg.RealIPHeader, "realIPHeader": cfg.RealIPHeader,
@ -154,6 +156,10 @@ func NewFrontend(logic frontend.TrackerLogic, provided Config) (*Frontend, error
return nil, errors.New("must specify addr or https_addr or both") return nil, errors.New("must specify addr or https_addr or both")
} }
if len(cfg.AnnounceRoutes) < 1 || len(cfg.ScrapeRoutes) < 1 {
return nil, errors.New("must specify routes")
}
// If TLS is enabled, create a key pair. // If TLS is enabled, create a key pair.
if cfg.TLSCertPath != "" && cfg.TLSKeyPath != "" { if cfg.TLSCertPath != "" && cfg.TLSKeyPath != "" {
var err error var err error
@ -236,15 +242,12 @@ func (f *Frontend) makeStopFunc(stopSrv *http.Server) stop.Func {
func (f *Frontend) handler() http.Handler { func (f *Frontend) handler() http.Handler {
router := httprouter.New() router := httprouter.New()
router.GET("/announce", f.announceRoute) for _, route := range f.AnnounceRoutes {
router.GET("/scrape", f.scrapeRoute) router.GET(route, f.announceRoute)
}
if f.EnableLegacyPHPURLs { for _, route := range f.ScrapeRoutes {
log.Info("http: enabling legacy PHP URLs") router.GET(route, f.scrapeRoute)
router.GET("/announce.php", f.announceRoute)
router.GET("/scrape.php", f.scrapeRoute)
} }
return router return router
} }
@ -288,8 +291,16 @@ func (f *Frontend) serveHTTPS(l net.Listener) error {
return nil return nil
} }
func injectRouteParamsToContext(ctx context.Context, ps httprouter.Params) context.Context {
rp := bittorrent.RouteParams{}
for _, p := range ps {
rp = append(rp, bittorrent.RouteParam{Key: p.Key, Value: p.Value})
}
return context.WithValue(ctx, bittorrent.RouteParamsKey, rp)
}
// announceRoute parses and responds to an Announce. // announceRoute parses and responds to an Announce.
func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
var err error var err error
var start time.Time var start time.Time
if f.EnableRequestTiming { if f.EnableRequestTiming {
@ -312,7 +323,8 @@ func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httpr
af = new(bittorrent.AddressFamily) af = new(bittorrent.AddressFamily)
*af = req.IP.AddressFamily *af = req.IP.AddressFamily
ctx, resp, err := f.logic.HandleAnnounce(context.Background(), req) ctx := injectRouteParamsToContext(context.Background(), ps)
ctx, resp, err := f.logic.HandleAnnounce(ctx, req)
if err != nil { if err != nil {
WriteError(w, err) WriteError(w, err)
return return
@ -329,7 +341,7 @@ func (f *Frontend) announceRoute(w http.ResponseWriter, r *http.Request, _ httpr
} }
// scrapeRoute parses and responds to a Scrape. // scrapeRoute parses and responds to a Scrape.
func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
var err error var err error
var start time.Time var start time.Time
if f.EnableRequestTiming { if f.EnableRequestTiming {
@ -370,7 +382,8 @@ func (f *Frontend) scrapeRoute(w http.ResponseWriter, r *http.Request, _ httprou
af = new(bittorrent.AddressFamily) af = new(bittorrent.AddressFamily)
*af = req.AddressFamily *af = req.AddressFamily
ctx, resp, err := f.logic.HandleScrape(context.Background(), req) ctx := injectRouteParamsToContext(context.Background(), ps)
ctx, resp, err := f.logic.HandleScrape(ctx, req)
if err != nil { if err != nil {
WriteError(w, err) WriteError(w, err)
return return