Repository navigation
Conversation
Probing a vhost on a given server, or an origin behind a CDN, needs the
hostname in the Host header and SNI while the connection goes to
another ip, and the same host may need probing on several ips. The
vhost,ip form builds the URL from the ip, so it sends no SNI and reports
the ip as the URL host, and -pa probes the ips DNS returns.
An input line can now be a JSON object with the target and the ip,
like curl --resolve:
{"target": "https://app.example.com", "ip": "192.0.2.10"}
The target is probed with the ip as its CustomIP, and host_ip reports
it. Lines are read from -l and stdin; -u splits its value on commas, so
it cannot carry them. The ip is validated and canonicalized, and the
target must have a hostname. An invalid line stops the run, or is
skipped with a warning in stream mode. Equivalent lines are stored once,
and -pa does not resolve a pinned target. -proxy, -unsafe, -pipeline,
-http2, -jarm, -screenshot and -vhost-input do not connect through the
ip, so they are refused with pinned targets.
The ip of a pinned line, and each ip of -pa, now pins only the probed
host, with fastdialer.WithResolveOverride. The fastdialer.IP value used
before pinned every dial of the request, so a redirect to another host
followed with -fr went to the same ip. IPv6 ips were passed in
brackets, which fastdialer does not accept as an ip, so those -pa probes
failed. Favicon and ztls requests keep the ip, -maxhr counts errors per
ip, and the ip is checked against the network policy as well as the
host.
go.mod points fastdialer at a fork commit with WithResolveOverride until
a fastdialer release includes it.
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Comment |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Probing a vhost on a given server, or an origin behind a CDN, needs the hostname in the Host header and SNI while the connection goes to another ip, and the same host may need probing on several ips. httpx had no input for that: the
vhost,ipform builds the URL from the ip, so it sends no SNI and reports the ip asurlandhost, and-pa, which probes the ips DNS returns, didn't reach them correctly.An input line can now be a JSON object with the target and the ip, like
curl --resolve. The connection goes to the ip, the hostname stays in the Host header and SNI, andhost_ipreports the ip.-panow pins its ips the same way. Run in a container without network, withapp.testresolving to 127.0.0.1 and 127.0.0.2, a server on each whose title is its address, andredir.testredirecting toother.test(127.0.0.3), with-title -ip:dev-lwith two lines pinninghttp://app.test:18080to .1 and .2[srv=127.0.0.1 …] [127.0.0.1],[srv=127.0.0.2 …] [127.0.0.2]-paonhttp://app.test:18080[srv=127.0.0.2 …] [127.0.0.1],[srv=127.0.0.2 …] [127.0.0.2][srv=127.0.0.1 …] [127.0.0.1],[srv=127.0.0.2 …] [127.0.0.2]-pa -fronhttp://redir.test:18201[302,200] [srv=127.0.0.1 host=other.test:18202][302,200] [srv=127.0.0.3 host=other.test:18202]-streamwith a malformed line[ERR] Skipping input: invalid target line …, the other lines probedDepends on projectdiscovery/fastdialer#580:
WithResolveOverride, and the dial cache fix without which the second ip of a host is served from the first one's cached dialer.go.modpoints fastdialer at the branch of that PR until a fastdialer release includes it; thatreplaceline is the only change togo.mod.Changes
-papassed each ip in thefastdialer.IPcontext value, which pins every dial made for the request, so a redirect to another host followed with-frwent to the same ip. The ip now pins only the probed host, withfastdialer.WithResolveOverride. IPv6 ips were passed in brackets, which fastdialer doesn't accept as an ip, so those probes failed; they are passed as is now. Favicon and ztls requests dropped the ip and reached the host through DNS; they keep it now.-maxhrcounts errors per ip, and the ip is checked against the network policy as well as the host.runner/targetline.goparses input lines that start with{. Onlytargetandipare accepted, and data after the object is rejected. The ip is validated and canonicalized (::ffff:192.0.2.10becomes192.0.2.10; zones and unspecified addresses are rejected), and the target must have a hostname: IP, CIDR, ASN, wildcard andvhost,iptargets are rejected. Lines are read from-land stdin;-usplits its value on commas, so it cannot carry them. Equivalent lines are stored once, a line without an ip is the plain target, and-padoesn't resolve a pinned target.streamInputshare onesendLinehelper.-proxy,-unsafe,-pipeline,-http2,-jarm,-screenshotand-vhost-inputdon't connect through the ip, so they are refused with pinned targets. The README note documents the format and says that a proxy set withHTTP_PROXY/HTTPS_PROXYresolves the host itself as well.Testing
TestParseTargetLinecovers valid lines and each rejected form.TestRunner_normalizeInputcovers deduplication of equivalent lines and the flag conflicts.TestRunner_targetLine_targetschecks that-paisn't applied to a pinned target.TestRunner_streamInput_skipsInvalidLineschecks that stream mode skips a malformed line and keeps the others.TestTargetLinePinsTheConnection: two local servers on 127.0.0.1 and 127.0.0.2 with the same port, each reached for its own line withHost: pinned.test:port.TestTargetLineKeepsSNI: a TLS server seespinned.testas SNI. Both skip when a proxy from the environment applies to the target.go test -race ./runner/passes exceptTestRunner_probeall_targets, which resolves one.one.one.one and fails the same way ondevhere; the target line tests pass with and withoutHTTPS_PROXYset, and with-racein agolang:1.27.1container without network.go test ./common/httpx/passes.golangci-lint run ./runner/... ./common/...: 0 issues.IPv6 could not be exercised here: the kernel of this environment has no IPv6.
Closes #2667
Checklist