5 ms·
Very interesting idea overall. I've long thought the current segregation of network protocols between userland and the kernel is rather arbitrary and inflexibl
by comex 10y ago
Very interesting idea overall. I've long thought the current segregation of network protocols between userland and the kernel is rather arbitrary and inflexible - why should reliability (TCP) be in the kernel but security (TLS) be in userland?
I don't think the idea of requiring Go-style lightweight threading is viable. Lightweight threading has many nice properties, but also inherently requires more expensive operations to deal with split stacks, and tends to use more memory than a manual approach. It's also rather poorly supported in general by existing languages and OSes (other than Go), while any new OS-level socket API should be as universally accessible as the existing one. In particular, many scripting-ish languages either have no concept of threading at all or only support isolated threads whose communication is limited to relatively slow message passing. In theory the language implementations could write a C shim to expose a non-blocking interface around blocking underlying operations - this is what libuv does today for file I/O, for instance - but the result would be a lot of unnecessary overhead.
- tptacek 10y agoHow would a design with TCP done entirely in userland work? A given socket address might in one instant belong to uid 10, and in the next, after uid=10's connection closes, to uid 20. (I'm not challenging you, just asking what you think the semantics should look like). Worth adding for everyone else, though I'm sure you know: high speed network implementations already pull a lot of this stuff into userland.
- zrm 10y agoBasically the same as SOCK_DGRAM works except that send() and recv() expect/provide the TCP header before the transport payload. If a user process calls bind() on some address/port then it gets all TCP packets for that local address/port. If it calls connect() then it gets only the ones that match both the local and remote address/port.
- 0x0 10y agoWith packet retransmissions and out-of-order packet delivery, wouldn't there be a risk that the client software at uid=10 sees a clean shutdown and disconnects, but uid=20 instantly binds with the same ports and steals a bunch of delayed packets?
- zrm 10y agoThat happens with UDP already and is another reason everything ought to be encrypted with session keys. But the normal TCP solution of the OS holding released ports in TIME_WAIT for a couple of minutes still works as ever.
- comex 10y agoThere are a few different ways to answer that question. First, I believe that for most applications, it's not that TCP should be in userland; rather, TLS should be in the kernel, or otherwise system managed. See the wall of text I just replied to someone else with. Second, if you do want to customize the transport layer, which is of course fairly common today - multiplayer games often go for some custom "reliable UDP" protocol that drops ordering guarantees to improve latency, and then there's Chromium with QUIC, and uTorrent µTP, and WebRTC... well, the reality of networking today is that that has to be done on top of UDP rather than IP directly. I doubt there's much point writing a new API for TCP itself that exposes all the bells and whistles, because the design of TCP is dated. Rather, there should be more standardized APIs for applications to more easily use replacements for TCP that run over UDP. Ideally I should be able to switch from TCP to QUIC just by changing a few lines of code. (Edit: By the way, if we could redo networking protocols from scratch, I think ports ought to exist at the IP layer rather than being replicated in TCP and UDP, and then UDP could be abolished entirely. But we can't.) Actually, that ties into high performance networking too. As you know, those alternate stacks require userland to talk directly or near-directly to hardware, meaning you just have to give up on different ports belonging to different applications. But beyond that, one thing holding those stacks back is that they require a lot of custom code and don't work with existing applications. With a standardized networking API that supported userspace plugins, it could be possible to add "DPDK+rumptcpip" as an option next to "kernel TCP" and "QUIC", and configure any random process to use it.
- zrm 10y ago> I doubt there's much point writing a new API for TCP itself that exposes all the bells and whistles, because the design of TCP is dated. Rather, there should be more standardized APIs for applications to more easily use replacements for TCP that run over UDP. The advantage TCP has over UDP is that middleboxes know what TCP FIN is and so are willing to use much longer timeouts for TCP sessions. For example the default Linux connection tracking timeout for established TCP connections is five days but for UDP streams it's three minutes. So if you need a long-lived session to receive event-based messages your choices are to use UDP with a mapped port using NAT-PMP or PCP (ideal but not always available), use UDP with frequent keepalives (expensive), or use TCP. Being able to do TCP in userspace would be very useful for any VPN-like thing because you could get the long timeouts but still deliver packets immediately even if an earlier one was lost, and avoid the TCP-over-TCP performance degradation by deferring congestion control to the inner packets.
- justincormack 10y agoThe thing is, if addresses are scarce, you do need something (typically a kernel) to allocate them. Port numbers on a single IP are scarce. IPv6 addresses, if each machine has a /64 though are not, and it becomes much easier, each (64 bit!) pid can have its own IP with neither being reused, so routing can be dumb. (And/or encrypt everything, keys are not a scarce resource either).
- rumcajz 10y agoCan be done for example by having a address allocation daemon running in user space. The socket library would create an IPC connection to the daemon and ask for an address/port. The daemon would reserve the address/port and pass it back. The daemon would have to health check the applications so that it can return the addresses back to the pool in case of failure.
- aftbit 10y agoThe big reason security is in userspace is because it requires policy decisions. How do we determine which remote users to trust? WoT, cert chains, trust on first use? There is kernel-mode security (IPsec) but it turns out that userspace is better equipped to make those decisions.
- comex 10y agoActually, policy decisions are a big part of why I think TLS should be "in the kernel". It doesn't have to literally be in the kernel - it could be a userspace daemon instead - but that's an implementation detail. What matters is that just like with TCP, there should be one high-level API, provided by the system, which all applications are expected to use. Scenario: You want to temporarily ignore an invalid certificate. (Yes, I know this is usually a bad idea, but sometimes it’s necessary.) Today: Every application needs its own flag, environment variable, configuration option, and/or UI element to disable validation. If you’re unlucky, there won’t be one. If you’re really unlucky, there won’t be any way to enable validation; even in 2017 there are still lots of poorly written applications like that. Centralized: There should be a standard environment variable that works with everything, and/or maybe a “security center” applet where you can add a temporary system-wide exemption per-host, or something like that. Scenario: You want to sniff a secure connection for debugging purposes. Today: You have to use a MITM proxy, which is gross and needs setup and breaks things, and requires trusting invalid certificates, which doesn’t always work; see above and below. Centralized: The kernel could just hand decrypted packets to packet sniffing programs, allowing for purely passive observation. Scenario: You want to ensure that you’re using high-quality ciphersuites. Today: Up to the application, usually not customizable, so browsers will do the right thing and other applications will have some list the developer copy+pasted that seemed to work. Welp. Centralized: The system should be able to specify policy for all applications, with the option for the user to override it. After all, it’s almost never actually desirable for a cipher suite to be supported by one application and not another - like, it’s okay if my mail client connects to Google insecurely, but not if my instant messaging client does. Scenario: You want to add a custom trusted CA, or generally you want different applications to be consistent in their policy decisions. Today: Different TLS libraries have their own trust store formats and trust rules. If you’re lucky, your TLS library of choice will have some way to use the system trust store, on Windows and macOS where such a thing exists, although who knows if it’ll properly replicate the various rules browsers like to impose, e.g. requiring certificate transparency. If you’re unlucky, you end up with things like Java having its own trust store, or wget on macOS refusing to download any https URLs until you go install some .crt file and point wget to the right path. In both cases, you end up with a separate list of trusted certificates, that requires a separate process if you want to add a custom one, or upgrade to remove newly distrusted roots, etc. Centralized: Well, there’s already some centralization with system trust stores, but ideally not would those be supported universally, the entire process of “should this TLS connection be established” could be defined and maintained in one place. Scenario: On a server, you want to run a program that accepts TLS connections. Today: Each program needs its own copy of the private key and its own TLS configuration, which often doesn’t expose the full range of settings it’s desirable to customize. Centralized: The system holds the keys (reducing both configuration burden and the danger of leaks); applications can just say “listen on port X using TLS”, and send/receive plaintext on the resulting sockets, and encryption will be handled automatically. ... I admit there are also some downsides of a centralized design. One of them is updates: these days, on most systems, users update their browsers a lot more than they update the OS, so the browser is likely to be up to date while the OS is not. But "at least the browser is secure, even if other apps are not" is not exactly an ideal outcome, and this too seems like an artifact of history... there's no reason that OS components can't auto-update like browsers do.
- jstimpfle 10y agoI've come to think that the whole distinction "kernel vs userland" is inflexible. There was a thread here on HN a few days ago, and it showed some clear deficits of conventional OS, for example in processes. Speaking of lack of composability of clients and linked-in libraries, speaking of IPC and uncontrolled implicit environment inheritance (Docker... :<), speaking of the ad-hoc security model (Unix permissions, setuid hacks, and more recently extended attributes). There's just a single trust boundary in Unix. What if the system was instead just a graph of interacting entities, each managing control over some resource? The "userland process" would just be another entity that is in control of another (more ephemeral) resource. We wouldn't even separate address spaces! Security by careful propagation through fine-grained trust boundaries (instead of globally accessible resource managers that have a hard time deciding whether a requesting entity should be authorized). Think svn vs git. And my understanding is that that's much of what Lisp Machines were about...
- morb 10y agoCould you please link to the mentioned thread?
- jstimpfle 10y agohttps://news.ycombinator.com/item?id=13621623 https://news.ycombinator.com/item?id=13621623 If you search for my name there, you will find at least discussions about file modes and also why I claim that processes are a failed abstraction (it was really another user who pointed that out).
- nwmcsween 10y agoDefine 'separate address spaces', you have linear address space (virtual) and kernel/user 'address spaces' which are address spaces but not in the way linear address spaces are. It would be easier to simply move almost everything not needed by the kernel into 'userspace' and have some sort of capability system to enforce access rights.
- jstimpfle 10y ago