2019-09-18
Firefox, DNS over HTTPS, and us
The news of the time interval is that Mozilla will soon start rolling out DNS over HTTPS for US users, where by 'rolling out' Mozilla means 'enabling by default'. To their minimum credit, Mozilla says that they will explicitly notify people of this change and give them the opportunity to opt out. I hope and assume that this will work much like how Mozilla rolled out various tracking protection measures, including with how thoroughly informative that was.
(Clearly notifying people and giving them the chance to opt out is the obvious right thing to do, but Mozilla's track record on doing the obvious right thing is somewhat mixed.)
Since we're not in the US, this doesn't immediately affect people here; however, I have to assume that Mozilla is going to start rolling DNS over HTTPS out more broadly than just the USA. Given things like GDPR, Mozilla may not push this to Europe any time soon, but there probably aren't many roadblocks for rolling it out in Canada. My overall views on this remain unchanged; there are tradeoffs in either direction, and I have no idea what the right choice is in general.
For my department in particular, Firefox switching to DNS over HTTPS presents a potential problem because we have a split horizon DNS setup where some names resolve to different IPs internally than they do externally. According to Mozilla's blog post, the Firefox DoH implementation has some heuristics to detect a split horizon DNS environment, but from the vague descriptions we have so far it's not clear if they would reliably trigger for our users. If people here wind up with Firefox configured to use DNS over HTTPS and Mozilla's split horizon DNS heuristics don't trigger, they won't be able to connect to some of our hosts. We could theoretically say that this is people's fault in the same way that setting their machine to always use one of the public resolvers is, but this is the wrong answer, since Mozilla will have made this setting for them.
Mozilla currently supports a way for networks to explicitly disable DNS over HTTPS, by making your local resolver return NXDOMAIN for a canary domain. This is easy to do in Unbound, which we use on our local OpenBSD resolvers (see here or here). We could preemptively deploy this, but I tentatively think that we should wait to see if the Firefox split horizon detection heuristics work in our environment. Working heuristics would be the best answer for various reasons (including that Mozilla may find too many people abusing the canary domain and start paying less attention to it).
For work, there's probably no point in adding DNS over HTTPS to our local resolving DNS servers, even once it's supported on the OpenBSD version of Unbound. As far as I know, people here would have to specifically configure their Firefox to talk to our servers, and then their configuration would break when they moved outside of our network and could no longer reach our resolving DNS servers.
For my own personal use, I may eventually add DNS over HTTPS support to my resolving Unbound instances, because apparently DoH is the only way to get encrypted SNI. Unfortunately it also apparently normally requires DNSSEC, so unless I can get my Unbound to lie about that (or Firefox to not care), I may be out of luck. I do wish I could tell Firefox that a resolver on localhost was trusted even without DoH, but I suspect that I can't.
(This does raise long term issues about encrypted SNI support for our users, but perhaps in the long term people will come up with answers. Hopefully ones that don't involve DNSSEC.)
Converting a Go pointer to an integer doesn't quite do what it looks like
Over on r/golang, an interesting question was asked:
[Is it] possible to parse a struct or interface to get its pointer address as an integer? [...]
The practical answer today is yes, as noted in the answers to the
question. You can convert any Go pointer to uintptr
by going through
unsafe.Pointer()
,
and then convert the uintptr
into some more conventional integer
type if you want. If you're going to convert to another integer
type, you should probably use uint64
for safety, since that should
hold any uintptr
value on any current Go platform.
However, the theoretical answer is no, in that this conversion
doesn't quite get you what you might think it does. What this
conversion really gives you is the address that the addressable
value had at the moment the conversion to
uintptr
was done. Go very carefully does not guarantee that this
past address is the same as the current address, although it always
will be today.
(I'm assuming here that there are other references to the addressable value that keep it from being garbage collected.)
Go's current garbage collector is a non-compacting garbage collector, where once things are allocated somewhere in memory, they never move for as long as they're alive. Since a non-compacting garbage collector has stable memory addresses for things, converting an address to an integer gives you something that is always the integer value of the current address of that thing. However, there are also compacting garbage collectors, which move live things around during garbage collection for various reasons. In these garbage collectors, the memory address of things is not stable.
Go is deliberately specified so that you could implement it using
a compacting GC, and at one point this was the long term plan. When it moved things as part
of garbage collection, such a Go would update the address of actual
pointers to them to the new value. However, it would not magically
update integer values derived from those pointers, whether they're
uintptr
s or some other integer types. In a compacting GC world,
getting the uintptr
of the address of something twice at different
times could give you two different values. Each value was accurate
at the moment you got it, but it's not guaranteed to be accurate
one instant past that; a GC pass could happen at any time and thus
the thing could be moved at any time.
Leaving the door open for a compacting GC is one of the reasons
that the rules surrounding the use of unsafe.Pointer()
and uintptr
are so
carefully and narrowly specified, as we've seen before. In fact the documentation points this out
explicitly:
A uintptr is an integer, not a reference. Converting a Pointer to a uintptr creates an integer value with no pointer semantics. Even if a uintptr holds the address of some object, the garbage collector will not update that uintptr's value if the object moves, nor will that uintptr keep the object from being reclaimed.
(The emphasis is mine.)
The Go garbage collector never moves things today, which leads to the practical answer for today of 'yes, you can do this'. But the theoretical answer is that the address of things could be constantly changing, and maybe someday in the future they sometimes will.
Update: As pointed out in the r/golang comments on my entry, I'm wrong here. In Go today, stacks are movable as stack usage grows and shrinks, and you can take the address of a value that is on the stack and that subsequently gets moved with the stack.