Skip to content
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

fix(runtime): Improve Error Handling and-Dot Handling in-fqdn! Macro #23590

Open
wants to merge 27 commits into
base: main
Choose a base branch
from

Conversation

yazan-nidal
Copy link

@yazan-nidal yazan-nidal commented Apr 28, 2024

Implement improvements for error handling and dot handling in fqdn! macro

This commit addresses issue (#23294 , #23552) by enhancing the error handling and dot handling logic within the fqdn! macro. Specifically, it:

  • Handles parsing errors gracefully using pattern matching instead of unwrap().
  • Adjusts substring parsing to correctly handle domain names ending with a dot.

This change improves the reliability and robustness of the fqdn! macro, ensuring more accurate parsing of fully qualified domain names.

Fixes: #23294 , #23552

…acro

This commit addresses issue denoland#23294 by enhancing the error handling and dot handling logic within the fqdn! macro. Specifically, it:
- Handles parsing errors gracefully using pattern matching instead of unwrap().
- Adjusts substring parsing to correctly handle domain names ending with a dot.

This change improves the reliability and robustness of the fqdn! macro, ensuring more accurate parsing of fully qualified domain names.

Fixes: denoland#23294
@CLAassistant
Copy link

CLAassistant commented Apr 28, 2024

CLA assistant check
All committers have signed the CLA.

@yazan-nidal yazan-nidal reopened this Apr 28, 2024
@yazan-nidal yazan-nidal changed the title Implement improvements for error handling and dot handling in fqdn! m… Implement improvements for error handling and dot handling in fqdn! macro Apr 28, 2024
@yazan-nidal yazan-nidal changed the title Implement improvements for error handling and dot handling in fqdn! macro fix (runtime) Improve Error Handling and-Dot Handling in-fqdn! Macro Apr 28, 2024
@mmastrac
Copy link
Contributor

Thanks for the fix. Could you add some tests around the error cases this fixes?

Does this help w/ #23552 ?

@mmastrac mmastrac changed the title fix (runtime) Improve Error Handling and-Dot Handling in-fqdn! Macro fix(runtime): Improve Error Handling and-Dot Handling in-fqdn! Macro Apr 28, 2024
@yazan-nidal
Copy link
Author

yazan-nidal commented Apr 28, 2024

Thanks for the fix. Could you add some tests around the error cases this fixes?

Does this help w/ #23552 ?

hi @mmastrac

Thank you for reviewing the fix! Since this is my first commit in Deno, I'm happy to add tests if necessary. Could you please guide me on how to locate existing tests in the codebase?

I tested the fix manually, but I'm keen to learn how tests are typically structured and where I can find examples within our project. This will help me understand the testing conventions used here and ensure that I contribute effectively to the test suite.

If you could point me to where I can find old tests or provide any resources on writing tests in Deno, I'd greatly appreciate it. Once I have a better understanding, I'll be more than happy to add the necessary tests for this fix.

Regarding issue #23552, I'm eager to ensure that our tests cover relevant error cases and edge scenarios.

Looking forward to your guidance!

@yazan-nidal
Copy link
Author

yazan-nidal commented Apr 29, 2024

@mmastrac
@bartlomieju
can u please review this pr?
I am not able to add reviewer.

Copy link
Contributor

@0f-0b 0f-0b left a comment

Choose a reason for hiding this comment

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

This change would introduce a security hole.

$ cat a.js
const message = "AAABAAABAAAAAAAAB2V4YW1wbGUDbmV0AAAcAAE=";

// A program can trick the user into granting access to a single IPv6 address
console.log(
  await (await fetch(`https://[2606:4700:4700::1111]/dns-query?dns=${message}`))
    .arrayBuffer(),
);

// Now it can connect to the entire IPv6 network
console.log(
  await (await fetch(`https://[2606:4700:4700::1001]/dns-query?dns=${message}`))
    .arrayBuffer(),
);
$ target/debug/deno run a.js
✅ Granted net access to "[2606:4700:4700::1111]".
ArrayBuffer {
  [Uint8Contents]: <00 00 81 80 00 01 00 01 00 00 00 00 07 65 78 61 6d 70 6c 65 03 6e 65 74 00 00 1c 00 01 c0 0c 00 1c 00 01 00 00 0e 10 00 10 26 06 28 00 02 1f cb 07 68 20 80 da af 6b 8b 2c>,
  byteLength: 57
}
ArrayBuffer {
  [Uint8Contents]: <00 00 81 80 00 01 00 01 00 00 00 00 07 65 78 61 6d 70 6c 65 03 6e 65 74 00 00 1c 00 01 c0 0c 00 1c 00 01 00 00 0e 10 00 10 26 06 28 00 02 1f cb 07 68 20 80 da af 6b 8b 2c>,
  byteLength: 57
}

Note that the second fetch call proceeds without asking for permission.

@yazan-nidal
Copy link
Author

Note that the second fetch call proceeds without asking for permission.

hi @0f-0b ,

It is for the same site, it will not request it the next time after approval the first time, and if it refuses, it will be rejected any other time, but it will ask you again if you submit a new request for another domain, and this is the original behavior, I just fixed it to make it not panic when using the wrong domain for fqdn! Macro, this did not affect the flow or behavior and was just to prevent panic

Copy link
Contributor

@mmastrac mmastrac left a comment

Choose a reason for hiding this comment

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

Requires some more work:

  1. We can't return FQDN::default from parsing because that results in a broken permission descriptor
  2. This will need some tests added to flags.rs, and spec tests added in tests/specs/run to ensure that it works as expected.
  3. We'll also need to implement wildcard permission tests which we don't support -- ideally we'd return a better result from flags.rs when encountering these.

yazan-nidal and others added 2 commits May 6, 2024 17:07
…n! macro

This commit addresses issue (denoland#23294 , denoland#23552) by enhancing the error handling and dot handling logic within the fqdn! macro. Specifically, it:

Handles parsing errors gracefully using pattern matching instead of unwrap().
Adjusts substring parsing to correctly handle domain names ending with a dot.
This change improves the reliability and robustness of the fqdn! macro, ensuring more accurate parsing of fully qualified domain names.

Fixes: denoland#23294 , denoland#23552
@yazan-nidal
Copy link
Author

@mmastrac
@bartlomieju
@0f-0b

Please review the latest changes.

@yazan-nidal yazan-nidal requested review from mmastrac and 0f-0b May 7, 2024 13:59
Copy link
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

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

@yazan-nidal there's a few linter errors - most of them are about use of eprintln! (which is now disallowed since 47f7bed) and a few because of using double reference. You can run ./tools/lint.js --rs locally to see these errors.

runtime/permissions/lib.rs Outdated Show resolved Hide resolved
runtime/permissions/lib.rs Outdated Show resolved Hide resolved
yazan-nidal and others added 3 commits May 12, 2024 16:07
…tional; enable net access for host on specified port

- Enhanced parsing logic for IPv6 and IPv4 addresses, as well as hostnames and URLs
- Made port extraction optional by supporting the ":port" syntax in hostnames
- Ensured consistent modification of `IpAddr` struct without cloning
- Added error handling for invalid IPv6 format and missing port specifications
- Enabled network access for the specified host on the given port
- Refactored helper functions for better readability and maintainability
@yazan-nidal yazan-nidal requested a review from dsherret May 23, 2024 06:20
yazan-nidal and others added 2 commits May 23, 2024 09:43
…-Handling-in-fqdn!-Macro

# Conflicts:
#	Cargo.lock
#	ext/net/Cargo.toml
#[test]
fn wildcard_flags() {
#[rustfmt::skip]
let r = flags_from_vec(svec![
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let r = flags_from_vec(svec![
let r = flags_from_vec(svec![

pin-project.workspace = true
rustls-tokio-stream.workspace = true
serde.workspace = true
socket2.workspace = true
tokio.workspace = true
trust-dns-proto = "0.22"
trust-dns-resolver = { version = "0.22", features = ["tokio-runtime", "serde-config"] }
url = "2.4.1"
Copy link
Member

Choose a reason for hiding this comment

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

Can you remove this and instead import Url from deno_core::url::Url?

Copy link
Author

Choose a reason for hiding this comment

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

Ok

ext/net/lib.rs Outdated
use std::sync::Arc;

pub const UNSTABLE_FEATURE_NAME: &str = "net";

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct NetPermissionHost {
pub host: String,
Copy link
Member

Choose a reason for hiding this comment

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

It's not ideal that we're going from a string to a known struct, to a string and then on each permission check doing the same thing. This code below here is also duplicated in permissions/lib.rs. Is there any way that once we parse something as a FQDN that we leave it as one? It seems like we might need to use an enum here to store multiple different kinds of values (ex. FQDN or IpAddr)

Copy link
Author

Choose a reason for hiding this comment

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

Hi @dsherret
dd15f60
done

///
/// # Errors
///
/// Returns an `AnyError` if the input string cannot be parsed into a valid host and optional port.
Copy link
Member

Choose a reason for hiding this comment

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

This documentation comment is a lot to maintain.

Copy link
Author

Choose a reason for hiding this comment

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

ok

…n-fqdn!-Macro' of https://github.com/yazan-nidal/deno into fix-(runtime)-Improve-Error-Handling-and-Dot-Handling-in-fqdn!-Macro
@yazan-nidal yazan-nidal requested a review from dsherret May 27, 2024 13:13
Copy link
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

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

Very nice work, this is a really though nut to crack for the first PR, but you're very close.

A few more comments that needs to be fixed before we can land this one.

ext/net/lib.rs Outdated
}

impl NetPermissionHost {
pub fn from_str(host: &str, mut port: Option<u16>) -> Result<Self, AnyError> {
Copy link
Member

Choose a reason for hiding this comment

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

I think clippy will complain about the name of this method. I suggest to rename it to from_host_and_maybe_port. Also port should be a mutable variable, do a copy if you need to change it

Copy link
Author

Choose a reason for hiding this comment

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

ok

.to_string(),
"Invalid format: [ipv6]:port"
);
}
Copy link
Member

Choose a reason for hiding this comment

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

Very nice tests 👍

ext/net/net.rs Outdated
Copy link
Member

Choose a reason for hiding this comment

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

Can you please rename this file to host.rs?

Copy link
Author

Choose a reason for hiding this comment

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

ok

ext/net/net.rs Outdated
}

impl Host {
pub fn from_str(host: &str, origin_host: &str) -> Result<Self, AnyError> {
Copy link
Member

Choose a reason for hiding this comment

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

Ditto, clippy will complain. Suggest to rename it to from_host_and_origin_host

ext/net/net.rs Outdated
return Ok(Host::FQDN(host));
}

pub fn to_string(&self) -> String {
Copy link
Member

Choose a reason for hiding this comment

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

You might have to implement Display trait instead, but I'm not sure about clippy

ext/net/net.rs Outdated
Ok((host, port))
}

pub fn extract_host(s: &str) -> String {
Copy link
Member

Choose a reason for hiding this comment

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

Is this meant only for URLs? If so maybe we should try to parse as url::Url and use appropriate methods from that crate? WDYT?

Copy link
Author

Choose a reason for hiding this comment

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

I extract the host and port from the url if it was url to request permission or grant permission to this host on this port so we don't need to parse the url itself
The url may contain another part such as the resource path

Likes
https://github.com:443/denoland/deno

I'm extracting "github.com:443" so we need permission to host:github.com on port:443

So I don't give any importance to the URL resource,

We also have another method to parse the url itself
"from_url"
But this needs a valid url

So I extracted the host from the url to validate the host

Such as https://git@hub.com/denoland/deno
git@hub.com -> Invalid

........

I tried parsing the url using url::Url and it gave no error for invalid url so I need to extract the host this way and then check the host is valid

ext/net/ops.rs Outdated
Comment on lines 66 to 75
fn process_ip_addr(addr: &mut IpAddr) -> Result<(), AnyError> {
let extracted_host = extract_host(&addr.hostname);
let tmp_host = &extracted_host.clone();
let (host_str, port) = split_host_port(&extracted_host)?;
addr.hostname = Host::from_str(&host_str, &tmp_host)?.to_string();
if let Some(port) = port {
addr.port = port;
}
Ok(())
}
Copy link
Member

Choose a reason for hiding this comment

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

What is the purpose of this function? A docstring here would be very useful, also if it's important there should be a unit test for it. I'm also not keen on having a mutable reference here if it's a validation function that doesn't return a value.

Copy link
Author

Choose a reason for hiding this comment

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

It is an handle for host before sent it to
01_net.js

When I try to do

Deno.connect({ hostname: "https://192.0.2.1/", port: 80 });
Deno.listen({ hostname: "https://golang.org/", port: 80, transport: "tcp" });

It will send the hostname and port as args
to
async function connect(args)
function listen(args)
In ext/net/01_net.js

So it will try to connect to invalid addresses, so we need to deal with the host and extract the valid port and host before connecting

Comment on lines +1 to +2
error: Uncaught (in promise) ConnectionRefused: No connection could be made because the target machine actively refused it. (os error 10061)
at async Object.connect (ext:deno_net/01_net.js:587:55)
Copy link
Member

Choose a reason for hiding this comment

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

I'm a bit confused here. The provided permission and host/port pair matches in the ipv6.js file, then why is it erroring?

Copy link
Author

Choose a reason for hiding this comment

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

it's refused connection from the host of ipv6 not permission error i don't find any valid ipv6 can make connect with it at some port

/// # Errors
///
/// Returns an `AnyError` if the input string cannot be parsed.
pub fn from_str(s: &str) -> Result<Self, AnyError> {
Copy link
Member

Choose a reason for hiding this comment

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

Again, I think clippy will complain about this one. Is this one meant to parse the CLI args? If so I suggest to rename it to from_cli_arg()

Copy link
Author

Choose a reason for hiding this comment

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

it's for extract the net descriptor from str

when do --allow-net=https://github.com:443/

it will extract the the NetDescriptor(hostname:github.com ,port:443)

@yazan-nidal
Copy link
Author

Very nice work, this is a really though nut to crack for the first PR, but you're very close.

A few more comments that needs to be fixed before we can land this one.

@bartlomieju
done
b4b84ab

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.

thread 'main' panicked at runtime/permissions/lib.rs:695:19
6 participants