Skip to content

cli: take host:port for --rpc-url - #1098

Merged
reardencode merged 2 commits into
masterfrom
cli/rpc-host-port
Oct 20, 2026
Merged

reardencode merged 2 commits into
masterfrom
cli/rpc-host-port

Conversation

@rearden-grok

@rearden-grok rearden-grok Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Summary

rbitcoin-cli --rpc-url now takes host:port and speaks plain HTTP. http:// and https:// are rejected instead of stripped. https:// used to look like TLS and then write the bearer token on a raw TcpStream.

The flag name stays --rpc-url. Omitting it still prefers {datadir}/rpc.sock, then 127.0.0.1 and the network RPC port. An IPv6 address is [::1]:8332; the Host header keeps the brackets.

Test

cargo test -p rbitcoin-cli --lib is green, including rpc_url_is_host_and_port. Local fmt, clippy --workspace --all-targets, cargo deny, and ast-grep are green. Workspace cargo test was not run locally.

The flag used to strip http:// and https:// and then open a plain
TCP socket. Pass host:port only. A scheme, path, or userinfo is an
error, so a bearer token is not sent when the operator wrote https.

@rearden-grok rearden-grok Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Disposition: request changes

--rpc-url is now host:port for plain HTTP. https://, any ://, /, and @ are rejected before a socket is opened, so the old cleartext-bearer path is gone, and bracketed IPv6 is dialed with a bracketed Host. The remaining hole is an unbracketed host that is not a strict IP and not a DNS name: parse_rpc_addr accepts it, and TcpStream::connect((host, port)) uses getaddrinfo, which applies inet_aton and can send the bearer token to a different address than the one written. That grammar also disagrees with --rpc-listen, which parses a SocketAddr and rejects these strings. An explicit --rpc-url still skips an existing unix socket and reads the token only after TCP connect succeeds; a rejected URL never reaches that read.

Issue counts by severity

  • bugs: 1
  • suggestions: 0
  • nits: 0

} else if raw_host.contains(':') {
return Err(bad());
} else {
raw_host

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[bug] An unbracketed host is returned unchanged and later dialed with TcpStream::connect((host, port)) (lib.rs:286), which falls through to getaddrinfo. On this libc that rewrites inet_aton forms that IpAddr and the node's SocketAddr (config.rs rpc_listen → val.parse()) both reject. Verified resolutions: 010.0.0.1:8332 → 8.0.0.1:8332, 0127.0.0.1:8332 → 87.0.0.1:8332, 127.0.0.010:8332 → 127.0.0.8:8332, 0x7f000001:8332 and 2130706433:8332 → 127.0.0.1:8332, 127.1:8332 → 127.0.0.1:8332. dispatch_call reads rpc.token and writes Authorization: Bearer only after that connect succeeds (lib.rs:290-291), so a padded or hex literal that looks local sends the bearer to another host. https://, userinfo, a path, and a query do not take this path (they error first). Real names such as rpc.lan and scoped IPv6 such as [fe80::1%lo]:8332 still resolve to the intended address; those are not this bug.

Suggestion: If the host is only an IP literal, dial IpAddr::from_str (Rust rejects leading zeros, short quads, hex, and decimal dwords) and do not call ToSocketAddrs. Reject leftover numeric forms (010.0.0.1, 0x7f000001, 2130706433, 127.1) with the existing host:port error. Keep getaddrinfo for DNS names, and keep scoped IPv6 on the SocketAddr / getaddrinfo path so [fe80::1%1] and [fe80::1%lo] still work. Cover 010.0.0.1:8332 and 0x7f000001:8332 in rpc_url_is_host_and_port as errors.

A strict IP connects as a SocketAddr. Leading zeros, short quads, and
hex forms are an error, so getaddrinfo cannot send the bearer token to
a rewritten address.

@rearden-grok rearden-grok Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Disposition: approve

The follow-up closes the inet_aton hole. parse_rpc_addr rejects schemes, userinfo, and paths, and acceptable_host rejects every glibc numeric spelling that is not a strict IpAddr (010.0.0.1 → 8.0.0.1, 0x7f.0.0.1, 0x7f000001, 127.1, 2130706433, short quads, partial octal). Those hosts never reach getaddrinfo. Strict addresses dial through SocketAddr; DNS names (dead.beef, 0x10.lan, localhost, rpc.lan) and scoped IPv6 (fe80::1%lo, numeric zones) still resolve to the address the operator wrote, with the interface name turned into a scope id only. Near misses that the parser still accepts (trailing dots, ::ffff:010.0.0.1, whitespace) fail getaddrinfo before read_token, so the bearer token is not sent.

Issue counts by severity

  • bugs: 0
  • suggestions: 0
  • nits: 0

@reardencode
reardencode merged commit 8da2df3 into master Oct 20, 2026
18 checks passed
@rearden-grok
rearden-grok Bot deleted the cli/rpc-host-port branch October 20, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant