139 lines
3.8 KiB
Go
139 lines
3.8 KiB
Go
package challtestsrv
|
|
|
|
import (
|
|
"net"
|
|
"strings"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// RequestEventType indicates what type of event occurred.
|
|
type RequestEventType int
|
|
|
|
const (
|
|
// HTTP requests
|
|
HTTPRequestEventType RequestEventType = iota
|
|
// DNS requests
|
|
DNSRequestEventType
|
|
// TLS-ALPN-01 requests
|
|
TLSALPNRequestEventType
|
|
)
|
|
|
|
// A RequestEvent is anything that can identify its RequestEventType and a key
|
|
// for storing the request event in the history.
|
|
type RequestEvent interface {
|
|
Type() RequestEventType
|
|
Key() string
|
|
}
|
|
|
|
// HTTPRequestEvent corresponds to an HTTP request received by a httpOneServer.
|
|
// It implements the RequestEvent interface.
|
|
type HTTPRequestEvent struct {
|
|
// The full request URL (path and query arguments)
|
|
URL string
|
|
// The Host header from the request
|
|
Host string
|
|
// Whether the request was received over HTTPS or HTTP
|
|
HTTPS bool
|
|
// The ServerName from the ClientHello. May be empty if there was no SNI or if
|
|
// the request was not HTTPS
|
|
ServerName string
|
|
// The User-Agent header from the request
|
|
UserAgent string
|
|
}
|
|
|
|
// HTTPRequestEvents always have type HTTPRequestEventType
|
|
func (e HTTPRequestEvent) Type() RequestEventType {
|
|
return HTTPRequestEventType
|
|
}
|
|
|
|
// HTTPRequestEvents use the HTTP Host as the storage key. Any explicit port
|
|
// will be removed.
|
|
func (e HTTPRequestEvent) Key() string {
|
|
if h, _, err := net.SplitHostPort(e.Host); err == nil {
|
|
return h
|
|
}
|
|
return e.Host
|
|
}
|
|
|
|
// DNSRequestEvent corresponds to a DNS request received by a dnsOneServer. It
|
|
// implements the RequestEvent interface.
|
|
type DNSRequestEvent struct {
|
|
// The DNS question received.
|
|
Question dns.Question
|
|
// The User-Agent header from the request, may be empty
|
|
// if the request was not over DoH.
|
|
UserAgent string
|
|
}
|
|
|
|
// DNSRequestEvents always have type DNSRequestEventType
|
|
func (e DNSRequestEvent) Type() RequestEventType {
|
|
return DNSRequestEventType
|
|
}
|
|
|
|
// DNSRequestEvents use the Question Name as the storage key. Any trailing `.`
|
|
// in the question name is removed.
|
|
func (e DNSRequestEvent) Key() string {
|
|
key := e.Question.Name
|
|
if strings.HasSuffix(key, ".") {
|
|
key = strings.TrimSuffix(key, ".")
|
|
}
|
|
return key
|
|
}
|
|
|
|
// TLSALPNRequestEvent corresponds to a TLS request received by
|
|
// a tlsALPNOneServer. It implements the RequestEvent interface.
|
|
type TLSALPNRequestEvent struct {
|
|
// ServerName from the TLS Client Hello.
|
|
ServerName string
|
|
// SupportedProtos from the TLS Client Hello.
|
|
SupportedProtos []string
|
|
}
|
|
|
|
// TLSALPNRequestEvents always have type TLSALPNRequestEventType
|
|
func (e TLSALPNRequestEvent) Type() RequestEventType {
|
|
return TLSALPNRequestEventType
|
|
}
|
|
|
|
// TLSALPNRequestEvents use the SNI value as the storage key
|
|
func (e TLSALPNRequestEvent) Key() string {
|
|
return e.ServerName
|
|
}
|
|
|
|
// AddRequestEvent adds a RequestEvent to the server's request history. It is
|
|
// appeneded to a list of RequestEvents indexed by the event's Type().
|
|
func (s *ChallSrv) AddRequestEvent(event RequestEvent) {
|
|
s.challMu.Lock()
|
|
defer s.challMu.Unlock()
|
|
|
|
typ := event.Type()
|
|
host := event.Key()
|
|
if s.requestHistory[host] == nil {
|
|
s.requestHistory[host] = make(map[RequestEventType][]RequestEvent)
|
|
}
|
|
s.requestHistory[host][typ] = append(s.requestHistory[host][typ], event)
|
|
}
|
|
|
|
// RequestHistory returns the server's request history for the given hostname
|
|
// and event type.
|
|
func (s *ChallSrv) RequestHistory(hostname string, typ RequestEventType) []RequestEvent {
|
|
s.challMu.RLock()
|
|
defer s.challMu.RUnlock()
|
|
|
|
if hostEvents, ok := s.requestHistory[hostname]; ok {
|
|
return hostEvents[typ]
|
|
}
|
|
return []RequestEvent{}
|
|
}
|
|
|
|
// ClearRequestHistory clears the server's request history for the given
|
|
// hostname and event type.
|
|
func (s *ChallSrv) ClearRequestHistory(hostname string, typ RequestEventType) {
|
|
s.challMu.Lock()
|
|
defer s.challMu.Unlock()
|
|
|
|
if hostEvents, ok := s.requestHistory[hostname]; ok {
|
|
hostEvents[typ] = []RequestEvent{}
|
|
}
|
|
}
|