Rename internal/proxy to internal/servewaf (closes #173)
check / check (push) Successful in 3m57s

The package passes nothing to an app since rproxy took that over, so it
is named after the command it serves. The rproxy tests call their
stand-in for servewaf standIn, since a local servewaf would hide the
package. No change of behaviour.

Model: opus-5-5
This commit is contained in:
2026-11-06 18:00:32 +00:00
parent 6deb9d7581
commit 6acde5c3bc
50 changed files with 488 additions and 484 deletions
+78
View File
@@ -0,0 +1,78 @@
package servewaf
import (
"context"
"net/http"
"net/netip"
"time"
"sneak.berlin/go/smallwebwaf/internal/lookup"
)
// The headers in which an answer of allow gives rproxy the client's AS number
// and country, for the app, while SWWAF_ADD_LOOKUP_HEADERS is set. Go writes
// every header name in this form, as it sends it and as it receives it, so
// X-Client-ASN arrives as X-Client-Asn; header names are not case-sensitive.
const (
asnHeader = "X-Client-Asn"
countryHeader = "X-Client-Country"
)
// lookUp looks up the client's AS number and country, in the lookup
// database or through GeoJS, and notes them for the log line, unless
// SWWAF_LOOKUP_SOURCE is off or the client is on a private, loopback or
// link-local address, which no lookup can place. The lookup database
// answers at once. With GeoJS, while a setting needs the answer, such as a
// country list or a biased threshold, a new client's request waits for it,
// unless refusedWhateverTheAnswer reports true. ctx is the request's own
// context.
func (rq *request) lookUp(ctx context.Context, now time.Time) {
if rq.h.config.LookupSource == "off" || !canBePlaced(rq.client) {
return
}
client := rq.h.clientGroup(rq.client)
switch {
case rq.h.config.LookupSource == "file":
rq.lookupAnswer = rq.h.lookupFile.LookUp(client)
case rq.refusedWhateverTheAnswer(now):
rq.lookupAnswer = rq.h.geojs.LookUpWithoutWaiting(ctx, client)
rq.skippedLookupWait = rq.lookupAnswer.Answered.IsZero()
default:
rq.lookupAnswer = rq.h.geojs.LookUp(ctx, client)
}
rq.lookedUp = true
rq.line.ASN = rq.lookupAnswer.ASN
rq.line.ASName = rq.lookupAnswer.ASName
rq.line.Country = rq.lookupAnswer.Country
}
// addLookup adds answer, an answer about a client from the lookup
// database or GeoJS, to the client's history, and to the notes of the bans
// on its netblock that have no AS number, AS name or country yet.
func (h *handler) addLookup(answer lookup.Answer) {
h.limiter.AddLookup(answer.Client, answer.Answered,
answer.ASN, answer.ASName, answer.Country)
h.ledger.AddLookup(h.netblock(answer.Client.Addr()),
answer.ASN, answer.ASName, answer.Country)
}
// setLookupHeaders sets the headers that give the client's AS number and
// country, leaving out one that is unknown.
func setLookupHeaders(header http.Header, asn, country string) {
if asn != "" {
header.Set(asnHeader, asn)
}
if country != "" {
header.Set(countryHeader, country)
}
}
// canBePlaced reports whether a lookup can place addr: private, loopback
// and link-local addresses have no AS number or country.
func canBePlaced(addr netip.Addr) bool {
return !addr.IsPrivate() && !addr.IsLoopback() && !addr.IsLinkLocalUnicast()
}