Compare commits

...

2 Commits

Author SHA1 Message Date
spiritlhl
cf9cd92651 Merge remote-tracking branch 'origin/main'
Some checks are pending
Sync ASN metadata / sync (push) Waiting to run
2026-08-06 21:09:06 +08:00
spiritlhl
e668455b46 fix: hide remote registry endpoints 2026-08-06 21:08:55 +08:00
4 changed files with 46 additions and 11 deletions

View File

@ -54,13 +54,13 @@ func TestStructuredReportErrorsDoNotExposeRemoteURLs(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
for _, forbidden := range []string{"token=", "key=", "secret", "userinfo@"} { for _, forbidden := range []string{"private.example", "token=", "key=", "secret", "userinfo@", `"geofeed_urls"`, `"port43"`, `"server"`, `"url"`} {
if strings.Contains(string(encoded), forbidden) { if strings.Contains(string(encoded), forbidden) {
t.Fatalf("structured report leaked %q: %s", forbidden, encoded) t.Fatalf("structured report leaked %q: %s", forbidden, encoded)
} }
} }
if report.RDAP == nil || len(report.RDAP.GeofeedURLs) != 1 || report.RDAP.GeofeedURLs[0] != "https://private.example/geofeed" || report.Geofeeds[0].URL != "https://private.example/geofeed" { if report.RDAP == nil || len(report.RDAP.GeofeedURLs) != 1 || report.Geofeeds[0].Status != ReportError {
t.Fatalf("geofeed URL was not sanitized consistently: %+v", report) t.Fatalf("internal geofeed processing was not preserved: %+v", report)
} }
} }
@ -95,3 +95,38 @@ func TestRemoteFetchErrorsDoNotExposeSourceURL(t *testing.T) {
}) })
} }
} }
func TestStructuredReportOmitsServiceLocationsButKeepsProbeEvidence(t *testing.T) {
report := IPBGPReport{
Status: ReportPartial,
RDAP: &RDAPRecord{
Port43: "whois.private.example:43",
GeofeedURLs: []string{"https://private.example/rdap-geofeed.csv"},
},
WHOIS: &WHOISRecord{
Server: "whois.private.example:43",
Status: ReportAvailable,
GeofeedURLs: []string{"https://private.example/whois-geofeed.csv"},
},
Geofeeds: []GeofeedResult{{
URL: "https://private.example/geofeed.csv",
Status: ReportAvailable,
HTTPStatus: http.StatusOK,
Bytes: 128,
}},
}
encoded, err := json.Marshal(report)
if err != nil {
t.Fatal(err)
}
for _, forbidden := range []string{"private.example", "whois.private", `"geofeed_urls"`, `"port43"`, `"server"`, `"url"`} {
if strings.Contains(string(encoded), forbidden) {
t.Fatalf("structured report leaked %q: %s", forbidden, encoded)
}
}
for _, expected := range []string{`"status":"available"`, `"http_status":200`, `"bytes":128`} {
if !strings.Contains(string(encoded), expected) {
t.Fatalf("structured report lost probe evidence %q: %s", expected, encoded)
}
}
}

View File

@ -36,9 +36,9 @@ type RDAPRecord struct {
Prefixes []string `json:"prefixes,omitempty"` Prefixes []string `json:"prefixes,omitempty"`
RegistrationDate *time.Time `json:"registration_date,omitempty"` RegistrationDate *time.Time `json:"registration_date,omitempty"`
LastChangedDate *time.Time `json:"last_changed_date,omitempty"` LastChangedDate *time.Time `json:"last_changed_date,omitempty"`
GeofeedURLs []string `json:"geofeed_urls,omitempty"` GeofeedURLs []string `json:"-"`
Entities []RDAPEntity `json:"entities,omitempty"` Entities []RDAPEntity `json:"entities,omitempty"`
Port43 string `json:"port43,omitempty"` Port43 string `json:"-"`
Status []string `json:"status,omitempty"` Status []string `json:"status,omitempty"`
Source string `json:"source"` Source string `json:"source"`
} }

View File

@ -46,10 +46,10 @@ type RIRInfo struct {
Status ReportStatus `json:"status"` Status ReportStatus `json:"status"`
} }
// GeofeedResult contains an RDAP/WHOIS geofeed URL and, when requested, the // GeofeedResult contains the bounded fetch result. URL remains internal so
// bounded fetch result. The payload itself is not retained in the report. // reports expose the probe outcome without disclosing the service location.
type GeofeedResult struct { type GeofeedResult struct {
URL string `json:"url"` URL string `json:"-"`
Status ReportStatus `json:"status"` Status ReportStatus `json:"status"`
HTTPStatus int `json:"http_status,omitempty"` HTTPStatus int `json:"http_status,omitempty"`
Bytes int64 `json:"bytes,omitempty"` Bytes int64 `json:"bytes,omitempty"`
@ -59,11 +59,11 @@ type GeofeedResult struct {
// WHOISRecord is the small, structured subset used when RDAP is unavailable // WHOISRecord is the small, structured subset used when RDAP is unavailable
// or missing required fields. Raw port-43 text is never returned. // or missing required fields. Raw port-43 text is never returned.
type WHOISRecord struct { type WHOISRecord struct {
Server string `json:"server"` Server string `json:"-"`
Status ReportStatus `json:"status"` Status ReportStatus `json:"status"`
Prefixes []string `json:"prefixes,omitempty"` Prefixes []string `json:"prefixes,omitempty"`
RegistrationDate *time.Time `json:"registration_date,omitempty"` RegistrationDate *time.Time `json:"registration_date,omitempty"`
GeofeedURLs []string `json:"geofeed_urls,omitempty"` GeofeedURLs []string `json:"-"`
RIR RIRInfo `json:"rir"` RIR RIRInfo `json:"rir"`
} }

View File

@ -2,7 +2,7 @@ package model
import "time" import "time"
const BackTraceVersion = "v0.0.18" const BackTraceVersion = "v0.0.19"
var EnableLoger = false var EnableLoger = false