-
Notifications
You must be signed in to change notification settings - Fork 9
Consolidate WHOIS #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Consolidate WHOIS #125
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
6c9d19a
first pass (rough)
EvanLeleux e74ef8d
strip out into lib
EvanLeleux 189e6b6
Merge remote-tracking branch 'origin/main' into evan/consolidate-whois
EvanLeleux 44dc665
first cleanup pass
EvanLeleux 84517bd
cleanup third pass
EvanLeleux 6230086
fix whois and rename old reverse_whois to viewdns
EvanLeleux 63ecb43
nit
EvanLeleux a98d606
merge in main
EvanLeleux 4b2f4b1
fix rootdomain
EvanLeleux 38518fc
fix
EvanLeleux 1bbb4ca
bot comments
EvanLeleux 9633f7c
add unit tests
EvanLeleux d08aea3
simplify
EvanLeleux c65d496
Delete whois-test-harness
EvanLeleux d7d8bc3
add result struct
EvanLeleux 16486da
fix
EvanLeleux 26ff648
nit
EvanLeleux 6cb6570
clear private contacts
EvanLeleux 9fed3e5
Merge pull request #136 from praetorian-inc/evan/whois-domain-format
josephwhenry File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| package netutil | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "net" | ||
| "net/netip" | ||
| "syscall" | ||
| ) | ||
|
|
||
| // SSRFSafeControl is a net.Dialer.Control hook that rejects connections to | ||
| // non-public addresses, preventing untrusted referrals from probing internal | ||
| // networks. | ||
| func SSRFSafeControl(_, address string, _ syscall.RawConn) error { | ||
| host, _, err := net.SplitHostPort(address) | ||
| if err != nil { | ||
| return fmt.Errorf("ssrf guard: malformed address %q: %w", address, err) | ||
| } | ||
| ip := net.ParseIP(host) | ||
| if ip == nil { | ||
| return fmt.Errorf("ssrf guard: non-IP address %q", host) | ||
| } | ||
| if IsDisallowedIP(ip) { | ||
| return fmt.Errorf("ssrf guard: refusing non-public address %s", ip) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| var v6GlobalUnicast = netip.MustParsePrefix("2000::/3") | ||
|
|
||
| var disallowedPrefixes = func() []netip.Prefix { | ||
| cidrs := []string{ | ||
| // IPv4 special-purpose | ||
| "0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", | ||
| "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.2.0/24", | ||
| "192.88.99.0/24", "192.168.0.0/16", "198.18.0.0/15", "198.51.100.0/24", | ||
| "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4", | ||
| // IPv6 special-purpose | ||
| "::1/128", "::/128", "::ffff:0:0/96", "::/96", | ||
| "64:ff9b::/96", "64:ff9b:1::/48", "100::/64", "100:0:0:1::/64", | ||
| "2001::/23", "2001:db8::/32", "2002::/16", "3fff::/20", | ||
| "5f00::/16", "fc00::/7", "fe80::/10", "fec0::/10", "ff00::/8", | ||
| } | ||
| prefixes := make([]netip.Prefix, 0, len(cidrs)) | ||
| for _, c := range cidrs { | ||
| prefixes = append(prefixes, netip.MustParsePrefix(c)) | ||
| } | ||
| return prefixes | ||
| }() | ||
|
|
||
| // IsDisallowedIP reports whether ip is non-public (loopback, private, CGNAT, | ||
| // link-local, etc.) and must not be dialed when following an untrusted referral. | ||
| func IsDisallowedIP(ip net.IP) bool { | ||
| if ip == nil { | ||
| return true | ||
| } | ||
| addr, ok := netip.AddrFromSlice(ip) | ||
| if !ok { | ||
| return true | ||
| } | ||
| addr = addr.Unmap() | ||
| if !addr.IsGlobalUnicast() || addr.IsPrivate() { | ||
| return true | ||
| } | ||
| if addr.Is6() && !v6GlobalUnicast.Contains(addr) { | ||
| return true | ||
| } | ||
| for _, p := range disallowedPrefixes { | ||
| if p.Contains(addr) { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| package strutil | ||
|
|
||
| import "strings" | ||
|
|
||
| // Tokenize lowercases s and splits on non-alphanumeric characters. | ||
| func Tokenize(s string) []string { | ||
| s = strings.ToLower(s) | ||
| var buf strings.Builder | ||
| for _, c := range s { | ||
| if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') { | ||
| buf.WriteRune(c) | ||
| } else { | ||
| buf.WriteByte(' ') | ||
| } | ||
| } | ||
| return strings.Fields(buf.String()) | ||
| } | ||
|
|
||
| // TokenSimilarity computes the ratio of shared tokens between two strings. | ||
| // Uses the shorter set as the denominator so partial matches score well. | ||
| func TokenSimilarity(a, b string) float64 { | ||
| aT := Tokenize(a) | ||
| bT := Tokenize(b) | ||
| if len(aT) == 0 || len(bT) == 0 { | ||
| return 0 | ||
| } | ||
| shorter, longer := aT, bT | ||
| if len(aT) > len(bT) { | ||
| shorter, longer = bT, aT | ||
| } | ||
| inLonger := make(map[string]bool, len(longer)) | ||
| for _, t := range longer { | ||
| inLonger[t] = true | ||
| } | ||
| matches := 0 | ||
| for _, t := range shorter { | ||
| if inLonger[t] { | ||
| matches++ | ||
| } | ||
| } | ||
| return float64(matches) / float64(len(shorter)) | ||
| } | ||
|
|
||
| // UniqueFunc returns a new slice containing only the first occurrence of each | ||
| // element as determined by the key function, preserving order. | ||
| func UniqueFunc[T any, K comparable](s []T, key func(T) K) []T { | ||
| seen := make(map[K]struct{}, len(s)) | ||
| out := make([]T, 0, len(s)) | ||
| for _, v := range s { | ||
| k := key(v) | ||
| if _, ok := seen[k]; ok { | ||
| continue | ||
| } | ||
| seen[k] = struct{}{} | ||
| out = append(out, v) | ||
| } | ||
| return out | ||
| } | ||
|
|
||
| // Unique returns a new slice containing only the first occurrence of each | ||
| // element, preserving order. | ||
| func Unique[T comparable](s []T) []T { | ||
| return UniqueFunc(s, func(v T) T { return v }) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package domains | ||
|
|
||
| import ( | ||
| "strings" | ||
|
|
||
| "github.com/praetorian-inc/pius/pkg/lib/strutil" | ||
| "github.com/praetorian-inc/pius/pkg/plugins" | ||
| "github.com/praetorian-inc/pius/pkg/whois" | ||
| ) | ||
|
|
||
| // domainFindings normalizes, deduplicates, and filters a raw list of domain | ||
| // strings into plausible FindingDomain entries with the pivot org attached. | ||
| // Shared by the reverse-whois plugins. | ||
| func domainFindings(source, pivotOrg string, rawDomains []string) []plugins.Finding { | ||
|
EvanLeleux marked this conversation as resolved.
|
||
| normalized := make([]string, 0, len(rawDomains)) | ||
| for _, raw := range rawDomains { | ||
| domain := strings.TrimSuffix(strings.TrimSpace(strings.ToLower(raw)), ".") | ||
| if domain != "" && whois.IsPlausibleDomain(domain) { | ||
| normalized = append(normalized, domain) | ||
| } | ||
| } | ||
|
|
||
| var findings []plugins.Finding | ||
| for _, domain := range strutil.Unique(normalized) { | ||
| findings = append(findings, plugins.Finding{ | ||
| Type: plugins.FindingDomain, | ||
| Value: domain, | ||
| Source: source, | ||
| Data: map[string]any{"pivot_org": pivotOrg}, | ||
| }) | ||
| } | ||
| return findings | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.