-
-
Notifications
You must be signed in to change notification settings - Fork 706
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
Avoid DNS TXT record resolutions for hostnames with pseudo-TLDs. #447
Avoid DNS TXT record resolutions for hostnames with pseudo-TLDs. #447
Conversation
* ADD function `hasPseudoTLD()` to shell/server/pre-meteor.js which checks if an hostname has any of the major pseudo-TLDs. * CHANGE `Meteor.startup()` function in shell/server/pre-meteor.js to avoid attempting to resolve DNS TXT records for requests with hostnames which have a pseudo-TLD.
Hey admins! Can one of you let me know if it's safe to build this pull request? See https://alpha.sandstorm.io/grain/kB7bofATTL2jGuKSFwmqdA/GithubPRCommands for a list of commands. |
I forgot to mention that this fixes part of issue #434. |
Garply, ok to test |
@@ -43,6 +43,12 @@ function isSandstormShell(hostname) { | |||
return (hostname === HOSTNAME || (DDP_HOSTNAME && hostname === DDP_HOSTNAME)); | |||
} | |||
|
|||
function hasPseudoTLD(hostname) { | |||
// Returns true if this hostname ends in one of the major pseudo-TLDs. | |||
let tld = hostname.split(".").pop(); |
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 think this should be var tld
.
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.
Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let it looks like let
is an ECMAScript 6 feature, which I wish we could use yet, but I guess we can't yet.
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.
@jparyani and @kentonv and others who might care, I'd be curious to hear if you think we should consider using https://github.com/mquandalle/meteor-harmony .
It looks like we can opt in on a file-by-file basis, by choosing a filename ending in .next.js
, which seems straightforward.
Hrm, it seems to be mad at the |
function hasPseudoTLD(hostname) { | ||
// Returns true if this hostname ends in one of the major pseudo-TLDs. | ||
let tld = hostname.split(".").pop(); | ||
return (tld === ("onion" || "i2p" || "gnu")); |
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.
In my testing, this seems to use short-circuit evaluation of ||
.
I think this would be cleaner if the function has a list called
var pseudoTlds = ['onion', 'i2p', 'gnu'];
and then you check for membership by e.g.
pseudoTlds.indexOf(tld) !== -1
I forget how to do stuff like this all the time in Javascript, so here is my interactive session where I verified the above:
➜ ~ js
> 'x' || 'y'
'x'
> var x = ['a', 'b'];
undefined
> x.indexOf('a');
0
> x.indexOf('z');
-1
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.
Note that elsewhere in the codebase, we seem to use _.contains(array, member)
, based on this grep:
$ git grep _.contains
shell/packages/sandstorm-accounts-oauth/oauth_server.js: if (!_.contains(Accounts.oauth.serviceNames(), result.serviceName)) {
shell/packages/sandstorm-accounts-packages/accounts.js: if (_.contains(services, serviceName)) {
shell/packages/sandstorm-accounts-packages/accounts.js: if (!_.contains(services, serviceName)) {
shell/packages/sandstorm-accounts-ui/accounts_ui.js: if (!_.contains(VALID_KEYS, key))
shell/packages/sandstorm-accounts-ui/accounts_ui.js: if (_.contains([
shell/packages/sandstorm-accounts-ui/login_buttons_dropdown.js: return _.contains(
shell/packages/sandstorm-accounts-ui/login_buttons_session.js: if (!_.contains(VALID_KEYS, key))
shell/packages/sandstorm-accounts-ui/login_buttons_session.js: if (_.contains(['errorMessage', 'infoMessage'], key))
shell/packages/sandstorm-accounts-ui/login_buttons_single.js: if (_.contains(_.pluck(getLoginServices(), "name"), attemptInfo.type))
shell/server/proxy.js: !(_.contains(["GET", "HEAD", "POST", "PUT", "DELETE"], requestedMethod))) {
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 do also use indexOf
based on a similar grep, so if you have no preference, I would pick the JS native indexOf
.
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.
Perhaps it's a nitpick, but I was concerned that using indexOf()
would return true for an hostname like storm.onion.example.com
. The same should be true for _.contains
.
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.
Oh, interesting, I see now.
Your way is almost fine, but I think the short-circuit evaluation is going to be bad news; I think you're ||
-ing the TLD names, not ||
-ing the result of comparing your desired string against the TLD names.
https://epeli.github.io/underscore.string/#endswith-string-ends-position-gt-boolean supposedly exists.
I don't know if you're familiar with the Sandstorm dev flow, so here's how I am checking how we'd use that:
$ cd ~/projects/sandstorm/shell
$ ./run-dev.sh
# lots of printouts while stuff compiles
# slow last line while it fuzz tests capnp
I couldn't find an initscript for Sandstorm. Please pass the directory
where Sandstorm is installed as an argument to this script.
$ ➜ ./run-dev.sh /opt/sandstorm
Please shut down your Sandstorm front-end:
sudo /opt/sandstorm/sandstorm stop-fe
$ sudo /opt/sandstorm/sandstorm stop-fe
$ ./run-dev.sh /opt/sandstorm
# more printout
=> App running at: http://local.sandstorm.io:6080
In a different terminal:
$ cd ~/projects/sandstorm/shell
$ meteor shell
# some printout
> _.endsWith('a')
TypeError: Object function (obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
} has no method 'endsWith'
at repl:1:4
at /home/paulproteus/projects/sandstorm/shell/.meteor/local/build/programs/server/shell-server.js:243:23
OK, so I guess we have to do something like
meteor add underscorestring:underscore.string
per https://github.com/epeli/underscore.string . That seems like a lot of work for one endsWith()
function, but it could be a reasonable idea.
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 demonstrate the above more clearly:
$ js
> ('x' === ('y' || 'x'))
false
>
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.
@paulproteus Yeah, sorry, you're totally right about the short-circuit evaluation on the ||
operator… ffffuuuuuu, I hate Javascript. I've added a patch to this branch which changes this function to use a mix between your suggested way and the original patch:
var tld = hostname.split(".").pop();
var pseudoTLDs = ["onion", "i2p", "gnu"];
return (_.contains(pseudoTLDs, tld));
This code looks great, modulo the concerns that the autobuild found (which I commented on). Also hi @isislovecruft ! Great to see you here. I'm that Asheesh person, in case you forgot the nick<->name mapping. I'll be really excited if Sandstorm ends up useful for Tor. Perhaps I'll see you at Debconf or CCC camp this year. |
if (hasPseudoTLD(hostname)) { | ||
return; | ||
} else { | ||
publicIdPromise = lookupPublicIdFromDns(hostname); |
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 have a feeling that the logic here, where for certain "TLDs" we carefully do not do the DNS lookup, would be better in the lookupPublicIdFromDns
function, though @kentonv or @jparyani might have another opinion.
It seems to me that it's the lookupPublicIdFromDns
function that is the one whose actions are being adjusted.
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.
Yes, I originally put the changes in lookupPublicIdFromDns()
and returned a new Error there. However, I changed it because I didn't want the error handling in Meteor.start()
to do something like return HTTP 500 with a message like "Hey, Sandstorm server here, and we're responding to tell you that we're pretending not to know what blahblahblahblahblah.onion
is!"
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 agree that the logic ought to be inside lookupPublicIdFromDns
.
I'm not sure I understand what you mean about the error message. I think the goal here should be to produce the same error page that you saw before, but without doing any DNS query. If we want to also change the error page to leak less information, that seems like a separate issue from the DNS lookup.
* CHANGE `let tld = […]` to `var tld = […]`. * CHANGE `hasPseudoTLD()` function to take @paulproteus' advice into account, specifically, use UnderscoreJS `_.contains()` method to test for pseudo-TLDs.
// returning any result which might indicate that there's actually a | ||
// server listening here. | ||
if (hasPseudoTLD(hostname)) { | ||
return; |
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'm not sure if this is correct here… would Meteor prefer getting a new Promise
that eventually returns null/undefined?
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.
Unfortunately, returning here will cause no response to ever be sent for this HTTP request, so the user will be left hanging.
You probably want to do something like:
publicIdPromise = Promise.reject(new Error("Pseudo-TLDs have no DNS records."))
Here's an article about ES6 promises, if you want to learn more about them:
Hi @isislovecruft ! Is this still something you're interested in seeing? There's now some merge conflicts, which might make it tough to revive this pull request. If I don't hear from you by a week from now then I might close this for now, but I'd be very happy to see this pull request get revived. If you want to see this get merged, but don't have time to finish it yourself, then let me know and I'll see what I can do. No promises about timeline but I like supporting y'all's needs. |
If we close this we should file a bug in its place. This is something we can and should fix when someone gets a free moment. |
At this point the code this touches has been completely re-written. The issue still exists, but we'd need to make the change in Re: opening a bug, is that not just #434? |
Since Asheesh said he'd probably close this if there was no response in a week, and that was in 2015, I will close this. |
hasPseudoTLD()
to shell/server/pre-meteor.js whichchecks if an hostname has any of the major pseudo-TLDs.
Meteor.startup()
function in shell/server/pre-meteor.js toavoid attempting to resolve DNS TXT records for requests with
hostnames which have a pseudo-TLD.