-
Notifications
You must be signed in to change notification settings - Fork 32
Make Servers Stop Rejecting Requests #599
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
Conversation
| masq_lib = { path = "../masq_lib" } | ||
| native-tls = "0.2.8" | ||
| node = { path = "../node", features = [ "expose_test_privates" ] } | ||
| node = { path = "../node" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed; Bert said it's obsolete
node/src/proxy_server/mod.rs
Outdated
| let stream_key = self.stream_key_factory.make(); | ||
| let stream_key = self | ||
| .stream_key_factory | ||
| .make(self.main_cryptde.public_key(), server_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Maybe the StreamKeyFactory should carry around the Node's public key? It's not like it's going to change...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to understand: Is the stream key used in the originating node to find the proper stream for a particular host? That means inboud_client_data.peer_addr is always the host IP we are asking for the web page or data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already talked about this, but for posterity: no. InboundClientData.peer_addr (now called InboundClientData.client_addr) is the address associated with the stream from the browser (or other client) we're dealing with. Hashed with our public key, it ought to be universally unique.
node/src/proxy_server/mod.rs
Outdated
| "make_stream_key() inserted new key {} for {}", &stream_key, ibcd.peer_addr | ||
| "find_or_generate_stream_key() inserted new key {} for {}", | ||
| &stream_key, | ||
| ibcd.peer_addr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another neglected name change
| hash.update(uuid_bytes); | ||
| hash.update(public_key.as_ref()); | ||
| hash = add_socket_addr_to_hash(hash, server_addr); | ||
| hash.update(STREAM_KEY_SALT.as_slice()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the main change, right here; everything else supports it
node/src/sub_lib/stream_key.rs
Outdated
| hash.update(v4.ip().octets().as_slice()); | ||
| } | ||
| SocketAddr::V6(v6) => { | ||
| hash.update(v6.ip().octets().as_slice()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, I don't think the Node officially supports IPv6 yet; but when it does, this will be one less thing to change.
node/src/sub_lib/stream_key.rs
Outdated
| } | ||
| } | ||
| let port = socket_addr.port(); | ||
| hash.update(&[(port & 0xFF) as u8, (port >> 8) as u8]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lower byte of the port, then upper byte of the port
| fn stream_keys_from_different_public_keys_are_different() { | ||
| let server_addr = SocketAddr::new(IpAddr::from_str("1.2.3.4").unwrap(), 1024); | ||
|
|
||
| let stream_keys = vec![PublicKey::new(&[1, 2, 3]), PublicKey::new(&[1, 2, 2])] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The public keys are only one bit different
| let attack = StreamKey { | ||
| hash: hash.digest().bytes(), | ||
| }; | ||
| assert_ne!(attack, result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make a StreamKey without hashing in the salt, and it'll be wrong
|
|
||
| #[test] | ||
| fn financials_command_retrieves_payable_and_receivable_records() { | ||
| fn financials_command_retrieves_payable_and_receivable_records_integration() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this test wasn't named xxx_integration, it wasn't being run. Since it wasn't being run, it didn't work. We fixed it.
| assert_eq!(receivable[0].wallet, wallet_receivable_1.to_string()); | ||
| assert_eq!(receivable[0].balance_gwei, 9000_i64); | ||
| assert_eq!(receivable[1].wallet, wallet_receivable_2.to_string()); | ||
| assert_eq!(receivable[1].balance_gwei, 345678_i64); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't assert this way, because we can't depend on the order of the receivables. So we first have to figure out which order they're in, and then assert on them.
| let data_dir = if sterile_database { | ||
| ensure_node_home_directory_exists("integration", test_name) | ||
| } else { | ||
| node_home_directory("integration", test_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the config_opt contains a --data-directory specification, it shouldn't be ignored like this.
czarte
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we decided to add host_name and port to streamkeys
masq_lib/Cargo.toml
Outdated
| tiny-hderive = "0.3.0" | ||
| toml = "0.5.8" | ||
| websocket = {version = "0.26.2", default-features = false, features = ["sync"]} | ||
| rand = { version = "0.9.0", features = ["thread_rng"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put this to alphabetical order please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
node/src/proxy_server/mod.rs
Outdated
| let stream_key = self.stream_key_factory.make(); | ||
| let stream_key = self | ||
| .stream_key_factory | ||
| .make(self.main_cryptde.public_key(), server_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to understand: Is the stream key used in the originating node to find the proper stream for a particular host? That means inboud_client_data.peer_addr is always the host IP we are asking for the web page or data?
node/src/proxy_server/mod.rs
Outdated
| } | ||
|
|
||
| fn find_or_generate_stream_key(&mut self, ibcd: &InboundClientData) -> StreamKey { | ||
| fn find_or_generate_stream_key( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't see how we want to select the stream for particular host, as I understand, maybe wrongly, the peer_addr is something different of server_addr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We talked about this, but for posterity: peer_addr (now called client_addr) is the address of the stream from the browser, not the stream to the server.
node/src/proxy_server/mod.rs
Outdated
| return Err("Browser request rejected due to missing consuming wallet".to_string()); | ||
| } | ||
| let stream_key = proxy.find_or_generate_stream_key(&msg); | ||
| let stream_key = proxy.find_or_generate_stream_key(&msg, source_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't source_addr be host_addr?
node/src/sub_lib/stream_key.rs
Outdated
| let uuid_bytes: &[u8] = uuid.as_bytes(); | ||
| hash.update(uuid_bytes); | ||
| hash.update(public_key.as_ref()); | ||
| hash = add_socket_addr_to_hash(hash, server_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
server_addr is host_addr?
This reverts commit 10735ad.
| let ibcd_in = InboundClientData { | ||
| timestamp: SystemTime::now(), | ||
| peer_addr, | ||
| client_addr, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed for clarity
| None => (Some(host.name), protocol_pack.standard_port()), | ||
| }, | ||
| let (target_hostname_opt, target_port) = match target_host { | ||
| Some(host) => (Some(host.name), host.port), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
host.port is no longer optional
| last_data: ibcd.last_data, | ||
| }, | ||
| target_hostname, | ||
| target_hostname: target_hostname_opt, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't correct the field name of ClientRequestPayload_0v1 without migrating to ClientRequestPayload_0v2, but I can correct the variable name...
| match HttpProtocolPack::find_header_host(data.as_slice()) { | ||
| Some(host) => Some(host), | ||
| None => HttpProtocolPack::find_header_host(data.as_slice()), | ||
| None => HttpProtocolPack::find_url_host(data.as_slice()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected the host-name priority
| 2 => Some(Host { | ||
| name: parts.remove(0).to_string(), | ||
| port: Self::port_from_string(parts.remove(0).to_string()), | ||
| port: HTTP_PORT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, instead of making a missing port number None here in HttpProtocolPack, where we know missing port numbers mean a default of 80, and then figuring out the number later when we run into the None outside the HTTP context, we're ditching the Option and defaulting it to 80 right here.
| Err(_) => None, | ||
| Ok(port) => Some(port), | ||
| Err(_) => Err(format!("Port '{}' is not a number", port_str)), | ||
| Ok(port) => Ok(port), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can't parse a port number, that's not just "no port was specified;" that's an error that needs to be reported and logged somewhere.
|
|
||
| assert_eq!(String::from("header.host.com"), host.name); | ||
| assert_eq!(host, Host::new("header.host.com", HTTP_PORT)); | ||
| assert_eq!(HTTP_PORT, host.port); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that Host has a constructor, we can easily assert on the whole thing, rather than just one field.
|
|
||
| #[test] | ||
| fn returns_host_name_and_port_from_url_if_both_exist() { | ||
| fn returns_host_name_and_port_from_header_if_both_exist() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Priorities have been corrected.
| let host = HttpProtocolPack {}.find_host(&data).unwrap(); | ||
|
|
||
| assert_eq!(String::from("top.host.com"), host.name); | ||
| assert_eq!(host.name, String::from("top.host.com")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is old, old code, back from the days when Rust followed the JUnit convention of assert_eq!(expected, actual). Where I happened across these, I changed them to conform to the more modern assert_eq!(actual, expected) standard.
| fn returns_host_name_from_url_when_no_scheme() { | ||
| let data = PlainData::new( | ||
| b"CONNECT good.url.dude/path.html HTTP/1.1\r\nHost: wrong.url.dude\r\n\r\n", | ||
| b"GET wrong.url.dude/path.html HTTP/1.1\r\nHost: good.url.dude\r\n\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CONNECTs are unusual in the way their URL parameters are formed. The code under test doesn't care about that, but I still don't like a test with a manifestly incorrect request syntax, if I can avoid it. And I can. So I did.
| } | ||
|
|
||
| #[test] | ||
| fn from_integration_test() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant test; removed.
| let msg_from_dispatcher = InboundClientData { | ||
| timestamp: SystemTime::now(), | ||
| peer_addr: socket_addr.clone(), | ||
| client_addr: socket_addr, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SocketAddr is Copy: no need for .clone().
| Encrypted with 0x03040506: LiveHop { public_key: 0x, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 1, r: "9ca23557adf96d7aed407a06ce96851a4184e947a7b29b6c3872eef902fcba1e", s: "9ca23557adf96d7aed407a06ce96851a4184e947a7b29b6c3872eef902fcba1e" } }), component: Neighborhood } | ||
| Encrypted with 0x01020304: LiveHop { public_key: 0x02030405, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 0, r: "3e3a92d7284c2c2ff7119e9f7a7e183b062a335a598e965a47c36a2f288b6f8d", s: "3e3a92d7284c2c2ff7119e9f7a7e183b062a335a598e965a47c36a2f288b6f8d" } }), component: Hopper } | ||
| Encrypted with 0x02030405: LiveHop { public_key: 0x03040506, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 0, r: "4324a40295bb36ef2b927fb24250fe42397a57b861ea152bbbe4f84150d4ff5a", s: "4324a40295bb36ef2b927fb24250fe42397a57b861ea152bbbe4f84150d4ff5a" } }), component: Hopper } | ||
| Encrypted with 0x03040506: LiveHop { public_key: 0x, payer: Some(Payer { wallet: Wallet { kind: Address(0x71d0fc7d1c570b1ed786382b551a09391c91e33d) }, proof: Signature { v: 1, r: "8649b8f6db6232cb1e4f1f04786ad4ef33488c968e64bec74ecd893d6d05c1b9", s: "8649b8f6db6232cb1e4f1f04786ad4ef33488c968e64bec74ecd893d6d05c1b9" } }), component: Neighborhood } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching blockchains from EthRopsten to BaseSepolia resulted in different signatures.
| fn default() -> Self { | ||
| Self::new() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a StreamKey now requires two parameters: no more Default.
|
|
||
| type HashType = [u8; sha1::DIGEST_LENGTH]; | ||
|
|
||
| fn add_socket_addr_to_hash(mut hash: sha1::Sha1, client_addr: SocketAddr) -> sha1::Sha1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot wrote this whole function, just working from the name of it (and probably the tests for the caller), and I didn't modify it. Pretty cool, hey?
No description provided.