Has anyone actually tried to connect a frontend to a remote kernel (on a different machine)? Because I'm pretty sure it's impossible with the current setup.
KernelManager.start_kernel() enforces that the kernel be bound to localhost, which can only be connected via the local machine. This is wrong, and prevents ever allowing external managers from connecting to the kernel (part of the point). It should not check that it's localhost; it should check that it refers to this machine, which, on my laptop, includes at least 5 valid addresses.
The correct logic should be:
LOCAL_IPS = socket.gethostbyname_ex('localhost')
# on my machine, this is now: ['127.0.0.1', '192.168.1.101', '192.168.1.111', '192.168.2.1', '192.168.151.1']
addr == LOCALHOST
tests should be:
addr in LOCAL_IPS
*There should probably be some try/excepts in constructing LOCAL_IPS, since gethostname might fail on some systems.
The ipythonqt script has similar logic preventing binding to a local non-loopback interface (it fails silently, which is worse, but easily fixable).
We also need to allow binding to multiple interfaces. At the very least, support the catch-all aliases, which can be specified as: '0.0.0.0' or '', since these are likely the most common choice after localhost.
No, I hadn't tried. I had assumed it was possible (the generic machinery for it is there), but I'd never actually tested it.
Go ahead and make the fixes.
Though since right now we have zero security/authentication/encryption, I'd say that allowing remote clients should be something explicitly required on startup with --allow-remote or somesuch. At least users will be aware that they are opening effectively a remote shell on their system.
On something like the UCB-wide network, I tend to keep long-running sessions on a machine that has a publicly addressable IP. I don't want to have to worry about remote connections all the time.
It would be even better if this could be toggled at runtime: you could decide you want to invite someone, then you allow their IP, then you close again.
So I think the ideal design would be:
And having the allow/disable remotes be an internal IPython method would be great, so that one can do this at runtime too (both allowing and closing).
How does that sound?
I pushed an implementation of this into my newkernel. It involves adding a file into IPython.utils that builds LOCALHOST and a list of IPs pointing to the current machine called LOCAL_IPS which can be used for checking whether a connection is really local.
The rest of the implementation involves propagating the existing --ip flag in base_launch_kernel up through the various launch/start_kernel methods, so that the frontend '--ip' flag actually makes sense when the kernel is not external.
It sounds like you want to be able to allow connections from specific clients, but that just isn't possible at the socket level. We would have to build all of the identifying machinery into our messaging system (e.g. via uuid1 based session IDs), and implementing security for the entire messaging system is a bit beyond the scope of this interface bugfix. Are we ready to start that discussion?
All I did was fix the '--ip' flag for the listening kernel, which didn't work unless it was loopback before. That means you can now listen on 192.168.x.y (enet) OR 127.0.0.1 (loopback) OR 0.0.0.0 (all interfaces). What you can't do is listen on more than one interface but less than all of them. If we change the ip argument from an interface to a list of interfaces, then we can reasonably build in the option to have multiple interfaces, and then runtime-removable interfaces make sense.
The default is still loopback, so unless users specify to listen on an externally visible IP, it's not vulnerable.
Mmh, this is weird. I'd written a long comment about this a couple of days ago, and now I don't see it! Very odd.
Reconstructing from memory, I think my main points were:
Otherwise, I'm happy to merge #164 and close this one. Let me know if you think you can do the little doc stub (whatever you have time for) and we'll proceed.
Thanks for the great work!
Yes, I thought I submitted the above comment before, but it didn't post, and I had to redo it a few hours later when I noticed. I assumed I just forgot to hit the button.
I think the logic is fairly straightforward, but there does seem to be an increasing number of states to switch between.
I just added a little bit of text to --help in #164, and I'll start a skeleton doc, hopefully by this weekend.
What's the status of this one? It seems to me that since we've closed #164 with these enhancements, this one can be closed, no?
Yes, this is fixed as part of #164. Closing...
Possible fix for GH-169