package proxy import ( "context" "net/http" "net/netip" "sneak.berlin/go/smallwebwaf/internal/lookup" ) // The headers in which the app is passed the client's AS number and // country 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, and Del removes a client's own whatever their // case; 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, a new // client's request waits for it. ctx is the request's own context. func (rq *request) lookUp(ctx context.Context) { if rq.h.config.LookupSource == "off" || !canBePlaced(rq.client) { return } if rq.h.config.LookupSource == "file" { rq.lookupAnswer = rq.h.lookupFile.LookUp(clientGroup(rq.client)) } else { rq.lookupAnswer = rq.h.geojs.LookUp(ctx, clientGroup(rq.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 in which the app is passed 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() }