Repository navigation
cli: take host:port for --rpc-url - #1098
Conversation
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
[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.
There was a problem hiding this comment.
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
Summary
rbitcoin-cli --rpc-urlnow takeshost:portand speaks plain HTTP.http://andhttps://are rejected instead of stripped.https://used to look like TLS and then write the bearer token on a rawTcpStream.The flag name stays
--rpc-url. Omitting it still prefers{datadir}/rpc.sock, then127.0.0.1and the network RPC port. An IPv6 address is[::1]:8332; theHostheader keeps the brackets.Test
cargo test -p rbitcoin-cli --libis green, includingrpc_url_is_host_and_port. Localfmt,clippy --workspace --all-targets,cargo deny, andast-grepare green. Workspacecargo testwas not run locally.