Might be used when tracker is behind reverse proxy and one of provided addresses in `real_ip_header` is private/local address. Additional changes: * check if provided address is not multicast/broadcast * configure `http.Server.ReadHeaderTimeout` with `http.ReadTimeout` to mitigate Slowloris * update dependencies * minor docs fixes
5.3 KiB
Frontends
A Frontend is a component of MoChi that serves a BitTorrent tracker on one protocol. The frontend accepts, parses and sanitizes requests, passes them to the Logic and writes responses to Clients.
This documentation first gives a high-level overview of Frontends and later goes into implementation specifics. Users of MoChi are expected to just read the first part - developers should read both.
Functionality
A Frontend serves one protocol, for example HTTP (BEP 3) or UDP (BEP 15). It listens for requests and usually answers each of them with one response, a basic overview of the control flow is:
- Read the request.
- Parse the request.
- Have the Logic handle the request. This calls a series of
PreHooks. - Send a response to the Client.
- Process the request and response through
PostHooks.
Available Frontends
MoChi ships with frontends for HTTP(S) and UDP. The HTTP frontend uses Go's http package. The UDP frontend
implements both old-opentracker-style IPv6 and the IPv6 support specified in BEP 15. The advantage of the old
opentracker style is that it contains a usable IPv6 ip field, to enable IP overrides in announces.
Implementing a Frontend
This part is intended for developers.
Implementation Specifics
A frontend should serve only one protocol. It may serve that protocol on multiple transports or networks, if applicable.
An example of that is the http Frontend, operating both on HTTP and HTTPS.
The typical control flow of handling announces, in more detail, is:
- Read the request.
- Parse the request, if invalid go to 9.
- Validate/sanitize the request, if invalid go to 9.
- If the request is protocol-specific, handle, respond, and go to 8.
- Pass the request to the
TrackerLogic'sHandleAnnounceorHandleScrapemethod, if an error is returned go to 9. - Send the response to the Client.
- Pass the request and response to the
TrackerLogic'sAfterAnnounceorAfterScrapemethod. - Finish, accept next request.
- For invalid requests or errors during processing: Send an error response to the client. This step may be skipped for suspected denial-of-service attacks. The error response may contain information about the cause of the error. Only errors where the Client is at fault should be explained, internal server errors should be returned without explanation. Then finish, and accept the next request.
Configuration
The frontend must be configurable using a single, exported struct. The struct must have YAML annotations. The struct
must implement zerolog.LogObjectMarshaler to be logged on startup.
Metrics
Frontends may provide runtime metrics, such as the number of requests or their duration. Metrics must be reported using Prometheus.
A frontend should provide at least the following metrics:
- The number of valid and invalid requests handled
- The average time it takes to handle a single request. This request timing should be made optional using a config entry.
Requests should be separated by type, i.e. Scrapes, Announces, and other protocol-specific requests. If the frontend serves multiple transports or networks, metrics for them should be separable.
It is recommended to publish one Prometheus HistogramVec with:
- A name like
mochi_PROTOCOL_response_duration_milliseconds - A value holding the duration in milliseconds of the reported request
- Labels for:
action(=announce,scrape, ...)address_family(=Unknown,IPv4,IPv6, ...), if applicableerror(= A textual representation of the error encountered during processing.) Becauseerroris expected to hold the textual representation of any error that occurred during the request, great care must be taken to ensure all error messages are static.errormust not contain any information directly taken from the request, e.g. the value of an invalid parameter. This would cause this dimension of prometheus to explode, which slows down prometheus clients and reporters.
Error Handling
Frontends should return bittorrent.ClientErrors to the Client. Frontends must not return errors that are not
a bittorrent.ClientError to the Client. A message like internal server error should be used instead.
Request Sanitization
The TrackerLogic expects sanitized requests in order to function properly.
The bittorrent package provides the SanitizeAnnounce and SanitizeScrape functions to sanitize Announces and
Scrapes, respectively. This is the minimal required sanitization, every AnnounceRequest and ScrapeRequest must be
sanitized this way.
Note that the AnnounceRequest struct contains booleans of the form XProvided, where X denotes an optional
parameter of the BitTorrent protocol. These should be set according to the values received by the Client.
Contexts
All methods of the TrackerLogic interface expect a context.Context as a parameter. After a request is handled
by HandleAnnounce without errors, the populated context returned must be used to call AfterAnnounce. The same
applies to Scrapes. This way, a PreHook can communicate with a PostHook by setting a context value.