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

inspector: perform DNS lookup for host #13478

Merged
merged 1 commit into from
Jun 16, 2017
Merged

inspector: perform DNS lookup for host #13478

merged 1 commit into from
Jun 16, 2017

Conversation

eugeneo
Copy link
Contributor

@eugeneo eugeneo commented Jun 5, 2017

Fixes: #13477

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)

inspector: performs a sync DNS lookup when the server is starting.

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. dont-land-on-v4.x inspector Issues and PRs related to the V8 inspector protocol labels Jun 5, 2017
@refack
Copy link
Contributor

refack commented Jun 5, 2017

Code LGTM, the question is does it make sense? Do people need a DNS lookup? Won't it be simpler to check for host_.c_str()[0] == '[' and call uv_ip6_addr?

Copy link
Contributor

@refack refack left a comment

Choose a reason for hiding this comment

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

Needs new tests in test/cctest/test_inspector_socket_server.cc

Copy link
Contributor

@sam-github sam-github left a comment

Choose a reason for hiding this comment

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

Looks good, but the URL formatting isn't valid, will need to have the [...] placed around the address so the output URLs are valid:

% ./node --inspect=::1:9876
Debugger listening on ws://::1:9876/6fcffeb2-55bf-438b-b886-582a2d517513
For help see https://nodejs.org/en/docs/inspector
> %                                                                                    core/node ((a392ece...) $) % ./node --inspect=[::1]:9876
Debugger listening on ws://::1:9876/1fa763a7-4ca3-4040-a666-6eb8d3b268f9

int err = uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(),
std::to_string(port_).c_str(), nullptr);
if (err < 0) {
fprintf(out_, "%s is not a valid host name\n", host_.c_str());
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a more specific error message that can be reported? Is invalid host name the only reason for getaddrinfo to fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 5, 2017

Code LGTM, the question is does it make sense? Do people need a DNS lookup? Won't it be simpler to check for host_.c_str()[0] == '[' and call uv_ip6_addr?

One stupid thing I noticed was any symbolic name (non-existing, localhost) would always bind to *. With this lookup invalid names (e.g. with typos) will error out, localhost binds to 127.0.0.1 (e.g. no outside access).

v8.0.0:

$ node --inspect=google.com
Debugger listening on ws://google.com:9229/bd2d9e4f-b9b5-4503-b38e-df62a8082fbd

(actually listening *:9229)

This patch:

$ ./node --inspect=google.com
Starting inspector on google.com:9229 failed: address not available

@sam-github
Copy link
Contributor

Yes, definitely works better now.

@refack
Copy link
Contributor

refack commented Jun 5, 2017

One stupid thing I noticed was any symbolic name (non-existing, localhost) would always bind to *. With this lookup invalid names (e.g. with typos) will error out, localhost binds to 127.0.0.1 (e.g. no outside access).

Ack.
Still IMHO needs tests

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 6, 2017

@refack Tests added. Will see if they make it through the CI :)

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 6, 2017

@sam-github Fixed the URL

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 6, 2017

Please, don't review for now - I will upload a different version tomorrow.

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 6, 2017

Ready for review. CI: https://ci.nodejs.org/job/node-test-pull-request/8520/

@@ -26,7 +26,7 @@ static const char WS_HANDSHAKE_RESPONSE[] =
{ \
Timeout timeout(&loop); \
while ((condition) && !timeout.timed_out) { \
uv_run(&loop, UV_RUN_NOWAIT); \
uv_run(&loop, UV_RUN_ONCE); \
Copy link
Contributor

Choose a reason for hiding this comment

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

How does this change the current tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does not. Simply results in lower number of loops.

@@ -376,11 +385,25 @@ void InspectorSocketServer::SendListResponse(InspectorSocket* socket) {

bool InspectorSocketServer::Start() {
CHECK_EQ(state_, ServerState::kNew);
sockaddr_in addr;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
Copy link
Member

Choose a reason for hiding this comment

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

sizeof(hints) or just struct addrinfo hints().

I will admit I don't quite understand why you pass the port number if you aren't interested in service name lookups (AI_NUMERICSERV.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my opinion, made the code slightly easier - prefills the sockaddr structures.

uv_ip4_addr(host_.c_str(), port_, &addr);
int err = uv_tcp_bind(&server_,
reinterpret_cast<const struct sockaddr*>(&addr), 0);
err = uv_tcp_bind(&server_, req.addrinfo->ai_addr, 0);
Copy link
Member

Choose a reason for hiding this comment

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

Only binds to the first address. Acceptable for now but sooner or later someone is going to file a bug about that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now this class works with a vector of sockets. This should also help if there's ever a need to support listening on multiple ports (e.g. someone mentioned before something about changing the port at the runtime).

One issue this implementation is that different sockets will bind to different ports if requested port is 0 - while only first socket port is surfaced in API and console messages. I did not want to further complicate this implementation at this time, but an API that provides list of addresses and ports can be created later.

Copy link
Member

Choose a reason for hiding this comment

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

One issue this implementation is that different sockets will bind to different ports if requested port is 0

That seems reasonable to me.

bool has_ipv6_address() {
uv_interface_address_s* addresses;
int address_count;
int err = uv_interface_addresses(&addresses, &address_count);
Copy link
Member

Choose a reason for hiding this comment

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

Needs a matching call to uv_free_interface_addresses().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done. I'm bit fuzzy on this - but should uv_free_* be called if respective call (in this case to uv_interface_addresses) failed?

Copy link
Member

Choose a reason for hiding this comment

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

You normally only call it on success but it's safe to call on error if you initialize addresses and address_count to nullptr / zero.

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 7, 2017

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 7, 2017

(Please do not review for now, fixing)

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 8, 2017

I ended up moving more code around then I originally intended. My goal was to better separate responsibilities between server, server socket and session objects.

Please review.

CI: https://ci.nodejs.org/job/node-test-pull-request/8557/

PrintDebuggerReadyMessage(host_, port_, delegate_->GetTargetIds(), out_);
for (addrinfo* address = req.addrinfo; address != nullptr;
address = address->ai_next) {
err = ServerSocket::Listen(this, address->ai_addr, loop_);
Copy link
Contributor

Choose a reason for hiding this comment

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

If I understand this correctly for localhost we'll probably get ['127.0.0.1', '[::1]'] and try to listen to them all?
But print only the first success?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We are not printing out resolved address. Instead localhost:port will be printed. Only one port will be outputted - which is only a problem when port set to 0.

Copy link
Contributor

Choose a reason for hiding this comment

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

I can live with that

char buf[1024];
snprintf(buf, sizeof(buf), "%s:%d/%s", host.c_str(), port, id.c_str());
return buf;
// Host is valid (socket was bound) so colon means it's a v6 IP address
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we merge this with the code in inspector_agent.cc@node::inspector::URL() after the if?
/cc @sam-github

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was not aware of that code. I will share the code for generating the URL. It will still be slightly different - e.g. in json/list response it echoes IP address the client used to access the server while other places will print the host name specified from the command line (--inspect=0.0.0.0 will respond with 127.0.0.1 or external IP depending on the client but print out 0.0.0.0).

Copy link
Contributor

Choose a reason for hiding this comment

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

It's new code (less than a week old)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I found it. Moved the function to inspector_io.{h,cc}. Since the _server class does not depend on anything in the Node (so it is easier to test it) I copied a declaration to the inspector_socket_server.cc.

@refack
Copy link
Contributor

refack commented Jun 8, 2017

a few questions:

  1. I assume most of the refactoring is to enable multiple listening sockets?
  2. Should we update the docs?
  3. Should we add JS tests?
  4. Should we test that if IPv4 & IPv6 are enabled calling with localhost binds to both?

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 8, 2017

I assume most of the refactoring is to enable multiple listening sockets?

Yes.

Should we update the docs?

Don't think so. This should not be user-observable - we never claimed IPv6 was supported (nor did we explicitly call it unsupported). Multiple interfaces is also a bug fix - there is still no way to start listening on different port numbers and such.

Should we add JS tests?

IMHO, this change has no observable impact on wire clients. IPv6 on the low level is tested in cctest.

Should we test that if IPv4 & IPv6 are enabled calling with localhost binds to both?

This is likely platform and configuration specific. There may be setups without IPv6 interface (or even without IPv4), localhost may not resolve to all of them, etc.

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 8, 2017

I looked at CI failures and they do not seem to be caused by this code as inspector server is not started there.

@refack
Copy link
Contributor

refack commented Jun 8, 2017

Should we test that if IPv4 & IPv6 are enabled calling with localhost binds to both?

This is likely platform and configuration specific. There may be setups without IPv6 interface (or even without IPv4), localhost may not resolve to all of them, etc.

Ack (on my machine 'localhost' resolves only to IPv4)

url += "/";
url += ids[0];

std::string url = FormatWsAddress(io->host(), io->port(), ids[0], true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Solves the IPv6 URL bug 👍

@@ -12,6 +12,10 @@
namespace node {
namespace inspector {

std::string FormatWsAddress(const std::string& host, int port,
Copy link
Contributor

Choose a reason for hiding this comment

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

Circular dependency thing?
You should put a comment...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a comment.

@TimothyGu
Copy link
Member

DNS lookup aside, the entire host parsing process looks fairly complicated. I understand it would be a separate venture from this PR, but is there any value in sharing the WHATWG URL parser's host parser or host state (includes port parsing), which distinguishes between domains, IPv4, and IPv6 addresses in a standard-compliant manner?

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 9, 2017

@TimothyGu Thank you. I will look into it - but not for this PR (there's no address parsing/validation in this PR - it simply passes the string to DNS).

Copy link
Contributor

@refack refack left a comment

Choose a reason for hiding this comment

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

💯

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 16, 2017

Thank you for the reviews. New CI: https://ci.nodejs.org/job/node-test-pull-request/8694/


private:
explicit ServerSocket(InspectorSocketServer* server)
: tcp_socket_(uv_tcp_t()), server_(server), port_(-1) {}
Copy link
Member

Choose a reason for hiding this comment

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

Just 4-space indent relative to the previous line is enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

PR-URL: #13478
Fixes: #13477
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 16, 2017

CI have not indicated any relevant failures. Landed as 6e2c29b

@eugeneo eugeneo merged commit 6e2c29b into nodejs:master Jun 16, 2017
@eugeneo eugeneo deleted the ipv6 branch June 16, 2017 16:51
@refack
Copy link
Contributor

refack commented Jun 16, 2017

I think it's a good fix, but I don't yet trust our test suite coverage, can we let it cook for a while before porting to v8.x (going on gut feeling)?

@eugeneo
Copy link
Contributor Author

eugeneo commented Jun 16, 2017

I don't think it is pressing enough. I added labels - can remove (or manually backport) if need be.

@addaleax
Copy link
Member

addaleax commented Jun 16, 2017

@refack I would not let it wait. For one, to some degree having the latest bugfixes and features is what Current releases are there for; and then, as I’ve mentioned before it would likely be a good idea to do a RC process for 8.2.0, because that’s going to come with V8 5.9 and we’ve handled V8 upgrades the same way in the past.

If you feel really strongly, you can re-add the labels, but for now I removed them again.

(edit: Also, I would apply dont-land-on-v6.x only if it really shouldn’t land; otherwise we have baking-for-lts for that)

@refack
Copy link
Contributor

refack commented Jun 16, 2017

@refack I would not let it wait. For one, to some degree having the latest bugfixes and features is what Current releases are there for; and then, as I’ve mentioned before it would likely be a good idea to do a RC process for 8.2.0, because that’s going to come with V8 5.9 and we’ve handled V8 upgrades the same way in the past.

If you feel really strongly, you can re-add the labels, but for now I removed them again.

Ack.

Ping @jkrems, @joshgav, @roblourens, @billti, @prigara if you have external tests you could run on tomorrow's nightly, that would be great.
tl;dr we now DNS resolve the host address for --inspect=localhost:9229 would be happy to know there are no regressions in 3rd party tools
[edit]
@ulitink, @segrey

@mbraude
Copy link

mbraude commented Jun 16, 2017

@refack We'll do a test pass with the Node Tools for Visual Studio over the weekend and I'll get back to you on Monday. FYI, I am setting up nightly automation runs on the latest nightly node builds that will give us early warning when we're broken.

@refack
Copy link
Contributor

refack commented Jun 16, 2017

@mbraude that is great!

addaleax pushed a commit that referenced this pull request Jun 17, 2017
PR-URL: #13478
Fixes: #13477
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@addaleax addaleax mentioned this pull request Jun 17, 2017
@jkrems
Copy link
Contributor

jkrems commented Jun 18, 2017

Thanks for the ping! Ran node-inspect CI against the latest nightly and everything's still nice and green.

@segrey
Copy link

segrey commented Jun 19, 2017

@refack Thanks, it doesn't break IntelliJ.

addaleax pushed a commit that referenced this pull request Jun 21, 2017
PR-URL: #13478
Fixes: #13477
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
addaleax pushed a commit that referenced this pull request Jun 24, 2017
PR-URL: #13478
Fixes: #13477
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
rvagg pushed a commit that referenced this pull request Jun 29, 2017
PR-URL: #13478
Fixes: #13477
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
addaleax pushed a commit that referenced this pull request Jul 11, 2017
PR-URL: #13478
Fixes: #13477
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@MylesBorins
Copy link
Contributor

Could this be backported? v6.x inspector is pretty far behind

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. inspector Issues and PRs related to the V8 inspector protocol
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Debugger doesn't listen on IPv6 addresses